Support s6 service startup notification

This can be enabled via the s6-notify configure option; see
http://www.skarnet.org/software/s6/notifywhenup.html for details.

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

A typical command line option assuming the s6 service directory
notification-fd contains '3' would be '--s6-notify 3', and
a typical configure file option would be 's6-notify 3'.
This commit is contained in:
Nicholas J. Kain 2022-02-12 16:31:39 -05:00
parent d67e1599df
commit 2fb16567f1
6 changed files with 1493 additions and 991 deletions

2434
cfg.c

File diff suppressed because it is too large Load Diff

10
cfg.rl
View File

@ -149,6 +149,10 @@ struct cfgparse {
client_config.rfkillIdx = t; client_config.rfkillIdx = t;
client_config.enable_rfkill = true; client_config.enable_rfkill = true;
} }
action s6_notify {
client_config.s6_notify_fd = atoi(ccfg.buf);
client_config.enable_s6_notify = true;
}
action version { print_version(); exit(EXIT_SUCCESS); } action version { print_version(); exit(EXIT_SUCCESS); }
action help { show_usage(); exit(EXIT_SUCCESS); } action help { show_usage(); exit(EXIT_SUCCESS); }
}%% }%%
@ -190,13 +194,14 @@ struct cfgparse {
resolv_conf = 'resolv-conf' value @resolv_conf; resolv_conf = 'resolv-conf' value @resolv_conf;
dhcp_set_hostname = 'dhcp-set-hostname' boolval @dhcp_set_hostname; dhcp_set_hostname = 'dhcp-set-hostname' boolval @dhcp_set_hostname;
rfkill_idx = 'rfkill-idx' value @rfkill_idx; rfkill_idx = 'rfkill-idx' value @rfkill_idx;
s6_notify = 's6-notify' value @s6_notify;
main := blankline | main := blankline |
clientid | hostname | interface | now | clientid | hostname | interface | now |
request | vendorid | user | ifch_user | sockd_user | chroot | request | vendorid | user | ifch_user | sockd_user | chroot |
state_dir | seccomp_enforce | relentless_defense | arp_probe_wait | state_dir | seccomp_enforce | relentless_defense | arp_probe_wait |
arp_probe_num | arp_probe_min | arp_probe_max | gw_metric | arp_probe_num | arp_probe_min | arp_probe_max | gw_metric |
resolv_conf | dhcp_set_hostname | rfkill_idx resolv_conf | dhcp_set_hostname | rfkill_idx | s6_notify
; ;
}%% }%%
@ -292,6 +297,7 @@ static void parse_cfgfile(const char *fname)
resolv_conf = ('-R'|'--resolv-conf') argval @resolv_conf; resolv_conf = ('-R'|'--resolv-conf') argval @resolv_conf;
dhcp_set_hostname = ('-H'|'--dhcp-set-hostname') tbv @dhcp_set_hostname; dhcp_set_hostname = ('-H'|'--dhcp-set-hostname') tbv @dhcp_set_hostname;
rfkill_idx = ('-K'|'--rfkill-idx') argval @rfkill_idx; rfkill_idx = ('-K'|'--rfkill-idx') argval @rfkill_idx;
s6_notify = ('-N'|'--s6-notify') argval @s6_notify;
version = ('-v'|'--version') 0 @version; version = ('-v'|'--version') 0 @version;
help = ('-?'|'--help') 0 @help; help = ('-?'|'--help') 0 @help;
@ -300,7 +306,7 @@ static void parse_cfgfile(const char *fname)
now | request | vendorid | user | ifch_user | sockd_user | now | request | vendorid | user | ifch_user | sockd_user |
chroot | state_dir | seccomp_enforce | relentless_defense | chroot | state_dir | seccomp_enforce | relentless_defense |
arp_probe_wait | arp_probe_num | arp_probe_min | arp_probe_max | arp_probe_wait | arp_probe_num | arp_probe_min | arp_probe_max |
gw_metric | resolv_conf | dhcp_set_hostname | rfkill_idx | gw_metric | resolv_conf | dhcp_set_hostname | rfkill_idx | s6_notify |
version | help version | help
)*; )*;
}%% }%%

View File

@ -42,6 +42,13 @@ void open_leasefile(void)
void write_leasefile(struct in_addr ipnum) void write_leasefile(struct in_addr ipnum)
{ {
if (client_config.enable_s6_notify) {
static char buf[] = "\n";
safe_write(client_config.s6_notify_fd, buf, 1);
close(client_config.s6_notify_fd);
client_config.enable_s6_notify = false;
}
char ip[INET_ADDRSTRLEN]; char ip[INET_ADDRSTRLEN];
char out[INET_ADDRSTRLEN*2]; char out[INET_ADDRSTRLEN*2];
if (leasefilefd < 0) { if (leasefilefd < 0) {

6
ndhc.8
View File

@ -125,6 +125,12 @@ an rfkill-idx parameter is specified, ndhc will print messages for any
rfkill events that it sees, so it should not be too difficult to locate rfkill events that it sees, so it should not be too difficult to locate
the proper rfkill device by checking the logs after hitting the switch. the proper rfkill device by checking the logs after hitting the switch.
.TP .TP
.BI \-N\ NOTIFY_FDNUM ,\ \-\-s6\-notify= NOTIFY_FDNUM
If set, specifies the file descriptor number that will have a '\n' written to
and closed when the first DHCP lease is bound. This option should be used when
ndhc is run under a s6 supervisor that implements service startup
notifications.
.TP
.BI \-v ,\ \-\-version .BI \-v ,\ \-\-version
Display the ndhc version number. Display the ndhc version number.
.SH SIGNALS .SH SIGNALS

1
ndhc.c
View File

@ -59,6 +59,7 @@ struct client_state_t cs = {
struct client_config_t client_config = { struct client_config_t client_config = {
.interface = "eth0", .interface = "eth0",
.arp = "\0\0\0\0\0\0", .arp = "\0\0\0\0\0\0",
.s6_notify_fd = 3,
.clientid_len = 0, .clientid_len = 0,
.metric = 0, .metric = 0,
}; };

2
ndhc.h
View File

@ -49,9 +49,11 @@ struct client_config_t {
uint32_t rfkillIdx; // Index of the corresponding rfkill device uint32_t rfkillIdx; // Index of the corresponding rfkill device
int metric; // Metric for the default route int metric; // Metric for the default route
int ifindex; // Index number of the interface to use int ifindex; // Index number of the interface to use
int s6_notify_fd; // File descriptor for s6 notify mechanism
uint8_t clientid_len; // Length of the clientid uint8_t clientid_len; // Length of the clientid
bool abort_if_no_lease; // Abort if no lease bool abort_if_no_lease; // Abort if no lease
bool enable_rfkill; // Listen for rfkill events bool enable_rfkill; // Listen for rfkill events
bool enable_s6_notify; // Perform s6 startup notification
}; };
enum { enum {