Don't depend on external ncmlib.

This commit is contained in:
Nicholas J. Kain 2020-10-20 06:44:31 -04:00
parent 4575f74164
commit f1e20305ba
21 changed files with 1023 additions and 92 deletions

View File

@ -1,5 +1,3 @@
project(ndhc)
cmake_minimum_required(VERSION 3.3) cmake_minimum_required(VERSION 3.3)
if(${CMAKE_VERSION} VERSION_LESS 3.12) if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
@ -7,6 +5,8 @@ else()
cmake_policy(VERSION 3.12) cmake_policy(VERSION 3.12)
endif() endif()
project (ndhc DESCRIPTION "dhcp4 client" LANGUAGES C)
#################################### ####################################
# Computes the realtionship between two version strings. A version # Computes the realtionship between two version strings. A version
@ -101,6 +101,31 @@ if (NOT (${OSNAME} STREQUAL "Linux"))
return() return()
endif() endif()
if (${OSNAME} STREQUAL "Linux")
execute_process(
COMMAND uname -r
COMMAND tr "\n" " "
COMMAND sed "s/ //"
OUTPUT_VARIABLE LINUX_VERSION
)
COMPARE_VERSION_STRINGS(${LINUX_VERSION} "3.5" LINUX_HAS_NO_NEW_PRIVS)
if (NOT ${LINUX_HAS_NO_NEW_PRIVS} LESS 0)
message("ncmlib: Enabling use of prctl SET_NO_NEW_PRIVS.")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNK_USE_NO_NEW_PRIVS")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNK_USE_NO_NEW_PRIVS")
else()
message("ncmlib: prctl SET_NO_NEW_PRIVS not available.")
endif()
COMPARE_VERSION_STRINGS(${LINUX_VERSION} "3.17" LINUX_HAS_GETRANDOM_SYSCALL)
if (NOT ${LINUX_HAS_GETRANDOM_SYSCALL} LESS 0)
message("ncmlib: Enabling use of getrandom syscall.")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNK_USE_GETRANDOM_SYSCALL")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNK_USE_GETRANDOM_SYSCALL")
else()
message("ncmlib: getrandom syscall not available.")
endif()
endif()
if (NOT CMAKE_CROSSCOMPILING) if (NOT CMAKE_CROSSCOMPILING)
set(GLIBC_DETECT_TEST_C set(GLIBC_DETECT_TEST_C
" "
@ -139,5 +164,66 @@ else()
set(MACHINENAME $ENV{CROSSCOMPILE_MACHINENAME}) set(MACHINENAME $ENV{CROSSCOMPILE_MACHINENAME})
endif() endif()
add_subdirectory(ncmlib) add_executable(ndhc "")
add_subdirectory(src)
set(RAGEL_IFCHD_PARSE ${CMAKE_CURRENT_BINARY_DIR}/ifchd-parse.c)
set(RAGEL_CFG_PARSE ${CMAKE_CURRENT_BINARY_DIR}/cfg.c)
find_program(RAGEL ragel)
set(RAGEL_PRINT_COMMENT "Compiling Ragel state machine: FILE")
file(GLOB_RECURSE RAGEL_FILES
"src/ifchd-parse.rl"
"src/cfg.rl"
)
foreach(RAGEL_FILE ${RAGEL_FILES})
string(REGEX REPLACE "^[^/]*[/]" "" RAGEL_FILE_BASE ${RAGEL_FILE})
string(REGEX REPLACE ${RAGEL_FILE_BASE} "" RAGEL_FILE_PATH ${RAGEL_FILE})
string(REGEX REPLACE "[.]rl$" ".c" RAGEL_FILE_C ${RAGEL_FILE_BASE})
string(REGEX REPLACE "FILE$" ${RAGEL_FILE_BASE} RAGEL_COMMENT ${RAGEL_PRINT_COMMENT})
set(RAGEL_FILE_C_OUT ${CMAKE_CURRENT_BINARY_DIR}/${RAGEL_FILE_C})
list(APPEND RAGEL_C_FILES ${RAGEL_FILE_C_OUT})
add_custom_command(
OUTPUT ${RAGEL_FILE_C_OUT}
COMMAND ${RAGEL} -T0 ${RAGEL_ERRFMT_ARG} -o ${RAGEL_FILE_C_OUT} ${RAGEL_FILE_BASE}
MAIN_DEPENDENCY ${RAGEL_FILE}
WORKING_DIRECTORY ${RAGEL_FILE_PATH}
COMMENT ${RAGEL_COMMENT}
VERBATIM
)
set_property(SOURCE ${RAGEL_FILE_C_OUT} APPEND PROPERTY GENERATED TRUE)
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set_property(SOURCE ${RAGEL_FILE_C_OUT} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-const-variable")
endif()
set_source_files_properties(${RAGEL_FILE_C_OUT} PROPERTIES GENERATED true)
target_sources(ndhc PRIVATE ${RAGEL_FILE_C_OUT})
endforeach(RAGEL_FILE)
add_custom_target(ndhc_ragel DEPENDS ${RAGEL_C_FILES})
add_dependencies(ndhc ndhc_ragel)
target_sources(ndhc PRIVATE
"src/lib/io.c"
"src/lib/log.c"
"src/lib/hwrng.c"
"src/lib/random.c"
"src/lib/privs.c"
${RAGEL_C_FILES}
"src/arp.c"
"src/ifchd.c"
"src/netlink.c"
"src/sockd.c"
"src/dhcp.c"
"src/ifset.c"
"src/nl.c"
"src/state.c"
"src/duiaid.c"
"src/leasefile.c"
"src/options.c"
"src/sys.c"
"src/ifchange.c"
"src/ndhc.c"
"src/rfkill.c"
)
target_include_directories(ndhc PRIVATE
"${PROJECT_SOURCE_DIR}/src"
)

View File

@ -2,48 +2,42 @@
# for distros that want to avoid build dependencies. Produced exes will be # for distros that want to avoid build dependencies. Produced exes will be
# at './build/ndhc'. # at './build/ndhc'.
NCM_SRCS = $(sort $(wildcard ncmlib/*.c)) NCM_SRCS = $(sort $(wildcard src/lib/*.c))
NDHC_SRCS = $(sort $(wildcard src/*.c)) NDHC_SRCS = $(sort $(wildcard src/*.c))
NCM_OBJS = $(NCM_SRCS:.c=.o) NCM_OBJS = $(NCM_SRCS:.c=.o)
NDHC_OBJS = $(NDHC_SRCS:.c=.o) NDHC_OBJS = $(NDHC_SRCS:.c=.o)
NCM_INC = -I./ncmlib
NDHC_INC = -I./src NDHC_INC = -I./src
BUILD_DIR = build BUILD_DIR = build
OBJ_DIR = $(BUILD_DIR)/objs OBJ_DIR = $(BUILD_DIR)/objs
CC = gcc CC = gcc
AR = ar AR = ar
RANLIB = ranlib
CFLAGS = -O2 -s -std=gnu99 -pedantic -Wall -D_GNU_SOURCE CFLAGS = -O2 -s -std=gnu99 -pedantic -Wall -D_GNU_SOURCE
# Not required for glibc >= 2.17, but older glibcs are still common. # Not required for glibc >= 2.17, but older glibcs are still common.
# The CMake build script will perform detection, but this Makefile is simple. # The CMake build script will perform detection, but this Makefile is simple.
LINK_LIBS = -lrt LINK_LIBS = -lrt
all: makedir ifchd-parse.o cfg.o ncmlib.a ndhc all: makedir ifchd-parse.o cfg.o ndhc
clean: clean:
rm -Rf $(BUILD_DIR) rm -Rf $(BUILD_DIR)
makedir: makedir:
mkdir -p $(BUILD_DIR) $(OBJ_DIR)/src $(OBJ_DIR)/ncmlib mkdir -p $(BUILD_DIR) $(OBJ_DIR)/src
ifchd-parse.o: ifchd-parse.o:
ragel -G2 -o $(BUILD_DIR)/ifchd-parse.c src/ifchd-parse.rl ragel -G2 -o $(BUILD_DIR)/ifchd-parse.c src/ifchd-parse.rl
$(CC) $(CFLAGS) $(NCM_INC) $(NDHC_INC) -c -o $(OBJ_DIR)/src/$@ $(BUILD_DIR)/ifchd-parse.c $(CC) $(CFLAGS) $(NDHC_INC) -c -o $(OBJ_DIR)/src/$@ $(BUILD_DIR)/ifchd-parse.c
cfg.o: cfg.o:
ragel -G2 -o $(BUILD_DIR)/cfg.c src/cfg.rl ragel -G2 -o $(BUILD_DIR)/cfg.c src/cfg.rl
$(CC) $(CFLAGS) $(NCM_INC) $(NDHC_INC) -c -o $(OBJ_DIR)/src/$@ $(BUILD_DIR)/cfg.c $(CC) $(CFLAGS) $(NDHC_INC) -c -o $(OBJ_DIR)/src/$@ $(BUILD_DIR)/cfg.c
%.o: %.c %.o: %.c
$(CC) $(CFLAGS) $(NCM_INC) -c -o $(OBJ_DIR)/$@ $< $(CC) $(CFLAGS) -c -o $(OBJ_DIR)/$@ $<
ncmlib.a: $(NCM_OBJS) ndhc: $(NCM_OBJS) $(NDHC_OBJS) ifchd-parse.o cfg.o
$(AR) rc $(BUILD_DIR)/$@ $(subst ncmlib/,$(OBJ_DIR)/ncmlib/,$(NCM_OBJS)) $(CC) $(CFLAGS) -o $(BUILD_DIR)/$@ $(subst src/,$(OBJ_DIR)/src/,$(NDHC_OBJS)) $(BUILD_DIR)/objs/src/ifchd-parse.o $(BUILD_DIR)/objs/src/cfg.o $(LINK_LIBS)
$(RANLIB) $(BUILD_DIR)/$@
ndhc: $(NDHC_OBJS) ifchd-parse.o cfg.o
$(CC) $(CFLAGS) $(NCM_INC) -o $(BUILD_DIR)/$@ $(subst src/,$(OBJ_DIR)/src/,$(NDHC_OBJS)) $(BUILD_DIR)/ncmlib.a $(BUILD_DIR)/objs/src/ifchd-parse.o $(BUILD_DIR)/objs/src/cfg.o $(LINK_LIBS)
.PHONY: all clean .PHONY: all clean

View File

@ -88,15 +88,9 @@ new one.
* Linux kernel * Linux kernel
* GNU Make or CMake * GNU Make or CMake
* [Ragel 6](https://www.colm.net/open-source/ragel) * [Ragel 6](https://www.colm.net/open-source/ragel)
* [ncmlib](https://github.com/niklata/ncmlib)
## Installation ## Installation
Make sure that ncmlib is present in the ndhc source directory:
```
$ ls
CMakeLists.txt LICENSE Makefile ncmlib README src
```
Compile and install ndhc. Compile and install ndhc.
* Create a build directory: `mkdir build && cd build` * Create a build directory: `mkdir build && cd build`
* Create the makefiles: `cmake ..` * Create the makefiles: `cmake ..`

View File

@ -1,54 +0,0 @@
project (ndhc DESCRIPTION "dhcp4 client" LANGUAGES C)
set(RAGEL_IFCHD_PARSE ${CMAKE_CURRENT_BINARY_DIR}/ifchd-parse.c)
set(RAGEL_CFG_PARSE ${CMAKE_CURRENT_BINARY_DIR}/cfg.c)
find_program(RAGEL ragel)
add_custom_command(
OUTPUT ${RAGEL_IFCHD_PARSE}
COMMAND ${RAGEL} -G2 -o ${RAGEL_IFCHD_PARSE} ifchd-parse.rl
DEPENDS ifchd-parse.rl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Compiling Ragel state machine: ifchd-parse.rl"
VERBATIM
)
set_property(SOURCE ${RAGEL_IFCHD_PARSE} APPEND PROPERTY GENERATED TRUE)
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set_property(SOURCE ${RAGEL_IFCHD_PARSE} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-const-variable")
endif()
add_custom_command(
OUTPUT ${RAGEL_CFG_PARSE}
COMMAND ${RAGEL} -G2 -o ${RAGEL_CFG_PARSE} cfg.rl
DEPENDS cfg.rl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Compiling Ragel state machine: cfg.rl"
VERBATIM
)
set_property(SOURCE ${RAGEL_CFG_PARSE} APPEND PROPERTY GENERATED TRUE)
if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set_property(SOURCE ${RAGEL_CFG_PARSE} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-const-variable")
endif()
add_executable(ndhc ${RAGEL_CFG_PARSE} ${RAGEL_IFCHD_PARSE})
target_sources(ndhc PRIVATE
"arp.c"
"ifchd.c"
"netlink.c"
"sockd.c"
"dhcp.c"
"ifset.c"
"nl.c"
"state.c"
"duiaid.c"
"leasefile.c"
"options.c"
"sys.c"
"ifchange.c"
"ndhc.c"
"rfkill.c"
)
target_include_directories(ndhc PRIVATE
"${PROJECT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/../ncmlib"
)
target_link_libraries(ndhc PUBLIC ncmlib)

View File

@ -12,7 +12,7 @@
#include "ifchd.h" #include "ifchd.h"
#include "sockd.h" #include "sockd.h"
#include "nk/log.h" #include "nk/log.h"
#include "nk/privilege.h" #include "nk/privs.h"
#include "nk/copy_cmdarg.h" #include "nk/copy_cmdarg.h"
#include "nk/io.h" #include "nk/io.h"

View File

@ -84,7 +84,7 @@ static int perform_ip4set(const char buf[static 1], size_t len)
const char *p = buf; const char *p = buf;
const char *pe = p + len; const char *pe = p + len;
const char *eof = pe; const char *eof = pe;
const char *arg_start; const char *arg_start = p;
int cs = 0; int cs = 0;
bool have_ip = false; bool have_ip = false;
bool have_subnet = false; bool have_subnet = false;
@ -211,7 +211,7 @@ int execute_buffer(const char newbuf[static 1])
size_t init_siz = strlen(buf); size_t init_siz = strlen(buf);
const char *p = buf; const char *p = buf;
const char *pe = p + init_siz; const char *pe = p + init_siz;
const char *arg_start; const char *arg_start = p;
size_t arg_len = 0; size_t arg_len = 0;
int cs = 0; int cs = 0;

View File

@ -41,8 +41,7 @@
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
#include "nk/log.h" #include "nk/log.h"
#include "nk/privilege.h" #include "nk/privs.h"
#include "nk/signals.h"
#include "nk/io.h" #include "nk/io.h"
#include "ifchd.h" #include "ifchd.h"
@ -368,9 +367,8 @@ static void do_ifch_work(void)
} }
} }
// If we are requested to update resolv.conf, preopen the fd before // If we are requested to update resolv.conf, preopen the fd before we drop
// we drop root privileges, making sure that if we create // root, making sure that if we create resolv.conf, it will be world-readable.
// resolv.conf, it will be world-readable.
static void setup_resolv_conf(void) static void setup_resolv_conf(void)
{ {
if (strncmp(resolv_conf_d, "", sizeof resolv_conf_d)) { if (strncmp(resolv_conf_d, "", sizeof resolv_conf_d)) {

128
src/lib/hwrng.c Normal file
View File

@ -0,0 +1,128 @@
/* hwrng.c - access to system CRNG
*
* Copyright 2013-2018 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "nk/hwrng.h"
#include "nk/log.h"
#include "nk/io.h"
#ifdef NK_USE_GETRANDOM_SYSCALL
#include <sys/syscall.h>
#include <linux/random.h>
static bool nk_getrandom(char *seed, size_t len)
{
size_t fetched = 0;
while (fetched < len) {
int r = syscall(SYS_getrandom, seed + fetched, len - fetched, 0);
if (r <= 0) {
if (r == 0) {
// Failsafe to guard against infinite loops.
log_warning("%s: getrandom() returned no entropy", __func__);
return false;
}
if (errno == EINTR)
continue;
log_warning("%s: getrandom() failed: %s", __func__, strerror(errno));
return false;
}
fetched += (size_t)r;
}
return true;
}
#else
static bool nk_getrandom(char *seed, size_t len)
{
(void)seed;
(void)len;
return false;
}
#endif
static bool nk_get_rnd_clk(char *seed, size_t len)
{
struct timespec ts;
for (size_t i = 0; i < len; ++i) {
int r = clock_gettime(CLOCK_REALTIME, &ts);
if (r < 0) {
log_warning("%s: Could not call clock_gettime(CLOCK_REALTIME): %s",
__func__, strerror(errno));
return false;
}
char *p = (char *)&ts.tv_sec;
char *q = (char *)&ts.tv_nsec;
for (size_t j = 0; j < sizeof ts.tv_sec; ++j)
seed[i] ^= p[j];
for (size_t j = 0; j < sizeof ts.tv_nsec; ++j)
seed[i] ^= q[j];
// Force some scheduler jitter.
static const struct timespec st = { .tv_sec=0, .tv_nsec=1 };
nanosleep(&st, (struct timespec *)0);
}
return true;
}
static bool nk_get_urandom(char *seed, size_t len)
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
log_warning("%s: Could not open /dev/urandom: %s", __func__,
strerror(errno));
return false;
}
bool ret = true;
int r = safe_read(fd, seed, len);
if (r < 0) {
ret = false;
log_warning("%s: Could not read /dev/urandom: %s",
__func__, strerror(errno));
}
close(fd);
return ret;
}
void nk_get_hwrng(void *seed, size_t len)
{
char *s = (char *)seed;
if (nk_getrandom(s, len))
return;
if (nk_get_urandom(s, len))
return;
log_warning("%s: Seeding PRNG via system clock. May be predictable.",
__func__);
if (nk_get_rnd_clk(s, len))
return;
suicide("%s: All methods to seed PRNG failed. Exiting.", __func__);
}

131
src/lib/io.c Normal file
View File

@ -0,0 +1,131 @@
/* io.c - light wrappers for POSIX i/o functions
*
* Copyright 2010-2018 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include "nk/io.h"
#include <limits.h>
// POSIX says read/write/etc() with len param > SSIZE_MAX is implementation defined.
// So we avoid implementation-defined behavior with the bounding in each safe_* fn.
/* returns -1 on error, >= 0 and equal to # chars read on success */
ssize_t safe_read(int fd, char *buf, size_t len)
{
size_t s = 0;
if (len > SSIZE_MAX) len = SSIZE_MAX;
while (s < len) {
ssize_t r = read(fd, buf + s, len - s);
if (r == 0)
break;
if (r < 0) {
if (errno == EINTR)
continue;
else if ((errno == EAGAIN || errno == EWOULDBLOCK) && s > 0)
return (ssize_t)s;
else
return -1;
}
s += (size_t)r;
}
return (ssize_t)s;
}
/* returns -1 on error, >= 0 and equal to # chars written on success */
ssize_t safe_write(int fd, const char *buf, size_t len)
{
size_t s = 0;
if (len > SSIZE_MAX) len = SSIZE_MAX;
while (s < len) {
ssize_t r = write(fd, buf + s, len - s);
if (r < 0) {
if (errno == EINTR)
continue;
else if ((errno == EAGAIN || errno == EWOULDBLOCK) && s > 0)
return (ssize_t)s;
else
return -1;
}
s += (size_t)r;
}
return (ssize_t)s;
}
/* returns -1 on error, >= 0 and equal to # chars written on success */
ssize_t safe_sendto(int fd, const char *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
size_t s = 0;
if (len > SSIZE_MAX) len = SSIZE_MAX;
while (s < len) {
ssize_t r = sendto(fd, buf + s, len - s, flags, dest_addr, addrlen);
if (r < 0) {
if (errno == EINTR)
continue;
else if ((errno == EAGAIN || errno == EWOULDBLOCK) && s > 0)
return (ssize_t)s;
else
return -1;
}
s += (size_t)r;
}
return (ssize_t)s;
}
ssize_t safe_recv(int fd, char *buf, size_t len, int flags)
{
size_t s = 0;
if (len > SSIZE_MAX) len = SSIZE_MAX;
while (s < len) {
ssize_t r = recv(fd, buf + s, len - s, flags);
if (r == 0)
break;
if (r < 0) {
if (errno == EINTR)
continue;
else if ((errno == EAGAIN || errno == EWOULDBLOCK) && s > 0)
return (ssize_t)s;
else
return -1;
}
s += (size_t)r;
}
return (ssize_t)s;
}
ssize_t safe_recvmsg(int fd, struct msghdr *msg, int flags)
{
ssize_t r;
retry:
r = recvmsg(fd, msg, flags);
if (r < 0 && errno == EINTR)
goto retry;
return r;
}

82
src/lib/log.c Normal file
View File

@ -0,0 +1,82 @@
/* log.c - simple logging support
*
* Copyright 2003-2018 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include "nk/log.h"
/* global logging flags */
int gflags_quiet = 0;
int gflags_detach = 0;
int gflags_debug = 0;
char *gflags_log_name = 0;
#define log_syslog(level) do { \
openlog(gflags_log_name, LOG_PID, LOG_DAEMON); \
va_start(argp, format); \
vsyslog(level | LOG_DAEMON, format, argp); \
va_end(argp); \
closelog(); } while(0)
#define log_stdio() do { \
va_start(argp, format); \
vfprintf(stderr, format, argp); \
fprintf(stderr, "\n"); \
va_end(argp); } while(0)
__attribute__ ((format (printf, 2, 3)))
void log_line_l(int level, const char format[static 1], ...)
{
va_list argp;
if (gflags_quiet)
return;
if (gflags_detach)
log_syslog(level);
else
log_stdio();
}
__attribute__ ((format (printf, 1, 2)))
void __attribute__((noreturn)) suicide(const char format[static 1], ...)
{
va_list argp;
if (gflags_detach)
log_syslog(LOG_ERR);
else
log_stdio();
exit(EXIT_FAILURE);
}
#undef log_syslog
#undef log_stdio

224
src/lib/privs.c Normal file
View File

@ -0,0 +1,224 @@
/* privs.c - uid/gid, chroot, and capability handling
*
* Copyright 2005-2018 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#ifdef __linux__
#include <sys/capability.h>
#include <sys/prctl.h>
#endif
#include "nk/privs.h"
#include "nk/log.h"
void nk_set_chroot(const char *chroot_dir)
{
if (chroot(chroot_dir))
suicide("%s: chroot('%s') failed: %s", __func__, chroot_dir,
strerror(errno));
if (chdir("/"))
suicide("%s: chdir('/') failed: %s", __func__, strerror(errno));
}
#ifdef NK_USE_CAPABILITY
static size_t nk_get_capability_vinfo(uint32_t version[static 1])
{
struct __user_cap_header_struct hdr;
memset(&hdr, 0, sizeof hdr);
if (capget(&hdr, (cap_user_data_t)0) < 0) {
if (errno != EINVAL)
suicide("%s: capget failed: %s", __func__, strerror(errno));
}
switch (hdr.version) {
case _LINUX_CAPABILITY_VERSION_1:
*version = _LINUX_CAPABILITY_VERSION_1;
return _LINUX_CAPABILITY_U32S_1;
case _LINUX_CAPABILITY_VERSION_2:
*version = _LINUX_CAPABILITY_VERSION_2;
return _LINUX_CAPABILITY_U32S_2;
default: log_warning("%s: unknown capability version %x, using %x",
__func__, *version, _LINUX_CAPABILITY_VERSION_3);
case _LINUX_CAPABILITY_VERSION_3:
*version = _LINUX_CAPABILITY_VERSION_3;
return _LINUX_CAPABILITY_U32S_3;
}
}
static size_t nk_set_capability_prologue(const unsigned char *caps,
size_t caplen,
uint32_t cversion[static 1])
{
if (!caps || !caplen)
return 0;
size_t csize = nk_get_capability_vinfo(cversion);
if (prctl(PR_SET_KEEPCAPS, 1))
suicide("%s: prctl failed: %s", __func__, strerror(errno));
return csize;
}
static void nk_set_capability_epilogue(const unsigned char *caps,
size_t caplen, uint32_t cversion,
size_t csize)
{
if (!caps || !caplen)
return;
struct __user_cap_header_struct hdr = {
.version = cversion,
.pid = 0,
};
struct __user_cap_data_struct data[csize];
uint32_t mask[csize];
memset(mask, 0, sizeof mask);
for (size_t i = 0; i < caplen; ++i) {
size_t j = caps[i] / 32;
if (j >= csize)
suicide("%s: caps[%zu] == %u, which is >= %u and out of range",
__func__, caps[i], csize * 32);
mask[j] |= (uint32_t)CAP_TO_MASK(caps[i] - 32 * j);
}
for (size_t i = 0; i < csize; ++i) {
data[i].effective = mask[i];
data[i].permitted = mask[i];
data[i].inheritable = 0;
}
if (capset(&hdr, (cap_user_data_t)&data) < 0)
suicide("%s: capset failed: %s", __func__, strerror(errno));
}
#else
static size_t nk_set_capability_prologue(const unsigned char *caps,
size_t caplen,
uint32_t cversion[static 1])
{ (void)caps; (void)caplen; (void)cversion; return 0; }
static void nk_set_capability_epilogue(const unsigned char *caps,
size_t caplen, uint32_t cversion,
size_t csize)
{ (void)caps; (void)caplen; (void)cversion; (void)csize; }
#endif
#ifdef NK_USE_NO_NEW_PRIVS
static void nk_set_no_new_privs(void)
{
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
suicide("%s: prctl failed: %s", __func__, strerror(errno));
}
#else
static void nk_set_no_new_privs(void) {}
#endif
void nk_set_uidgid(uid_t uid, gid_t gid, const unsigned char *caps,
size_t caplen)
{
uint32_t cversion = 0;
size_t csize = nk_set_capability_prologue(caps, caplen, &cversion);
if (setgroups(1, &gid))
suicide("%s: setgroups failed: %s", __func__, strerror(errno));
if (setresgid(gid, gid, gid))
suicide("%s: setresgid failed: %s", __func__, strerror(errno));
if (setresuid(uid, uid, uid))
suicide("%s: setresuid failed: %s", __func__, strerror(errno));
uid_t ruid, euid, suid;
if (getresuid(&ruid, &euid, &suid))
suicide("%s: getresuid failed: %s", __func__, strerror(errno));
if (ruid != uid || euid != uid || suid != uid)
suicide("%s: getresuid failed; the OS or libc is broken", __func__);
gid_t rgid, egid, sgid;
if (getresgid(&rgid, &egid, &sgid))
suicide("%s: getresgid failed: %s", __func__, strerror(errno));
if (rgid != gid || egid != gid || sgid != gid)
suicide("%s: getresgid failed; the OS or libc is broken", __func__);
if (uid && setreuid((uid_t)-1, 0) == 0)
suicide("%s: OS or libc broken; able to restore privs after drop",
__func__);
nk_set_capability_epilogue(caps, caplen, cversion, csize);
nk_set_no_new_privs();
}
uid_t nk_uidgidbyname(const char *username, uid_t *uid, gid_t *gid)
{
if (!username)
return (uid_t)-1;
struct passwd *pws = getpwnam(username);
if (!pws) {
for (size_t i = 0; username[i]; ++i) {
if (!isdigit(username[i]))
return (uid_t)-1;
}
char *p;
long lt = strtol(username, &p, 10);
if (errno == ERANGE && (lt == LONG_MIN || lt == LONG_MAX))
return (uid_t)-1;
if (lt < 0 || lt > (long)UINT_MAX)
return (uid_t)-1;
if (p == username)
return (uid_t)-1;
pws = getpwuid((uid_t)lt);
if (!pws)
return (uid_t)-1;
}
if (gid)
*gid = pws->pw_gid;
if (uid)
*uid = pws->pw_uid;
return (uid_t)0;
}
gid_t nk_gidbyname(const char *groupname, gid_t *gid)
{
if (!groupname)
return (gid_t)-1;
struct group *grp = getgrnam(groupname);
if (!grp) {
for (size_t i = 0; groupname[i]; ++i) {
if (!isdigit(groupname[i]))
return (gid_t)-1;
}
char *p;
long lt = strtol(groupname, &p, 10);
if (errno == ERANGE && (lt == LONG_MIN || lt == LONG_MAX))
return (gid_t)-1;
if (lt < 0 || lt > (long)UINT_MAX)
return (gid_t)-1;
if (p == groupname)
return (gid_t)-1;
grp = getgrgid((gid_t)lt);
if (!grp)
return (gid_t)-1;
}
if (gid)
return grp->gr_gid;
return (gid_t)0;
}

62
src/lib/random.c Normal file
View File

@ -0,0 +1,62 @@
/* random.c - non-cryptographic fast PRNG
*
* Copyright 2013-2018 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include "nk/hwrng.h"
#include "nk/random.h"
// GJrand64: https://gjrand.sourceforge.net
void nk_random_init(struct nk_random_state *s)
{
nk_get_hwrng(s->seed, sizeof(uint64_t) * 2);
s->seed[2] = 2000001;
s->seed[3] = 0;
for (size_t i = 0; i < 14; ++i) nk_random_u64(s);
}
static inline uint64_t rotl64(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
}
uint64_t nk_random_u64(struct nk_random_state *s)
{
s->seed[1] += s->seed[2];
s->seed[0] = rotl64(s->seed[0], 32);
s->seed[2] ^= s->seed[1];
s->seed[3] += 0x55aa96a5;
s->seed[0] += s->seed[1];
s->seed[2] = rotl64(s->seed[2], 23);
s->seed[1] ^= s->seed[0];
s->seed[0] += s->seed[2];
s->seed[1] = rotl64(s->seed[1], 19);
s->seed[2] += s->seed[0];
s->seed[1] += s->seed[3];
return s->seed[0];
}

View File

@ -48,8 +48,7 @@
#include <grp.h> #include <grp.h>
#include <limits.h> #include <limits.h>
#include "nk/log.h" #include "nk/log.h"
#include "nk/privilege.h" #include "nk/privs.h"
#include "nk/pidfile.h"
#include "nk/io.h" #include "nk/io.h"
#include "nk/copy_cmdarg.h" #include "nk/copy_cmdarg.h"
@ -153,9 +152,9 @@ void show_usage(void)
" -n, --now Exit with failure if lease cannot be\n" " -n, --now Exit with failure if lease cannot be\n"
" immediately negotiated.\n" " immediately negotiated.\n"
" -r, --request=IP IP address to request (default: none)\n" " -r, --request=IP IP address to request (default: none)\n"
" -u, --user=USER Change ndhc privileges to this user\n" " -u, --user=USER ndhc runs as this user\n"
" -U, --ifch-user=USER Change ndhc-ifch privileges to this user\n" " -U, --ifch-user=USER ndhc-ifch runs as this user\n"
" -D, --sockd-user=USER Change ndhc-sockd privileges to this user\n" " -D, --sockd-user=USER ndhc-sockd runs as this user\n"
" -C, --chroot=DIR Chroot to this directory\n" " -C, --chroot=DIR Chroot to this directory\n"
" -s, --state-dir=DIR State storage dir (default: /etc/ndhc)\n" " -s, --state-dir=DIR State storage dir (default: /etc/ndhc)\n"
" -d, --relentless-defense Never back off in defending IP against\n" " -d, --relentless-defense Never back off in defending IP against\n"

18
src/nk/copy_cmdarg.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef NCMLIB_COPY_CMDARG_H_
#define NCMLIB_COPY_CMDARG_H_
#include <stdio.h>
#include <stdlib.h>
#include "nk/log.h"
static inline void copy_cmdarg(char *dest, const char *src,
size_t destlen, const char *argname)
{
ssize_t olen = snprintf(dest, destlen, "%s", src);
if (olen < 0)
suicide("snprintf failed on %s; your system is broken?", argname);
if ((size_t)olen >= destlen)
suicide("snprintf would truncate %s arg; it's too long", argname);
}
#endif /* NCMLIB_COPY_CMDARG_H_ */

37
src/nk/hwrng.h Normal file
View File

@ -0,0 +1,37 @@
/* hwrng.h - access to system CRNG
*
* Copyright 2016 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef NCMLIB_HWCRNG__
#define NCMLIB_HWCRNG__
#include <stddef.h>
void nk_get_hwrng(void *seed, size_t len);
#endif

41
src/nk/io.h Normal file
View File

@ -0,0 +1,41 @@
/* io.h - light wrappers for POSIX i/o functions
*
* Copyright 2010-2015 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef NCM_IO_H_
#define NCM_IO_H_
#include <sys/socket.h>
ssize_t safe_read(int fd, char *buf, size_t len);
ssize_t safe_write(int fd, const char *buf, size_t len);
ssize_t safe_sendto(int fd, const char *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t safe_recv(int fd, char *buf, size_t len, int flags);
ssize_t safe_recvmsg(int fd, struct msghdr *msg, int flags);
#endif /* NCM_IO_H_ */

48
src/nk/log.h Normal file
View File

@ -0,0 +1,48 @@
/* log.h - simple logging support
*
* Copyright 2003-2015 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef NCM_LOG_H_
#define NCM_LOG_H_
#include <syslog.h>
extern int gflags_quiet;
extern int gflags_detach;
extern int gflags_debug;
extern char *gflags_log_name;
#define log_line(...) log_line_l(LOG_INFO, __VA_ARGS__)
#define log_debug(...) if (gflags_debug) log_line_l(LOG_DEBUG, __VA_ARGS__)
#define log_warning(...) log_line_l(LOG_WARNING, __VA_ARGS__)
#define log_error(...) log_line_l(LOG_ERR, __VA_ARGS__)
void log_line_l(int level, const char *format, ...);
void __attribute__((noreturn)) suicide(const char *format, ...);
#endif

54
src/nk/net_checksum.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef NCMLIB_NET_CHECKSUM_H
#define NCMLIB_NET_CHECKSUM_H
#include <stdint.h>
// When summing ones-complement 16-bit values using a 32-bit unsigned
// representation, fold the carry bits that have spilled into the upper
// 16-bits of the 32-bit unsigned value back into the 16-bit ones-complement
// binary value.
static inline uint16_t net_checksum161c_foldcarry(uint32_t v)
{
v = (v >> 16) + (v & 0xffff);
v += v >> 16;
return v;
}
// This function is not suitable for summing buffers that are greater than
// 128k bytes in length: failure case will be incorrect checksums via
// unsigned overflow, which is a defined operation and is safe. This limit
// should not be an issue for IPv4 or IPv6 packet, which are limited to
// at most 64k bytes.
static uint16_t net_checksum161c(const void *buf, size_t size)
{
uint32_t sum = 0;
int odd = size & 0x01;
size_t i;
size &= ~((size_t)0x01);
size >>= 1;
const uint8_t *b = (const uint8_t *)buf;
for (i = 0; i < size; ++i) {
uint16_t hi = b[i*2];
uint16_t lo = b[i*2+1];
sum += ntohs((lo + (hi << 8)));
}
if (odd) {
uint16_t hi = b[i*2];
uint16_t lo = 0;
sum += ntohs((lo + (hi << 8)));
}
return ~net_checksum161c_foldcarry(sum);
}
// For two sequences of bytes A and B that return checksums CS(A) and CS(B),
// this function will calculate the checksum CS(AB) of the concatenated value
// AB given the checksums of the individual parts CS(A) and CS(B).
static inline uint16_t net_checksum161c_add(uint16_t a, uint16_t b)
{
const uint32_t A = a;
const uint32_t B = b;
return ~net_checksum161c_foldcarry((~A & 0xffffu) + (~B & 0xffffu));
}
#endif

44
src/nk/privs.h Normal file
View File

@ -0,0 +1,44 @@
/* privs.h - uid/gid, chroot, and capability handling
*
* Copyright 2005-2014 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef NCM_PRIVS_H_
#define NCM_PRIVS_H_
#include <unistd.h>
#ifdef __linux__
#include <sys/capability.h>
#endif
void nk_set_chroot(const char *chroot_dir);
void nk_set_uidgid(uid_t uid, gid_t gid, const unsigned char *caps,
size_t caplen);
uid_t nk_uidgidbyname(const char *username, uid_t *uid, gid_t *gid);
gid_t nk_gidbyname(const char *groupname, gid_t *gid);
#endif

45
src/nk/random.h Normal file
View File

@ -0,0 +1,45 @@
/* random.h - non-cryptographic fast PRNG
*
* Copyright 2013-2018 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef NCMLIB_RANDOM__
#define NCMLIB_RANDOM__
#include <stdint.h>
struct nk_random_state {
uint64_t seed[4];
};
void nk_random_init(struct nk_random_state *s);
uint64_t nk_random_u64(struct nk_random_state *s);
static inline uint32_t nk_random_u32(struct nk_random_state *s)
{
// Discard lower bits as they have less linear complexity.
return nk_random_u64(s) >> 32;
}
#endif

View File

@ -50,7 +50,7 @@
#include <grp.h> #include <grp.h>
#include "nk/log.h" #include "nk/log.h"
#include "nk/io.h" #include "nk/io.h"
#include "nk/privilege.h" #include "nk/privs.h"
#include "sockd.h" #include "sockd.h"
#include "ndhc-defines.h" #include "ndhc-defines.h"