From a4632ef6d7073fd702e13596fb431e65daeb4b14 Mon Sep 17 00:00:00 2001 From: bol-van Date: Thu, 31 Oct 2024 17:55:26 +0300 Subject: [PATCH] nfqws,tpws: read config from a file --- nfq/helpers.c | 79 +++++++++++++++++++++++++++++++++++++++++--------- nfq/helpers.h | 6 +++- nfq/nfqws.c | 44 ++++++++++++++++++++++++++++ nfq/params.h | 3 ++ tpws/helpers.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ tpws/helpers.h | 5 ++++ tpws/params.h | 3 ++ tpws/tpws.c | 44 ++++++++++++++++++++++++++++ 8 files changed, 240 insertions(+), 14 deletions(-) diff --git a/nfq/helpers.c b/nfq/helpers.c index 7e5087c..9b563d0 100644 --- a/nfq/helpers.c +++ b/nfq/helpers.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "params.h" @@ -17,20 +19,9 @@ void rtrim(char *s) for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0'; } -void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit) +void replace_char(char *s, char from, char to) { - size_t k; - bool bcut = false; - if (size > limit) - { - size = limit; - bcut = true; - } - if (!size) return; - for (k = 0; k < size; k++) DLOG("%02X ", data[k]); - DLOG(bcut ? "... : " : ": "); - for (k = 0; k < size; k++) DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.'); - if (bcut) DLOG(" ..."); + for(;*s;s++) if (*s==from) *s=to; } char *strncasestr(const char *s, const char *find, size_t slen) @@ -54,6 +45,23 @@ char *strncasestr(const char *s, const char *find, size_t slen) return (char *)s; } +void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit) +{ + size_t k; + bool bcut = false; + if (size > limit) + { + size = limit; + bcut = true; + } + if (!size) return; + for (k = 0; k < size; k++) DLOG("%02X ", data[k]); + DLOG(bcut ? "... : " : ": "); + for (k = 0; k < size; k++) DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.'); + if (bcut) DLOG(" ..."); +} + + bool load_file(const char *filename, void *buffer, size_t *buffer_size) { FILE *F; @@ -497,3 +505,48 @@ bool parse_cidr6(char *s, struct cidr6 *cidr) if (p) *p=d; // restore char return b; } + + +void free_command_line(char **argv, int argc) +{ + int i; + if (argv) + { + for (i = 0; i < argc; i++) + if (argv[i]) free(argv[i]); + free(argv); + } +} + +char **split_command_line(const char *cmdline, int *argc) +{ + int i; + char **argv = NULL; + wordexp_t p; + + *argc=0; + + // Note! This expands shell variables. + if (!cmdline || wordexp(cmdline, &p, WRDE_NOCMD)) + return NULL; + + if (!(argv = malloc(p.we_wordc * sizeof(char *)))) + { + wordfree(&p); + return NULL; + } + + for (i = 0; i < p.we_wordc; i++) + { + if (!(argv[i] = strdup(p.we_wordv[i]))) + { + wordfree(&p); + free_command_line(argv,i); + return NULL; + } + } + *argc=i; + + wordfree(&p); + return argv; +} diff --git a/nfq/helpers.h b/nfq/helpers.h index 2bdc6f5..0f914dd 100644 --- a/nfq/helpers.h +++ b/nfq/helpers.h @@ -18,9 +18,10 @@ typedef union } sockaddr_in46; void rtrim(char *s); +void replace_char(char *s, char from, char to); +char *strncasestr(const char *s,const char *find, size_t slen); void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit); -char *strncasestr(const char *s,const char *find, size_t slen); bool load_file(const char *filename,void *buffer,size_t *buffer_size); bool load_file_nonempty(const char *filename,void *buffer,size_t *buffer_size); bool save_file(const char *filename, const void *buffer, size_t buffer_size); @@ -106,3 +107,6 @@ static inline const struct in6_addr *mask_from_preflen6(uint8_t preflen) { return ip6_mask+preflen; } + +void free_command_line(char **argv, int argc); +char **split_command_line(const char *cmdline, int *argc); diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 554282f..5c291c9 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -46,6 +46,8 @@ #define CTRACK_T_EST 300 #define CTRACK_T_UDP 60 +#define MAX_CONFIG_FILE_SIZE 16384 + struct params_s params; #ifdef __CYGWIN__ bool bQuit=false; @@ -550,8 +552,17 @@ static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale) +static void cleanup_args() +{ + free_command_line(params.argv,params.argc); + params.argv = NULL; + params.argc = 0; +} + static void cleanup_params(void) { + cleanup_args(); + ConntrackPoolDestroy(¶ms.conntrack); dp_list_destroy(¶ms.desync_profiles); @@ -842,6 +853,7 @@ static unsigned int hash_jen(const void *data,unsigned int len) static void exithelp(void) { printf( + " @\t\t\t\t\t; read file for options. must be the only argument. other options are ignored.\n\n" " --debug=0|1|syslog|@\n" #ifdef __linux__ " --qnum=\n" @@ -1036,6 +1048,34 @@ int main(int argc, char **argv) } #endif + if (argc>=2 && argv[1][0]=='@') + { + // config from a file + + char buf[MAX_CONFIG_FILE_SIZE]; + buf[0]='x'; // fake argv[0] + buf[1]=' '; + size_t bufsize=sizeof(buf)-3; + if (!load_file(argv[1]+1,buf+2,&bufsize)) + { + DLOG_ERR("could not load config file '%s'\n",argv[1]+1); + exit_clean(1); + } + buf[bufsize+2]=0; + // wordexp fails if it sees \t \n \r between args + replace_char(buf,'\n',' '); + replace_char(buf,'\r',' '); + replace_char(buf,'\t',' '); + params.argv = split_command_line(buf,¶ms.argc); + if (!params.argv) + { + DLOG_ERR("failed to split command line options from file '%s'\n",argv[1]+1); + exit_clean(1); + } + argv=params.argv; + argc=params.argc; + } + const struct option long_options[] = { {"debug",optional_argument,0,0}, // optidx=0 #ifdef __linux__ @@ -1782,6 +1822,10 @@ int main(int argc, char **argv) #endif } } + + // do not need args from file anymore + cleanup_args(); + argv=NULL; argc=0; #ifdef __linux__ if (params.qnum<0) diff --git a/nfq/params.h b/nfq/params.h index e6ff5a6..1203455 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -95,6 +95,9 @@ bool dp_list_have_autohostlist(struct desync_profile_list_head *head); struct params_s { + char **argv; // for file based config + int argc; + enum log_target debug_target; char debug_logfile[PATH_MAX]; bool debug; diff --git a/tpws/helpers.c b/tpws/helpers.c index 0a11ff1..7423009 100644 --- a/tpws/helpers.c +++ b/tpws/helpers.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include void rtrim(char *s) { @@ -17,6 +19,11 @@ void rtrim(char *s) for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0'; } +void replace_char(char *s, char from, char to) +{ + for(;*s;s++) if (*s==from) *s=to; +} + char *strncasestr(const char *s,const char *find, size_t slen) { char c, sc; @@ -38,6 +45,24 @@ char *strncasestr(const char *s,const char *find, size_t slen) return (char *)s; } +bool load_file(const char *filename, void *buffer, size_t *buffer_size) +{ + FILE *F; + + F = fopen(filename, "rb"); + if (!F) return false; + + *buffer_size = fread(buffer, 1, *buffer_size, F); + if (ferror(F)) + { + fclose(F); + return false; + } + + fclose(F); + return true; +} + bool append_to_list_file(const char *filename, const char *s) { FILE *F = fopen(filename,"at"); @@ -395,3 +420,48 @@ bool parse_cidr6(char *s, struct cidr6 *cidr) if (p) *p=d; // restore char return b; } + + +void free_command_line(char **argv, int argc) +{ + int i; + if (argv) + { + for (i = 0; i < argc; i++) + if (argv[i]) free(argv[i]); + free(argv); + } +} + +char **split_command_line(const char *cmdline, int *argc) +{ + int i; + char **argv = NULL; + wordexp_t p; + + *argc=0; + + // Note! This expands shell variables. + if (!cmdline || wordexp(cmdline, &p, WRDE_NOCMD)) + return NULL; + + if (!(argv = malloc(p.we_wordc * sizeof(char *)))) + { + wordfree(&p); + return NULL; + } + + for (i = 0; i < p.we_wordc; i++) + { + if (!(argv[i] = strdup(p.we_wordv[i]))) + { + wordfree(&p); + free_command_line(argv,i); + return NULL; + } + } + *argc=i; + + wordfree(&p); + return argv; +} diff --git a/tpws/helpers.h b/tpws/helpers.h index 4279e35..39476b7 100644 --- a/tpws/helpers.h +++ b/tpws/helpers.h @@ -16,8 +16,10 @@ typedef union } sockaddr_in46; void rtrim(char *s); +void replace_char(char *s, char from, char to); char *strncasestr(const char *s,const char *find, size_t slen); +bool load_file(const char *filename,void *buffer,size_t *buffer_size); bool append_to_list_file(const char *filename, const char *s); void ntop46(const struct sockaddr *sa, char *str, size_t len); @@ -110,3 +112,6 @@ static inline const struct in6_addr *mask_from_preflen6(uint8_t preflen) { return ip6_mask+preflen; } + +void free_command_line(char **argv, int argc); +char **split_command_line(const char *cmdline, int *argc); diff --git a/tpws/params.h b/tpws/params.h index 4f30854..fedace7 100644 --- a/tpws/params.h +++ b/tpws/params.h @@ -79,6 +79,9 @@ void dp_list_destroy(struct desync_profile_list_head *head); struct params_s { + char **argv; // for file based config + int argc; + int debug; enum log_target debug_target; char debug_logfile[PATH_MAX]; diff --git a/tpws/tpws.c b/tpws/tpws.c index ca45c27..e36199a 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -41,6 +41,9 @@ #include "gzip.h" #include "pools.h" + +#define MAX_CONFIG_FILE_SIZE 16384 + struct params_s params; static void onhup(int sig) @@ -119,6 +122,7 @@ static int get_default_ttl(void) static void exithelp(void) { printf( + " @\t\t\t\t; read file for options. must be the only argument. other options are ignored.\n\n" " --bind-addr=|\t; for v6 link locals append %%interface_name\n" " --bind-iface4=\t\t; bind to the first ipv4 addr of interface\n" " --bind-iface6=\t\t; bind to the first ipv6 addr of interface\n" @@ -211,8 +215,16 @@ static void exithelp(void) ); exit(1); } +static void cleanup_args() +{ + free_command_line(params.argv,params.argc); + params.argv = NULL; + params.argc = 0; +} static void cleanup_params(void) { + cleanup_args(); + dp_list_destroy(¶ms.desync_profiles); hostlist_files_destroy(¶ms.hostlists); @@ -392,6 +404,34 @@ void parse_params(int argc, char *argv[]) } dp = &dpl->dp; dp->n = ++desync_profile_count; + + if (argc>=2 && argv[1][0]=='@') + { + // config from a file + + char buf[MAX_CONFIG_FILE_SIZE]; + buf[0]='x'; // fake argv[0] + buf[1]=' '; + size_t bufsize=sizeof(buf)-3; + if (!load_file(argv[1]+1,buf+2,&bufsize)) + { + DLOG_ERR("could not load config file '%s'\n",argv[1]+1); + exit_clean(1); + } + buf[bufsize+2]=0; + // wordexp fails if it sees \t \n \r between args + replace_char(buf,'\n',' '); + replace_char(buf,'\r',' '); + replace_char(buf,'\t',' '); + params.argv = split_command_line(buf,¶ms.argc); + if (!params.argv) + { + DLOG_ERR("failed to split command line options from file '%s'\n",argv[1]+1); + exit_clean(1); + } + argv=params.argv; + argc=params.argc; + } const struct option long_options[] = { { "help",no_argument,0,0 },// optidx=0 @@ -1091,6 +1131,9 @@ void parse_params(int argc, char *argv[]) HostlistsDebug(); IpsetsDebug(); VPRINT("\n"); + + // do not need args from file anymore + cleanup_args(); } @@ -1250,6 +1293,7 @@ int main(int argc, char *argv[]) mask_from_preflen6_prepare(); parse_params(argc, argv); + argv=NULL; argc=0; if (params.daemon) daemonize();