Parse config options with ragel and support a configuration file.
This commit is contained in:
		| @@ -5,6 +5,7 @@ cmake_minimum_required (VERSION 2.6) | ||||
| include_directories("${PROJECT_SOURCE_DIR}") | ||||
|  | ||||
| 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( | ||||
| @@ -15,8 +16,16 @@ add_custom_command( | ||||
|   COMMENT "Compiling Ragel state machine: ifchd-parse.rl" | ||||
|   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") | ||||
|  | ||||
| add_executable(ndhc ${RAGEL_IFCHD_PARSE} ${NDHC_SRCS}) | ||||
| add_executable(ndhc ${RAGEL_CFG_PARSE} ${RAGEL_IFCHD_PARSE} ${NDHC_SRCS}) | ||||
| target_link_libraries(ndhc ncmlib) | ||||
|   | ||||
| @@ -122,7 +122,7 @@ static struct arp_data garp = { | ||||
|     .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) | ||||
| { | ||||
|   | ||||
| @@ -28,6 +28,7 @@ | ||||
| #ifndef ARP_H_ | ||||
| #define ARP_H_ | ||||
|  | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <net/if_arp.h> | ||||
| #include "ndhc.h" | ||||
| @@ -57,7 +58,7 @@ extern int arp_probe_num; | ||||
| extern int arp_probe_min; | ||||
| 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_close_fd(struct client_state_t *cs); | ||||
| 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/file.h> | ||||
| #include <unistd.h> | ||||
| #include <getopt.h> | ||||
| #include <stdlib.h> | ||||
| #include <signal.h> | ||||
| #include <time.h> | ||||
| @@ -57,6 +56,7 @@ | ||||
|  | ||||
| #include "ndhc.h" | ||||
| #include "ndhc-defines.h" | ||||
| #include "cfg.h" | ||||
| #include "seccomp.h" | ||||
| #include "state.h" | ||||
| #include "options.h" | ||||
| @@ -94,13 +94,42 @@ struct client_config_t client_config = { | ||||
|     .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( | ||||
| "ndhc " NDHC_VERSION ", dhcp client.  Licensed under 2-clause BSD.\n" | ||||
| "Copyright (C) 2004-2014 Nicholas J. Kain\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" | ||||
| "  -V, --vendorid=VENDORID         Client vendor identification string\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" | ||||
| "  -t, --gw-metric                 Route metric for default gw (default: 0)\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" | ||||
|            ); | ||||
|     exit(EXIT_SUCCESS); | ||||
| @@ -205,7 +234,7 @@ static int is_string_hwaddr(char *str, size_t slen) | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int get_clientid_string(char *str, size_t slen) | ||||
| int get_clientid_string(char *str, size_t slen) | ||||
| { | ||||
|     if (!slen) | ||||
|         return -1; | ||||
| @@ -333,9 +362,9 @@ jumpstart: | ||||
| char state_dir[PATH_MAX] = "/etc/ndhc"; | ||||
| char chroot_dir[PATH_MAX] = ""; | ||||
| char resolv_conf_d[PATH_MAX] = ""; | ||||
| static char pidfile[PATH_MAX] = PID_FILE_DEFAULT; | ||||
| static uid_t ndhc_uid = 0; | ||||
| static gid_t ndhc_gid = 0; | ||||
| char pidfile[PATH_MAX] = PID_FILE_DEFAULT; | ||||
| uid_t ndhc_uid = 0; | ||||
| gid_t ndhc_gid = 0; | ||||
| int ifchSock[2]; | ||||
| int ifchPipe[2]; | ||||
| int sockdSock[2]; | ||||
| @@ -432,176 +461,9 @@ void background(void) | ||||
|         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[]) | ||||
| { | ||||
|     parse_program_options(argc, argv); | ||||
|     parse_cmdline(argc, argv); | ||||
|  | ||||
|     nk_random_u32_init(&cs.rnd32_state); | ||||
|  | ||||
|   | ||||
| @@ -74,7 +74,14 @@ extern int sockdPipe[2]; | ||||
| extern char state_dir[PATH_MAX]; | ||||
| extern char chroot_dir[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 print_version(void); | ||||
|  | ||||
| #endif /* NJK_NDHC_NDHC_H_ */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user