From 3fd6b24ace319b139ec3c4e3031a5f05d21e304e Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 15 Jun 2010 13:30:55 +0200 Subject: ipset 5 in an almost ready state - milestone Reworked protocol and internal interfaces, missing set types added, backward compatibility verified, lots of tests added (and thanks to the tests, bugs fixed), even the manpage is rewritten ;-). Countless changes everywhere... The missing bits before announcing ipset 5: - net namespace support - new iptables/ip6tables extension library - iptables/ip6tables match and target tests (backward/forward compatibility) - tests on catching syntax errors --- src/ui.c | 231 ++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 162 insertions(+), 69 deletions(-) (limited to 'src/ui.c') diff --git a/src/ui.c b/src/ui.c index bc01e61..d8face5 100644 --- a/src/ui.c +++ b/src/ui.c @@ -4,107 +4,155 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include /* assert */ +#include /* tolower */ +#include /* memcmp, str* */ + #include /* IPSET_CMD_* */ #include /* IPSET_*_ARG */ #include /* ipset_envopt_parse */ #include /* ipset_parse_family */ #include /* ipset_print_family */ +#include /* STREQ */ #include /* prototypes */ /* Commands and environment options */ const struct ipset_commands ipset_commands[] = { - [IPSET_CMD_CREATE - 1] = { - .name = { "create", "c", "-N", "--create", NULL }, + /* Order is important */ + + { /* c[reate], --create, n, -N */ + .cmd = IPSET_CMD_CREATE, + .name = { "create", "n" }, .has_arg = IPSET_MANDATORY_ARG2, .help = "SETNAME TYPENAME [type-specific-options]\n" " Create a new set", }, - [IPSET_CMD_DESTROY - 1] = { - .name = { "destroy", "x", "-X", "--destroy", NULL }, - .has_arg = IPSET_OPTIONAL_ARG, - .help = "[SETNAME]\n" - " Destroy a named set or all sets", - }, - [IPSET_CMD_FLUSH - 1] = { - .name = { "flush", "f", "-F", "--flush", NULL }, - .has_arg = IPSET_OPTIONAL_ARG, - .help = "[SETNAME]\n" - " Flush a named set or all sets", + { /* a[dd], --add, -A */ + .cmd = IPSET_CMD_ADD, + .name = { "add", NULL }, + .has_arg = IPSET_MANDATORY_ARG2, + .help = "SETNAME ENTRY\n" + " Add entry to the named set", }, - [IPSET_CMD_RENAME - 1] = { - .name = { "rename", "e", "-E", "--rename", NULL }, + { /* d[el], --del, -D */ + .cmd = IPSET_CMD_DEL, + .name = { "del", NULL }, .has_arg = IPSET_MANDATORY_ARG2, - .help = "FROM-SETNAME TO-SETNAME\n" - " Rename two sets", + .help = "SETNAME ENTRY\n" + " Delete entry from the named set", }, - [IPSET_CMD_SWAP - 1] = { - .name = { "swap", "w", "-W", "--swap", NULL }, + { /* t[est], --test, -T */ + .cmd = IPSET_CMD_TEST, + .name = { "test", NULL }, .has_arg = IPSET_MANDATORY_ARG2, - .help = "FROM-SETNAME TO-SETNAME\n" - " Swap the contect of two existing sets", + .help = "SETNAME ENTRY\n" + " Test entry in the named set", + }, + { /* des[troy], --destroy, x, -X */ + .cmd = IPSET_CMD_DESTROY, + .name = { "destroy", "x" }, + .has_arg = IPSET_OPTIONAL_ARG, + .help = "[SETNAME]\n" + " Destroy a named set or all sets", }, - [IPSET_CMD_LIST - 1] = { - .name = { "list", "l", "-L", "--list", NULL }, + { /* l[ist], --list, -L */ + .cmd = IPSET_CMD_LIST, + .name = { "list", NULL }, .has_arg = IPSET_OPTIONAL_ARG, .help = "[SETNAME]\n" " List the entries of a named set or all sets", }, - [IPSET_CMD_SAVE - 1] = { - .name = { "save", "s", "-S", "--save", NULL }, + { /* s[save], --save, -S */ + .cmd = IPSET_CMD_SAVE, + .name = { "save", NULL }, .has_arg = IPSET_OPTIONAL_ARG, .help = "[SETNAME]\n" " Save the named set or all sets to stdout", }, - [IPSET_CMD_ADD - 1] = { - .name = { "add", "a", "-A", "--add", NULL }, - .has_arg = IPSET_MANDATORY_ARG2, - .help = "SETNAME ENTRY\n" - " Add entry to a named set", + { /* r[estore], --restore, -R */ + .cmd = IPSET_CMD_RESTORE, + .name = { "restore", NULL }, + .has_arg = IPSET_NO_ARG, + .help = "\n" + " Restore a saved state", + }, + { /* f[lush], --flush, -F */ + .cmd = IPSET_CMD_FLUSH, + .name = { "flush", NULL }, + .has_arg = IPSET_OPTIONAL_ARG, + .help = "[SETNAME]\n" + " Flush a named set or all sets", }, - [IPSET_CMD_DEL - 1] = { - .name = { "del", "d", "-D", "--del", NULL }, + { /* ren[ame], --rename, e, -E */ + .cmd = IPSET_CMD_RENAME, + .name = { "rename", "e" }, .has_arg = IPSET_MANDATORY_ARG2, - .help = "SETNAME ENTRY\n" - " Delete entry from a named set", + .help = "FROM-SETNAME TO-SETNAME\n" + " Rename two sets", }, - [IPSET_CMD_TEST - 1] = { - .name = { "test", "t", "-T", "--test", NULL }, + { /* sw[ap], --swap, w, -W */ + .cmd = IPSET_CMD_SWAP, + .name = { "swap", "w" }, .has_arg = IPSET_MANDATORY_ARG2, - .help = "SETNAME ENTRY\n" - " Test if entry exists in the named set", + .help = "FROM-SETNAME TO-SETNAME\n" + " Swap the contect of two existing sets", }, - [IPSET_CMD_HELP - 1] = { - .name = { "help", "h", "-H", "-h", "--help", NULL }, + { /* h[elp, --help, -H */ + .cmd = IPSET_CMD_HELP, + .name = { "help", NULL }, .has_arg = IPSET_OPTIONAL_ARG, .help = "[TYPENAME]\n" " Print help, and settype specific help", }, - [IPSET_CMD_RESTORE - 1] = { - .name = { "restore", "r", "-R", "--restore", NULL }, + { /* v[ersion], --version, -V */ + .cmd = IPSET_CMD_VERSION, + .name = { "version", NULL }, .has_arg = IPSET_NO_ARG, .help = "\n" - " Restore a saved state", + " Print version information", }, - [IPSET_CMD_VERSION - 1] = { - .name = { "version", "v", "-V", "-v", "--version", NULL }, + { /* q[uit] */ + .cmd = IPSET_CMD_QUIT, + .name = { "quit", NULL }, .has_arg = IPSET_NO_ARG, .help = "\n" - " Print version information", + " Quit interactive mode", }, - [IPSET_CMD_MAX - 1] = { }, + { }, }; +/* Match a command: try to match as a prefix or letter-command */ +bool +ipset_match_cmd(const char *arg, const char * const name[]) +{ + size_t len; + + assert(arg); + assert(name && name[0]); + + /* Ignore (two) leading dashes */ + if (arg[0] == '-') + arg++; + if (arg[0] == '-') + arg++; + + len = strlen(arg); + + if (len > strlen(name[0]) || !len) + return false; + else if (memcmp(arg, name[0], len) == 0) + return true; + else if (len != 1) + return false; + else if (name[1] == NULL) + return tolower(arg[0]) == name[0][0]; + else + return tolower(arg[0]) == name[1][0]; +} + const struct ipset_envopts ipset_envopts[] = { - { .name = { "family", "--family", NULL }, - .has_arg = IPSET_MANDATORY_ARG, .flag = IPSET_OPT_FAMILY, - .parse = ipset_parse_family, .print = ipset_print_family, - .help = "inet|inet6\n" - " Specify family when creating a set\n" - " which supports multiple families.\n" - " The default family is INET.", - }, - { .name = { "-o", "--output", NULL }, + { .name = { "-o", "-output" }, .has_arg = IPSET_MANDATORY_ARG, .flag = IPSET_OPT_MAX, .parse = ipset_parse_output, .help = "plain|save|xml\n" @@ -112,25 +160,25 @@ const struct ipset_envopts ipset_envopts[] = { " Default value for \"list\" command is mode \"plain\"\n" " and for \"save\" command is mode \"save\".", }, - { .name = { "-s", "--sorted", NULL }, + { .name = { "-s", "-sorted" }, .parse = ipset_envopt_parse, .has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_SORTED, .help = "\n" " Print elements sorted (if supported by the set type).", }, - { .name = { "-q", "--quiet", NULL }, + { .name = { "-q", "-quiet" }, .parse = ipset_envopt_parse, .has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_QUIET, .help = "\n" " Suppress any notice or warning message.", }, - { .name = { "-r", "--resolve", NULL }, + { .name = { "-r", "-resolve" }, .parse = ipset_envopt_parse, .has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_RESOLVE, .help = "\n" " Try to resolve IP addresses in the output (slow!)", }, - { .name = { "-x", "--exist", NULL }, + { .name = { "-!", "-exist" }, .parse = ipset_envopt_parse, .has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_EXIST, .help = "\n" @@ -138,14 +186,59 @@ const struct ipset_envopts ipset_envopts[] = { " when adding already existing elements\n" " or when deleting non-existing elements.", }, - /* Aliases */ - { .name = { "-4", NULL }, - .has_arg = IPSET_NO_ARG, .flag = IPSET_OPT_FAMILY, - .parse = ipset_parse_family, - }, - { .name = { "-6", NULL }, - .has_arg = IPSET_NO_ARG, .flag = IPSET_OPT_FAMILY, - .parse = ipset_parse_family, - }, { }, }; + +/* Strict option matching */ +bool +ipset_match_option(const char *arg, const char * const name[]) +{ + assert(arg); + assert(name && name[0]); + + /* Skip two leading dashes */ + if (arg[0] == '-' && arg[1] == '-') + arg++, arg++; + + return STREQ(arg, name[0]) + || (name[1] != NULL && STREQ(arg, name[1])); +} + +/* Strict envopt matching */ +bool +ipset_match_envopt(const char *arg, const char * const name[]) +{ + assert(arg); + assert(name && name[0]); + + /* Skip one leading dash */ + if (arg[0] == '-' && arg[1] == '-') + arg++; + + return STREQ(arg, name[0]) + || (name[1] != NULL && STREQ(arg, name[1])); +} + +/** + * ipset_shift_argv - shift off an argument + * @arc: argument count + * @argv: array of argument strings + * @from: from where shift off an argument + * + * Shift off the argument at "from" from the array of + * arguments argv of size argc. + */ +void +ipset_shift_argv(int *argc, char *argv[], int from) +{ + int i; + + assert(*argc >= from + 1); + + for (i = from + 1; i <= *argc; i++) { + argv[i-1] = argv[i]; + } + (*argc)--; + return; +} + -- cgit v1.2.3