Parse config options with ragel and support a configuration file.
This commit is contained in:
parent
51033d3664
commit
a501789e04
@ -5,6 +5,7 @@ cmake_minimum_required (VERSION 2.6)
|
|||||||
include_directories("${PROJECT_SOURCE_DIR}")
|
include_directories("${PROJECT_SOURCE_DIR}")
|
||||||
|
|
||||||
set(RAGEL_IFCHD_PARSE ${CMAKE_CURRENT_BINARY_DIR}/ifchd-parse.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)
|
find_program(RAGEL ragel)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
@ -15,8 +16,16 @@ add_custom_command(
|
|||||||
COMMENT "Compiling Ragel state machine: ifchd-parse.rl"
|
COMMENT "Compiling Ragel state machine: ifchd-parse.rl"
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
file(GLOB NDHC_SRCS "*.c")
|
file(GLOB NDHC_SRCS "*.c")
|
||||||
|
|
||||||
add_executable(ndhc ${RAGEL_IFCHD_PARSE} ${NDHC_SRCS})
|
add_executable(ndhc ${RAGEL_CFG_PARSE} ${RAGEL_IFCHD_PARSE} ${NDHC_SRCS})
|
||||||
target_link_libraries(ndhc ncmlib)
|
target_link_libraries(ndhc ncmlib)
|
||||||
|
@ -122,7 +122,7 @@ static struct arp_data garp = {
|
|||||||
.server_replied = false,
|
.server_replied = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_arp_relentless_def(void) { garp.relentless_def = true; }
|
void set_arp_relentless_def(bool v) { garp.relentless_def = v; }
|
||||||
|
|
||||||
static void arp_reply_clear(void)
|
static void arp_reply_clear(void)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#ifndef ARP_H_
|
#ifndef ARP_H_
|
||||||
#define ARP_H_
|
#define ARP_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <net/if_arp.h>
|
#include <net/if_arp.h>
|
||||||
#include "ndhc.h"
|
#include "ndhc.h"
|
||||||
@ -57,7 +58,7 @@ extern int arp_probe_num;
|
|||||||
extern int arp_probe_min;
|
extern int arp_probe_min;
|
||||||
extern int arp_probe_max;
|
extern int arp_probe_max;
|
||||||
|
|
||||||
void set_arp_relentless_def(void);
|
void set_arp_relentless_def(bool v);
|
||||||
void arp_reset_send_stats(void);
|
void arp_reset_send_stats(void);
|
||||||
void arp_close_fd(struct client_state_t *cs);
|
void arp_close_fd(struct client_state_t *cs);
|
||||||
int arp_check(struct client_state_t *cs, struct dhcpmsg *packet);
|
int arp_check(struct client_state_t *cs, struct dhcpmsg *packet);
|
||||||
|
7
src/cfg.h
Normal file
7
src/cfg.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef NDHC_CONFIG_H_
|
||||||
|
#define NDHC_CONFIG_H_
|
||||||
|
|
||||||
|
void parse_cmdline(int argc, char *argv[]);
|
||||||
|
|
||||||
|
#endif /* NDHC_CONFIG_H_ */
|
||||||
|
|
321
src/cfg.rl
Normal file
321
src/cfg.rl
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include "ndhc-defines.h"
|
||||||
|
#include "cfg.h"
|
||||||
|
#include "arp.h"
|
||||||
|
#include "ndhc.h"
|
||||||
|
#include "ifchd.h"
|
||||||
|
#include "sockd.h"
|
||||||
|
#include "seccomp.h"
|
||||||
|
#include "nk/log.h"
|
||||||
|
#include "nk/privilege.h"
|
||||||
|
#include "nk/copy_cmdarg.h"
|
||||||
|
|
||||||
|
struct cfgparse {
|
||||||
|
char buf[MAX_BUF];
|
||||||
|
size_t buflen;
|
||||||
|
int ternary; // = 0 nothing, -1 = false, +1 = true
|
||||||
|
int cs;
|
||||||
|
};
|
||||||
|
|
||||||
|
%%{
|
||||||
|
machine cfg_actions;
|
||||||
|
access ccfg.;
|
||||||
|
|
||||||
|
action clear { memset(&ccfg, 0, sizeof ccfg); }
|
||||||
|
action append {
|
||||||
|
if (ccfg.buflen < sizeof ccfg.buf - 1)
|
||||||
|
ccfg.buf[ccfg.buflen++] = *p;
|
||||||
|
else
|
||||||
|
suicide("line or option is too long");
|
||||||
|
}
|
||||||
|
action term {
|
||||||
|
if (ccfg.buflen < sizeof ccfg.buf)
|
||||||
|
ccfg.buf[ccfg.buflen] = 0;
|
||||||
|
}
|
||||||
|
action truval { ccfg.ternary = 1; }
|
||||||
|
action falsval { ccfg.ternary = -1; }
|
||||||
|
|
||||||
|
action clientid { get_clientid_string(ccfg.buf, ccfg.buflen); }
|
||||||
|
action background {
|
||||||
|
switch (ccfg.ternary) {
|
||||||
|
case 1:
|
||||||
|
client_config.background_if_no_lease = 1;
|
||||||
|
gflags_detach = 1;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
client_config.background_if_no_lease = 0;
|
||||||
|
gflags_detach = 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action pidfile {
|
||||||
|
copy_cmdarg(pidfile, ccfg.buf, sizeof pidfile, "pidfile");
|
||||||
|
}
|
||||||
|
action hostname {
|
||||||
|
copy_cmdarg(client_config.hostname, ccfg.buf,
|
||||||
|
sizeof client_config.hostname, "hostname");
|
||||||
|
}
|
||||||
|
action interface {
|
||||||
|
copy_cmdarg(client_config.interface, ccfg.buf,
|
||||||
|
sizeof client_config.interface, "interface");
|
||||||
|
}
|
||||||
|
action now {
|
||||||
|
switch (ccfg.ternary) {
|
||||||
|
case 1: client_config.abort_if_no_lease = 1; break;
|
||||||
|
case -1: client_config.abort_if_no_lease = 0; default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action quit {
|
||||||
|
switch (ccfg.ternary) {
|
||||||
|
case 1: client_config.quit_after_lease = 1; break;
|
||||||
|
case -1: client_config.quit_after_lease = 0; default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action request { set_client_addr(ccfg.buf); }
|
||||||
|
action vendorid {
|
||||||
|
copy_cmdarg(client_config.vendor, ccfg.buf,
|
||||||
|
sizeof client_config.vendor, "vendorid");
|
||||||
|
}
|
||||||
|
action user {
|
||||||
|
if (nk_uidgidbyname(ccfg.buf, &ndhc_uid, &ndhc_gid))
|
||||||
|
suicide("invalid ndhc user '%s' specified", ccfg.buf);
|
||||||
|
}
|
||||||
|
action ifch_user {
|
||||||
|
if (nk_uidgidbyname(ccfg.buf, &ifch_uid, &ifch_gid))
|
||||||
|
suicide("invalid ifch user '%s' specified", ccfg.buf);
|
||||||
|
}
|
||||||
|
action sockd_user {
|
||||||
|
if (nk_uidgidbyname(ccfg.buf, &sockd_uid, &sockd_gid))
|
||||||
|
suicide("invalid sockd user '%s' specified", ccfg.buf);
|
||||||
|
}
|
||||||
|
action chroot {
|
||||||
|
copy_cmdarg(chroot_dir, ccfg.buf, sizeof chroot_dir, "chroot");
|
||||||
|
}
|
||||||
|
action state_dir {
|
||||||
|
copy_cmdarg(state_dir, ccfg.buf, sizeof state_dir, "state-dir");
|
||||||
|
}
|
||||||
|
action seccomp_enforce {
|
||||||
|
switch (ccfg.ternary) {
|
||||||
|
case 1: seccomp_enforce = true; break;
|
||||||
|
case -1: seccomp_enforce = false; default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action relentless_defense {
|
||||||
|
switch (ccfg.ternary) {
|
||||||
|
case 1: set_arp_relentless_def(true); break;
|
||||||
|
case -1: set_arp_relentless_def(false); default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action arp_probe_wait {
|
||||||
|
int t = atoi(ccfg.buf);
|
||||||
|
if (t >= 0)
|
||||||
|
arp_probe_wait = t;
|
||||||
|
}
|
||||||
|
action arp_probe_num {
|
||||||
|
int t = atoi(ccfg.buf);
|
||||||
|
if (t >= 0)
|
||||||
|
arp_probe_num = t;
|
||||||
|
}
|
||||||
|
action arp_probe_min {
|
||||||
|
int t = atoi(ccfg.buf);
|
||||||
|
arp_probe_min = t;
|
||||||
|
if (arp_probe_min > arp_probe_max) {
|
||||||
|
t = arp_probe_max;
|
||||||
|
arp_probe_max = arp_probe_min;
|
||||||
|
arp_probe_min = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action arp_probe_max {
|
||||||
|
int t = atoi(ccfg.buf);
|
||||||
|
arp_probe_max = t;
|
||||||
|
if (arp_probe_min > arp_probe_max) {
|
||||||
|
t = arp_probe_max;
|
||||||
|
arp_probe_max = arp_probe_min;
|
||||||
|
arp_probe_min = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action gw_metric {
|
||||||
|
char *q;
|
||||||
|
long mt = strtol(ccfg.buf, &q, 10);
|
||||||
|
if (q == ccfg.buf)
|
||||||
|
suicide("gw-metric arg '%s' isn't a valid number", ccfg.buf);
|
||||||
|
if (mt > INT_MAX)
|
||||||
|
suicide("gw-metric arg '%s' is too large", ccfg.buf);
|
||||||
|
if (mt < 0)
|
||||||
|
mt = 0;
|
||||||
|
client_config.metric = (int)mt;
|
||||||
|
}
|
||||||
|
action resolv_conf {
|
||||||
|
copy_cmdarg(resolv_conf_d, ccfg.buf, sizeof resolv_conf_d,
|
||||||
|
"resolv-conf");
|
||||||
|
}
|
||||||
|
action dhcp_set_hostname {
|
||||||
|
switch (ccfg.ternary) {
|
||||||
|
case 1: allow_hostname = 1; break;
|
||||||
|
case -1: allow_hostname = 0; default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action version { print_version(); exit(EXIT_SUCCESS); }
|
||||||
|
action help { show_usage(); exit(EXIT_SUCCESS); }
|
||||||
|
}%%
|
||||||
|
|
||||||
|
%%{
|
||||||
|
machine file_cfg;
|
||||||
|
access ccfg.;
|
||||||
|
include cfg_actions;
|
||||||
|
|
||||||
|
spc = [ \t];
|
||||||
|
delim = spc* '=' spc*;
|
||||||
|
string = [^\n]+ >clear $append %term;
|
||||||
|
term = '\n';
|
||||||
|
value = delim string term;
|
||||||
|
truval = ('true'|'1') % truval;
|
||||||
|
falsval = ('false'|'0') % falsval;
|
||||||
|
boolval = delim (truval|falsval) term;
|
||||||
|
|
||||||
|
blankline = term;
|
||||||
|
|
||||||
|
clientid = 'clientid' value @clientid;
|
||||||
|
background = 'background' value @background;
|
||||||
|
pidfile = 'pidfile' value @pidfile;
|
||||||
|
hostname = 'hostname' value @hostname;
|
||||||
|
interface = 'interface' value @interface;
|
||||||
|
now = 'now' boolval @now;
|
||||||
|
quit = 'quit' boolval @quit;
|
||||||
|
request = 'request' value @request;
|
||||||
|
vendorid = 'vendorid' value @vendorid;
|
||||||
|
user = 'user' value @user;
|
||||||
|
ifch_user = 'ifch-user' value @ifch_user;
|
||||||
|
sockd_user = 'sockd-user' value @sockd_user;
|
||||||
|
chroot = 'chroot' value @chroot;
|
||||||
|
state_dir = 'state-dir' value @state_dir;
|
||||||
|
seccomp_enforce = 'seccomp-enforce' boolval @seccomp_enforce;
|
||||||
|
relentless_defense = 'relentless-defense' boolval @relentless_defense;
|
||||||
|
arp_probe_wait = 'arp-probe-wait' value @arp_probe_wait;
|
||||||
|
arp_probe_num = 'arp-probe-num' value @arp_probe_num;
|
||||||
|
arp_probe_min = 'arp-probe-min' value @arp_probe_min;
|
||||||
|
arp_probe_max = 'arp-probe-max' value @arp_probe_max;
|
||||||
|
gw_metric = 'gw-metric' value @gw_metric;
|
||||||
|
resolv_conf = 'resolv-conf' value @resolv_conf;
|
||||||
|
dhcp_set_hostname = 'dhcp-set-hostname' boolval @dhcp_set_hostname;
|
||||||
|
|
||||||
|
main := blankline |
|
||||||
|
clientid | background | pidfile | hostname | interface | now | quit |
|
||||||
|
request | vendorid | user | ifch_user | sockd_user | chroot |
|
||||||
|
state_dir | seccomp_enforce | relentless_defense | arp_probe_wait |
|
||||||
|
arp_probe_num | arp_probe_min | arp_probe_max | gw_metric |
|
||||||
|
resolv_conf | dhcp_set_hostname
|
||||||
|
;
|
||||||
|
}%%
|
||||||
|
|
||||||
|
%% write data;
|
||||||
|
|
||||||
|
static void parse_cfgfile(const char *fname)
|
||||||
|
{
|
||||||
|
struct cfgparse ccfg;
|
||||||
|
memset(&ccfg, 0, sizeof ccfg);
|
||||||
|
FILE *f = fopen(fname, "r");
|
||||||
|
if (!f)
|
||||||
|
suicide("Unable to open config file '%s'.", fname);
|
||||||
|
char l[MAX_BUF];
|
||||||
|
size_t linenum = 0;
|
||||||
|
while (linenum++, fgets(l, sizeof l, f)) {
|
||||||
|
size_t llen = strlen(l);
|
||||||
|
const char *p = l;
|
||||||
|
const char *pe = l + llen;
|
||||||
|
%% write init;
|
||||||
|
%% write exec;
|
||||||
|
|
||||||
|
if (ccfg.cs == file_cfg_error)
|
||||||
|
suicide("error parsing config file line %zu: malformed", linenum);
|
||||||
|
if (ccfg.cs < file_cfg_first_final)
|
||||||
|
suicide("error parsing config file line %zu: incomplete", linenum);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
%%{
|
||||||
|
machine cmd_cfg;
|
||||||
|
access ccfg.;
|
||||||
|
include cfg_actions;
|
||||||
|
|
||||||
|
action cfgfile { parse_cfgfile(ccfg.buf); }
|
||||||
|
action tbv { ccfg.ternary = 1; }
|
||||||
|
|
||||||
|
string = [^\0]+ >clear $append %term;
|
||||||
|
argval = 0 string 0;
|
||||||
|
tbv = 0 % tbv;
|
||||||
|
|
||||||
|
cfgfile = ('-c'|'--config') argval @cfgfile;
|
||||||
|
clientid = ('-I'|'--clientid') argval @clientid;
|
||||||
|
background = ('-b'|'--background') tbv @background;
|
||||||
|
pidfile = ('-p'|'--pidfile') argval @pidfile;
|
||||||
|
hostname = ('-h'|'--hostname') argval @hostname;
|
||||||
|
interface = ('-i'|'--interface') argval @interface;
|
||||||
|
now = ('-n'|'--now') tbv @now;
|
||||||
|
quit = ('-q'|'--quit') tbv @quit;
|
||||||
|
request = ('-r'|'--request') argval @request;
|
||||||
|
vendorid = ('-V'|'--vendorid') argval @vendorid;
|
||||||
|
user = ('-u'|'--user') argval @user;
|
||||||
|
ifch_user = ('-U'|'--ifch-user') argval @ifch_user;
|
||||||
|
sockd_user = ('-D'|'--sockd-user') argval @sockd_user;
|
||||||
|
chroot = ('-C'|'--chroot') argval @chroot;
|
||||||
|
state_dir = ('-s'|'--state-dir') argval @state_dir;
|
||||||
|
seccomp_enforce = ('-S'|'--seccomp-enforce') tbv @seccomp_enforce;
|
||||||
|
relentless_defense = ('-d'|'--relentless-defense') tbv @relentless_defense;
|
||||||
|
arp_probe_wait = ('-w'|'--arp-probe-wait') argval @arp_probe_wait;
|
||||||
|
arp_probe_num = ('-W'|'--arp-probe-num') argval @arp_probe_num;
|
||||||
|
arp_probe_min = ('-m'|'--arp-probe-min') argval @arp_probe_min;
|
||||||
|
arp_probe_max = ('-M'|'--arp-probe-max') argval @arp_probe_max;
|
||||||
|
gw_metric = ('-t'|'--gw-metric') argval @gw_metric;
|
||||||
|
resolv_conf = ('-R'|'--resolv-conf') argval @resolv_conf;
|
||||||
|
dhcp_set_hostname = ('-H'|'--dhcp-set-hostname') tbv @dhcp_set_hostname;
|
||||||
|
version = ('-v'|'--version') 0 @version;
|
||||||
|
help = ('-?'|'--help') 0 @help;
|
||||||
|
|
||||||
|
main := (
|
||||||
|
cfgfile | clientid | background | pidfile | hostname | interface |
|
||||||
|
now | quit | request | vendorid | user | ifch_user | sockd_user |
|
||||||
|
chroot | state_dir | seccomp_enforce | relentless_defense |
|
||||||
|
arp_probe_wait | arp_probe_num | arp_probe_min | arp_probe_max |
|
||||||
|
gw_metric | resolv_conf | dhcp_set_hostname | version | help
|
||||||
|
)*;
|
||||||
|
}%%
|
||||||
|
|
||||||
|
%% write data;
|
||||||
|
|
||||||
|
void parse_cmdline(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char argb[8192];
|
||||||
|
size_t argbl = 0;
|
||||||
|
for (size_t i = 1; i < (size_t)argc; ++i) {
|
||||||
|
ssize_t snl;
|
||||||
|
if (i > 1)
|
||||||
|
snl = snprintf(argb + argbl, sizeof argb - argbl, "%c%s",
|
||||||
|
0, argv[i]);
|
||||||
|
else
|
||||||
|
snl = snprintf(argb + argbl, sizeof argb - argbl, "%s", argv[i]);
|
||||||
|
if (snl < 0 || (size_t)snl >= sizeof argb)
|
||||||
|
suicide("error parsing command line option: option too long");
|
||||||
|
argbl += snl;
|
||||||
|
}
|
||||||
|
struct cfgparse ccfg;
|
||||||
|
memset(&ccfg, 0, sizeof ccfg);
|
||||||
|
const char *p = argb;
|
||||||
|
const char *pe = argb + argbl + 1;
|
||||||
|
const char *eof = pe;
|
||||||
|
|
||||||
|
%% write init;
|
||||||
|
%% write exec;
|
||||||
|
|
||||||
|
if (ccfg.cs == cmd_cfg_error)
|
||||||
|
suicide("error parsing command line option: malformed");
|
||||||
|
if (ccfg.cs >= cmd_cfg_first_final)
|
||||||
|
return;
|
||||||
|
suicide("error parsing command line option: incomplete");
|
||||||
|
}
|
||||||
|
|
214
src/ndhc.c
214
src/ndhc.c
@ -32,7 +32,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <getopt.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@ -57,6 +56,7 @@
|
|||||||
|
|
||||||
#include "ndhc.h"
|
#include "ndhc.h"
|
||||||
#include "ndhc-defines.h"
|
#include "ndhc-defines.h"
|
||||||
|
#include "cfg.h"
|
||||||
#include "seccomp.h"
|
#include "seccomp.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
@ -94,13 +94,42 @@ struct client_config_t client_config = {
|
|||||||
.foreground = 1,
|
.foreground = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void show_usage(void)
|
void set_client_addr(const char *v) { cs.clientAddr = inet_addr(v); }
|
||||||
|
|
||||||
|
void print_version(void)
|
||||||
|
{
|
||||||
|
printf("ndhc %s, dhcp client.\n", NDHC_VERSION);
|
||||||
|
printf("Copyright (c) 2004-2014 Nicholas J. Kain\n"
|
||||||
|
"All rights reserved.\n\n"
|
||||||
|
"Redistribution and use in source and binary forms, with or without\n"
|
||||||
|
"modification, are permitted provided that the following conditions are met:\n\n"
|
||||||
|
"- Redistributions of source code must retain the above copyright notice,\n"
|
||||||
|
" this list of conditions and the following disclaimer.\n"
|
||||||
|
"- Redistributions in binary form must reproduce the above copyright notice,\n"
|
||||||
|
" this list of conditions and the following disclaimer in the documentation\n"
|
||||||
|
" and/or other materials provided with the distribution.\n\n"
|
||||||
|
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
|
||||||
|
"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
|
||||||
|
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
|
||||||
|
"ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n"
|
||||||
|
"LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
|
||||||
|
"CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
|
||||||
|
"SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
|
||||||
|
"INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
|
||||||
|
"CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
|
||||||
|
"ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
|
||||||
|
"POSSIBILITY OF SUCH DAMAGE.\n");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_usage(void)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
"ndhc " NDHC_VERSION ", dhcp client. Licensed under 2-clause BSD.\n"
|
"ndhc " NDHC_VERSION ", dhcp client. Licensed under 2-clause BSD.\n"
|
||||||
"Copyright (C) 2004-2014 Nicholas J. Kain\n"
|
"Copyright (C) 2004-2014 Nicholas J. Kain\n"
|
||||||
"Usage: ndhc [OPTIONS]\n\n"
|
"Usage: ndhc [OPTIONS]\n\n"
|
||||||
" -c, --clientid=CLIENTID Client identifier\n"
|
" -c, --config=FILE Path to ndhc configuration file\n"
|
||||||
|
" -I, --clientid=CLIENTID Client identifier\n"
|
||||||
" -h, --hostname=HOSTNAME Client hostname\n"
|
" -h, --hostname=HOSTNAME Client hostname\n"
|
||||||
" -V, --vendorid=VENDORID Client vendor identification string\n"
|
" -V, --vendorid=VENDORID Client vendor identification string\n"
|
||||||
" -b, --background Fork to background if lease cannot be\n"
|
" -b, --background Fork to background if lease cannot be\n"
|
||||||
@ -127,7 +156,7 @@ static void show_usage(void)
|
|||||||
" -M, --arp-probe-max Max ms to wait for ARP response\n"
|
" -M, --arp-probe-max Max ms to wait for ARP response\n"
|
||||||
" -t, --gw-metric Route metric for default gw (default: 0)\n"
|
" -t, --gw-metric Route metric for default gw (default: 0)\n"
|
||||||
" -R, --resolve-conf=FILE Path to resolv.conf or equivalent\n"
|
" -R, --resolve-conf=FILE Path to resolv.conf or equivalent\n"
|
||||||
" -H, --dhcp-hostname Allow DHCP to set machine hostname\n"
|
" -H, --dhcp-set-hostname Allow DHCP to set machine hostname\n"
|
||||||
" -v, --version Display version\n"
|
" -v, --version Display version\n"
|
||||||
);
|
);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
@ -205,7 +234,7 @@ static int is_string_hwaddr(char *str, size_t slen)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_clientid_string(char *str, size_t slen)
|
int get_clientid_string(char *str, size_t slen)
|
||||||
{
|
{
|
||||||
if (!slen)
|
if (!slen)
|
||||||
return -1;
|
return -1;
|
||||||
@ -333,9 +362,9 @@ jumpstart:
|
|||||||
char state_dir[PATH_MAX] = "/etc/ndhc";
|
char state_dir[PATH_MAX] = "/etc/ndhc";
|
||||||
char chroot_dir[PATH_MAX] = "";
|
char chroot_dir[PATH_MAX] = "";
|
||||||
char resolv_conf_d[PATH_MAX] = "";
|
char resolv_conf_d[PATH_MAX] = "";
|
||||||
static char pidfile[PATH_MAX] = PID_FILE_DEFAULT;
|
char pidfile[PATH_MAX] = PID_FILE_DEFAULT;
|
||||||
static uid_t ndhc_uid = 0;
|
uid_t ndhc_uid = 0;
|
||||||
static gid_t ndhc_gid = 0;
|
gid_t ndhc_gid = 0;
|
||||||
int ifchSock[2];
|
int ifchSock[2];
|
||||||
int ifchPipe[2];
|
int ifchPipe[2];
|
||||||
int sockdSock[2];
|
int sockdSock[2];
|
||||||
@ -432,176 +461,9 @@ void background(void)
|
|||||||
write_pid(pidfile);
|
write_pid(pidfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_program_options(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
static const struct option arg_options[] = {
|
|
||||||
{"clientid", required_argument, 0, 'c'},
|
|
||||||
{"background", no_argument, 0, 'b'},
|
|
||||||
{"pidfile", required_argument, 0, 'p'},
|
|
||||||
{"hostname", required_argument, 0, 'h'},
|
|
||||||
{"interface", required_argument, 0, 'i'},
|
|
||||||
{"now", no_argument, 0, 'n'},
|
|
||||||
{"quit", no_argument, 0, 'q'},
|
|
||||||
{"request", required_argument, 0, 'r'},
|
|
||||||
{"vendorid", required_argument, 0, 'V'},
|
|
||||||
{"user", required_argument, 0, 'u'},
|
|
||||||
{"ifch-user", required_argument, 0, 'U'},
|
|
||||||
{"sockd-user", required_argument, 0, 'D'},
|
|
||||||
{"chroot", required_argument, 0, 'C'},
|
|
||||||
{"state-dir", required_argument, 0, 's'},
|
|
||||||
{"seccomp-enforce", no_argument, 0, 'S'},
|
|
||||||
{"relentless-defense", no_argument, 0, 'd'},
|
|
||||||
{"arp-probe-wait", required_argument, 0, 'w'},
|
|
||||||
{"arp-probe-num", required_argument, 0, 'W'},
|
|
||||||
{"arp-probe-min", required_argument, 0, 'm'},
|
|
||||||
{"arp-probe-max", required_argument, 0, 'M'},
|
|
||||||
{"gw-metric", required_argument, 0, 't'},
|
|
||||||
{"resolv-conf", required_argument, 0, 'R'},
|
|
||||||
{"dhcp-set-hostname", no_argument, 0, 'H'},
|
|
||||||
{"version", no_argument, 0, 'v'},
|
|
||||||
{"help", no_argument, 0, '?'},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
int c;
|
|
||||||
c = getopt_long(argc, argv, "c:bp:P:h:i:nqr:V:u:U:D:C:s:Sdw:W:m:M:t:R:Hv?",
|
|
||||||
arg_options, NULL);
|
|
||||||
if (c < 0) break;
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
case 'c':
|
|
||||||
get_clientid_string(optarg, strlen(optarg));
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
client_config.background_if_no_lease = 1;
|
|
||||||
gflags_detach = 1;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
copy_cmdarg(pidfile, optarg, sizeof pidfile, "pidfile");
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
copy_cmdarg(client_config.hostname, optarg,
|
|
||||||
sizeof client_config.hostname, "hostname");
|
|
||||||
break;
|
|
||||||
case 'i':
|
|
||||||
copy_cmdarg(client_config.interface, optarg,
|
|
||||||
sizeof client_config.interface, "interface");
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
client_config.abort_if_no_lease = 1;
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
client_config.quit_after_lease = 1;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
cs.clientAddr = inet_addr(optarg);
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
if (nk_uidgidbyname(optarg, &ndhc_uid, &ndhc_gid))
|
|
||||||
suicide("invalid ndhc user '%s' specified", optarg);
|
|
||||||
break;
|
|
||||||
case 'U':
|
|
||||||
if (nk_uidgidbyname(optarg, &ifch_uid, &ifch_gid))
|
|
||||||
suicide("invalid ifch user '%s' specified", optarg);
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
if (nk_uidgidbyname(optarg, &sockd_uid, &sockd_gid))
|
|
||||||
suicide("invalid sockd user '%s' specified", optarg);
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
copy_cmdarg(chroot_dir, optarg, sizeof chroot_dir, "chroot");
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
copy_cmdarg(state_dir, optarg, sizeof state_dir, "state-dir");
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
seccomp_enforce = true;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
set_arp_relentless_def();
|
|
||||||
break;
|
|
||||||
case 'w':
|
|
||||||
case 'W': {
|
|
||||||
int t = atoi(optarg);
|
|
||||||
if (t < 0)
|
|
||||||
break;
|
|
||||||
if (c == 'w')
|
|
||||||
arp_probe_wait = t;
|
|
||||||
else
|
|
||||||
arp_probe_num = t;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'm':
|
|
||||||
case 'M': {
|
|
||||||
int t = atoi(optarg);
|
|
||||||
if (c == 'm')
|
|
||||||
arp_probe_min = t;
|
|
||||||
else
|
|
||||||
arp_probe_max = t;
|
|
||||||
if (arp_probe_min > arp_probe_max) {
|
|
||||||
t = arp_probe_max;
|
|
||||||
arp_probe_max = arp_probe_min;
|
|
||||||
arp_probe_min = t;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'v':
|
|
||||||
printf("ndhc %s, dhcp client.\n", NDHC_VERSION);
|
|
||||||
printf("Copyright (c) 2004-2014 Nicholas J. Kain\n"
|
|
||||||
"All rights reserved.\n\n"
|
|
||||||
"Redistribution and use in source and binary forms, with or without\n"
|
|
||||||
"modification, are permitted provided that the following conditions are met:\n\n"
|
|
||||||
"- Redistributions of source code must retain the above copyright notice,\n"
|
|
||||||
" this list of conditions and the following disclaimer.\n"
|
|
||||||
"- Redistributions in binary form must reproduce the above copyright notice,\n"
|
|
||||||
" this list of conditions and the following disclaimer in the documentation\n"
|
|
||||||
" and/or other materials provided with the distribution.\n\n"
|
|
||||||
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
|
|
||||||
"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
|
|
||||||
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
|
|
||||||
"ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n"
|
|
||||||
"LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
|
|
||||||
"CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
|
|
||||||
"SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
|
|
||||||
"INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
|
|
||||||
"CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
|
|
||||||
"ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
|
|
||||||
"POSSIBILITY OF SUCH DAMAGE.\n");
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
copy_cmdarg(client_config.vendor, optarg,
|
|
||||||
sizeof client_config.vendor, "vendorid");
|
|
||||||
break;
|
|
||||||
case 't': {
|
|
||||||
char *p;
|
|
||||||
long mt = strtol(optarg, &p, 10);
|
|
||||||
if (p == optarg)
|
|
||||||
suicide("gw-metric arg '%s' isn't a valid number", optarg);
|
|
||||||
if (mt > INT_MAX)
|
|
||||||
suicide("gw-metric arg '%s' is too large", optarg);
|
|
||||||
if (mt < 0)
|
|
||||||
mt = 0;
|
|
||||||
client_config.metric = (int)mt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'R':
|
|
||||||
copy_cmdarg(resolv_conf_d, optarg, sizeof resolv_conf_d,
|
|
||||||
"resolv-conf");
|
|
||||||
break;
|
|
||||||
case 'H':
|
|
||||||
allow_hostname = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
show_usage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
parse_program_options(argc, argv);
|
parse_cmdline(argc, argv);
|
||||||
|
|
||||||
nk_random_u32_init(&cs.rnd32_state);
|
nk_random_u32_init(&cs.rnd32_state);
|
||||||
|
|
||||||
|
@ -74,7 +74,14 @@ extern int sockdPipe[2];
|
|||||||
extern char state_dir[PATH_MAX];
|
extern char state_dir[PATH_MAX];
|
||||||
extern char chroot_dir[PATH_MAX];
|
extern char chroot_dir[PATH_MAX];
|
||||||
extern char resolv_conf_d[PATH_MAX];
|
extern char resolv_conf_d[PATH_MAX];
|
||||||
|
extern char pidfile[PATH_MAX];
|
||||||
|
extern uid_t ndhc_uid;
|
||||||
|
extern gid_t ndhc_gid;
|
||||||
|
|
||||||
|
void set_client_addr(const char *v);
|
||||||
|
void show_usage(void);
|
||||||
|
int get_clientid_string(char *str, size_t slen);
|
||||||
void background(void);
|
void background(void);
|
||||||
|
void print_version(void);
|
||||||
|
|
||||||
#endif /* NJK_NDHC_NDHC_H_ */
|
#endif /* NJK_NDHC_NDHC_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user