Compare commits

...

10 Commits

Author SHA1 Message Date
Nicholas J. Kain
3ff8685fc6
cfg.rl: Build with compact table-driven Ragel mode.
This reduces binary size by over 10% and the small hit to
config file parsing performance is insignificant and only
paid once at startup.
2023-02-13 00:27:18 -05:00
Nicholas J. Kain
d9e0afdc7c
Move get_clientid_string() to cfg.rl. 2023-02-13 00:18:16 -05:00
Nicholas J. Kain
aa684baad7
Don't use ctype.h functions. 2023-02-11 20:45:30 -05:00
Nicholas J. Kain
841c8663e9
Make example s6 script handle empty leasefile properly.
Prior to this change, ndhc would fail to run with a malformed
command error if the leasefile was empty since the -r parameter
requires an argument.

Note that this script requires execline 2.9.1.0 for the
eltest program.  For earlier versions of s6, it should be
fine to use the POSIX test program instead.
2023-01-18 12:54:55 -05:00
Nicholas J. Kain
44511e6789
Don't overwrite a possibly valid leasefile if we have no valid lease. 2023-01-18 08:08:33 -05:00
Nicholas J. Kain
1b8dc7f05e
random: Use sfc64 instead of gjrand. 2022-10-13 08:43:11 -04:00
Nicholas J. Kain
1c1ea86604
ifset: Use a slightly better portable ctz().
The behavior is identical but the codegen is improved.
2022-09-24 14:12:02 -04:00
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
10 changed files with 1941 additions and 11749 deletions

View File

@ -23,7 +23,7 @@ ifchd-parse.c:
ragel -G2 -o ifchd-parse.c ifchd-parse.rl
cfg.c:
ragel -G2 -o cfg.c cfg.rl
ragel -T0 -o cfg.c cfg.rl
ragel: ifchd-parse.c cfg.c

13523
cfg.c

File diff suppressed because it is too large Load Diff

38
cfg.rl
View File

@ -9,6 +9,7 @@
#include <limits.h>
#include "ndhc-defines.h"
#include "cfg.h"
#include "sys.h"
#include "arp.h"
#include "ndhc.h"
#include "ifchd.h"
@ -17,6 +18,43 @@
#include "nk/privs.h"
#include "nk/io.h"
static bool xisxdigit(int c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}
static bool is_string_hwaddr(const char *str, size_t slen)
{
return slen == 17 && str[2] == ':' && str[5] == ':' && str[8] == ':' &&
str[11] == ':' && str[14] == ':' &&
xisxdigit(str[0]) && xisxdigit(str[1]) && xisxdigit(str[3]) &&
xisxdigit(str[4]) && xisxdigit(str[6]) && xisxdigit(str[7]) &&
xisxdigit(str[9]) && xisxdigit(str[10]) && xisxdigit(str[12]) &&
xisxdigit(str[13]) && xisxdigit(str[15]) && xisxdigit(str[16]);
}
static int get_clientid_string(const char *str, size_t slen)
{
if (!slen)
return -1;
if (!is_string_hwaddr(str, slen)) {
client_config.clientid[0] = 0;
memcpy(client_config.clientid + 1, str,
min_size_t(slen, sizeof client_config.clientid - 1));
client_config.clientid_len = slen + 1;
return 0;
}
uint8_t mac[6];
for (size_t i = 0; i < sizeof mac; ++i)
mac[i] = strtol(str+i*3, (char **)0, 16);
client_config.clientid[0] = 1; // Ethernet MAC type
memcpy(client_config.clientid + 1, mac,
min_size_t(sizeof mac, sizeof client_config.clientid - 1));
client_config.clientid_len = 7;
return 1;
}
static void copy_cmdarg(char *dest, const char *src,
size_t destlen, const char *argname)
{

View File

@ -1,6 +1,8 @@
#!/bin/execlineb -P
fdmove -c 2 1
backtick OLDEXTIP { cat /etc/firewall/tmp/OLDEXTIP }
backtick OLDEXTIP { cat /etc/ndhc/LEASE-wan0 }
importas OLDEXTIP OLDEXTIP
/sbin/ndhc -c /etc/ndhc/wan0.conf -r $OLDEXTIP
ifelse { eltest -n $OLDEXTIP }
{ /sbin/ndhc -c /etc/ndhc/wan0.conf -r $OLDEXTIP }
/sbin/ndhc -c /etc/ndhc/wan0.conf

13
ifset.c
View File

@ -29,15 +29,14 @@
static uint32_t ifset_nl_seq = 1;
// 32-bit position values are relatively prime to 37, so the residue mod37
// gives a unique mapping for each value. Gives correct result for v=0.
static int trailz(uint32_t v)
// Portable ctz() that gives a defined result for x == 0.
static int trailz(uint32_t x)
{
static const int bpm37[] = {
32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17,
0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18
static const int ctzt[32] = {
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10,
};
return bpm37[(-v & v) % 37];
return x ? ctzt[((x & -x) * 0x077cb531u) >> 27] : 32;
}
// sn must be in network order

View File

@ -33,7 +33,7 @@ void open_leasefile(void)
{
char leasefile[PATH_MAX];
get_leasefile_path(leasefile, sizeof leasefile, client_config.interface);
leasefilefd = open(leasefile, O_WRONLY|O_TRUNC|O_CREAT|O_CLOEXEC, 0644);
leasefilefd = open(leasefile, O_WRONLY|O_CREAT|O_CLOEXEC, 0644);
if (leasefilefd < 0)
suicide("%s: (%s) Failed to create lease file '%s': %s",
client_config.interface, __func__, leasefile, strerror(errno));
@ -59,6 +59,10 @@ static void do_write_leasefile(struct in_addr ipnum)
log_line("%s: (%s) memccpy failed", client_config.interface, __func__);
return;
}
size_t outlen = strlen(out);
// Make sure that we're not overwriting the leasefile with an invalid
// IP address. This is a very minimal check.
if (outlen < 7) return;
if (safe_ftruncate(leasefilefd, 0)) {
log_line("%s: (%s) Failed to truncate lease file: %s",
client_config.interface, __func__, strerror(errno));
@ -69,7 +73,6 @@ static void do_write_leasefile(struct in_addr ipnum)
client_config.interface, __func__, strerror(errno));
return;
}
size_t outlen = strlen(out);
ssize_t ret = safe_write(leasefilefd, out, outlen);
if (ret < 0 || (size_t)ret != outlen)
log_line("%s: (%s) Failed to write ip to lease file.",

66
ndhc.c
View File

@ -10,7 +10,6 @@
#include <signal.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@ -198,41 +197,6 @@ static void setup_signals_ndhc(void)
suicide("sigaction failed");
}
static int is_string_hwaddr(const char *str, size_t slen)
{
if (slen == 17 && str[2] == ':' && str[5] == ':' && str[8] == ':' &&
str[11] == ':' && str[14] == ':' &&
isxdigit(str[0]) && isxdigit(str[1]) && isxdigit(str[3]) &&
isxdigit(str[4]) && isxdigit(str[6]) && isxdigit(str[7]) &&
isxdigit(str[9]) && isxdigit(str[10]) && isxdigit(str[12]) &&
isxdigit(str[13]) && isxdigit(str[15]) && isxdigit(str[16])
)
return 1;
return 0;
}
int get_clientid_string(const char *str, size_t slen)
{
if (!slen)
return -1;
if (!is_string_hwaddr(str, slen)) {
client_config.clientid[0] = 0;
memcpy(client_config.clientid + 1, str,
min_size_t(slen, sizeof client_config.clientid - 1));
client_config.clientid_len = slen + 1;
return 0;
}
uint8_t mac[6];
for (size_t i = 0; i < sizeof mac; ++i)
mac[i] = strtol(str+i*3, (char **)0, 16);
client_config.clientid[0] = 1; // Ethernet MAC type
memcpy(client_config.clientid + 1, mac,
min_size_t(sizeof mac, sizeof client_config.clientid - 1));
client_config.clientid_len = 7;
return 1;
}
static void fail_if_state_dir_dne(void)
{
if (strlen(state_dir) == 0)
@ -257,24 +221,21 @@ static void do_ndhc_work(void)
setup_signals_ndhc();
start_dhcp_listen(&cs);
struct pollfd pfds[6] = {0};
pfds[0].fd = cs.nlFd;
pfds[0].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
pfds[1].fd = ifchStream[0];
pfds[1].events = POLLHUP|POLLERR|POLLRDHUP;
pfds[2].fd = sockdStream[0];
pfds[2].events = POLLHUP|POLLERR|POLLRDHUP;
pfds[3].fd = cs.rfkillFd;
pfds[3].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
// These can change on the fly.
pfds[4].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
pfds[5].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
struct pollfd pfds[] = {
[0] = { .fd = cs.nlFd, .events = POLLIN|POLLHUP|POLLERR|POLLRDHUP },
[1] = { .fd = ifchStream[0], .events = POLLHUP|POLLERR|POLLRDHUP },
[2] = { .fd = sockdStream[0], .events = POLLHUP|POLLERR|POLLRDHUP },
[6] = { .fd = scriptdStream[0], .events = POLLHUP|POLLERR|POLLRDHUP },
[3] = { .fd = cs.rfkillFd, .events = POLLIN|POLLHUP|POLLERR|POLLRDHUP },
// These can change on the fly.
[4] = { .events = POLLIN|POLLHUP|POLLERR|POLLRDHUP },
[5] = { .events = POLLIN|POLLHUP|POLLERR|POLLRDHUP },
};
for (;;) {
pfds[4].fd = cs.arpFd;
pfds[5].fd = cs.listenFd;
had_event = false;
if (poll(pfds, 6, timeout) < 0) {
if (poll(pfds, 7, timeout) < 0) {
if (errno != EINTR) suicide("poll failed");
}
@ -300,6 +261,9 @@ static void do_ndhc_work(void)
if (pfds[2].revents & (POLLHUP|POLLERR|POLLRDHUP)) {
exit(EXIT_FAILURE);
}
if (pfds[6].revents & (POLLHUP|POLLERR|POLLRDHUP)) {
exit(EXIT_FAILURE);
}
if (pfds[3].revents & POLLIN) {
had_event = true;
sev_rfk = rfkill_get(&cs, 1, client_config.rfkillIdx);
@ -411,7 +375,7 @@ int ifchStream[2];
int sockdSock[2];
int sockdStream[2];
int scriptdSock[2];
int scriptdStream[2];
int scriptdStream[2] = { -1, -1 };
static void create_ifch_ipc_sockets(void) {
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ifchSock) < 0)

1
ndhc.h
View File

@ -83,7 +83,6 @@ bool carrier_isup(void);
void set_client_addr(const char *v);
void show_usage(void);
void signal_exit(int status);
int get_clientid_string(const char *str, size_t slen);
void print_version(void);
static inline void advance_xid(struct client_state_t *cs) {

View File

@ -1,17 +1,16 @@
// Copyright 2013-2018 Nicholas J. Kain <njkain at gmail dot com>
// Copyright 2013-2022 Nicholas J. Kain <njkain at gmail dot com>
// SPDX-License-Identifier: MIT
#include <stdint.h>
#include "nk/hwrng.h"
#include "nk/random.h"
// GJrand64: https://gjrand.sourceforge.net
// SFC64 modified to use a Weyl counter.
void nk_random_init(struct nk_random_state *s)
{
nk_hwrng_bytes(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);
nk_hwrng_bytes(s->seed, sizeof(uint64_t) * 3);
s->seed[3] = 1;
for (size_t i = 0; i < 12; ++i) nk_random_u64(s);
}
static inline uint64_t rotl64(const uint64_t x, int k) {
@ -20,17 +19,11 @@ static inline uint64_t rotl64(const uint64_t x, int 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];
const uint64_t t = (s->seed[0] + s->seed[1]) ^ s->seed[3];
s->seed[3] += 0x6a09e667a7541669ull;
s->seed[0] = s->seed[1] ^ (s->seed[1] >> 11);
s->seed[1] = s->seed[2] + (s->seed[2] << 3);
s->seed[2] = rotl64(s->seed[2], 24) + t;
return t;
}

View File

@ -10,6 +10,7 @@
#include <sys/wait.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "nk/log.h"
#include "nk/io.h"
#include "nk/pspawn.h"
@ -138,7 +139,7 @@ static void setup_signals_scriptd(void)
struct sigaction sa = {
.sa_handler = signal_handler,
.sa_flags = SA_RESTART|SA_NOCLDWAIT,
.sa_flags = SA_RESTART,
};
if (sigemptyset(&sa.sa_mask))
suicide("sigemptyset failed");
@ -153,6 +154,8 @@ void scriptd_main(void)
prctl(PR_SET_NAME, "ndhc: scriptd");
umask(077);
setup_signals_scriptd();
fcntl(scriptdSock[1], F_SETFD, FD_CLOEXEC);
fcntl(scriptdStream[1], F_SETFD, FD_CLOEXEC);
do_scriptd_work();
}