summaryrefslogtreecommitdiffstats
path: root/src/ipset.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipset.c')
-rw-r--r--src/ipset.c2398
1 files changed, 465 insertions, 1933 deletions
diff --git a/src/ipset.c b/src/ipset.c
index 3b8e248..d29042d 100644
--- a/src/ipset.c
+++ b/src/ipset.c
@@ -1,2054 +1,586 @@
/* Copyright 2000-2002 Joakim Axelsson (gozem@linux.nu)
* Patrick Schaaf (bof@bof.de)
- * Copyright 2003-2004 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
+ * Copyright 2003-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
-#include <stdio.h> /* *printf, perror, sscanf, fdopen */
-#include <string.h> /* mem*, str* */
-#include <errno.h> /* errno, perror */
-#include <time.h> /* time, ctime */
-#include <netdb.h> /* gethostby*, getnetby*, getservby* */
-#include <stdlib.h> /* exit, malloc, free, strtol, getenv, mkstemp */
-#include <unistd.h> /* read, close, fork, exec*, unlink */
-#include <sys/types.h> /* open, wait, socket, *sockopt, umask */
-#include <sys/stat.h> /* open, umask */
-#include <sys/wait.h> /* wait */
-#include <sys/socket.h> /* socket, *sockopt, gethostby*, inet_* */
-#include <netinet/in.h> /* inet_* */
-#include <fcntl.h> /* open */
-#include <arpa/inet.h> /* htonl, inet_* */
+#include <ctype.h> /* isspace */
#include <stdarg.h> /* va_* */
-#include <dlfcn.h> /* dlopen */
-
-#include "ipset.h"
-
-#ifndef PROC_SYS_MODPROBE
-#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
-#endif
-
-char program_name[] = "ipset";
-char program_version[] = IPSET_VERSION;
-static int protocol_version = 0;
-
-#define STREQ(a,b) (strncmp(a,b,IP_SET_MAXNAMELEN) == 0)
-#define DONT_ALIGN (protocol_version == IP_SET_PROTOCOL_UNALIGNED)
-#define ALIGNED(len) IPSET_VALIGN(len, DONT_ALIGN)
-
-/* The list of loaded set types */
-static struct settype *all_settypes = NULL;
-
-/* Array of sets */
-struct set **set_list = NULL;
-ip_set_id_t max_sets = 0;
-
-/* Suppress output to stdout and stderr? */
-static int option_quiet = 0;
-
-/* Data for restore mode */
-static int restore = 0;
-void *restore_data = NULL;
-struct ip_set_restore *restore_set = NULL;
-size_t restore_offset = 0;
-socklen_t restore_size;
-unsigned restore_line = 0;
-unsigned warn_once = 0;
-
-#define TEMPFILE_PATTERN "/ipsetXXXXXX"
-
-#ifdef IPSET_DEBUG
-int option_debug = 0;
-#endif
-
-#define OPTION_OFFSET 256
-static unsigned int global_option_offset = 0;
-
-/* Most of these command parsing functions are borrowed from iptables.c */
-
-static const char cmdflags[] = { ' ', /* CMD_NONE */
- 'N', 'X', 'F', 'E', 'W', 'L', 'S', 'R',
- 'A', 'D', 'T', 'H', 'V',
-};
-
-/* Options */
-#define OPT_NONE 0x0000U
-#define OPT_NUMERIC 0x0001U /* -n */
-#define OPT_SORTED 0x0002U /* -s */
-#define OPT_QUIET 0x0004U /* -q */
-#define OPT_DEBUG 0x0008U /* -z */
-#define OPT_RESOLVE 0x0020U /* -r */
-#define NUMBER_OF_OPT 5
-static const char optflags[] =
- { 'n', 's', 'q', 'z', 'r' };
-
-static struct option opts_long[] = {
- /* set operations */
- {"create", 1, 0, 'N'},
- {"destroy", 2, 0, 'X'},
- {"flush", 2, 0, 'F'},
- {"rename", 1, 0, 'E'},
- {"swap", 1, 0, 'W'},
- {"list", 2, 0, 'L'},
-
- {"save", 2, 0, 'S'},
- {"restore", 0, 0, 'R'},
-
- /* ip in set operations */
- {"add", 1, 0, 'A'},
- {"del", 1, 0, 'D'},
- {"test", 1, 0, 'T'},
-
- /* free options */
- {"numeric", 0, 0, 'n'},
- {"sorted", 0, 0, 's'},
- {"quiet", 0, 0, 'q'},
- {"resolve", 0, 0, 'r'},
-
-#ifdef IPSET_DEBUG
- /* debug (if compiled with it) */
- {"debug", 0, 0, 'z'},
-#endif
-
- /* version and help */
- {"version", 0, 0, 'V'},
- {"help", 2, 0, 'H'},
-
- /* end */
- {NULL},
-};
-
-static char opts_short[] =
- "-N:X::F::E:W:L::S::RA:D:T:nrsqzvVh::H::";
-
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal.
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
+#include <stdbool.h> /* bool */
+#include <stdio.h> /* fprintf, fgets */
+#include <stdlib.h> /* exit */
+#include <string.h> /* str* */
+
+#include <config.h>
+
+#include <libipset/parse.h> /* ipset_parse_* */
+#include <libipset/session.h> /* ipset_session_* */
+#include <libipset/types.h> /* struct ipset_type */
+#include <libipset/ui.h> /* core options, commands */
+#include <libipset/utils.h> /* ipset_name_match */
+
+static char program_name[] = PACKAGE;
+static char program_version[] = PACKAGE_VERSION;
+
+static struct ipset_session *session = NULL;
+static uint32_t restore_line = 0;
+static bool interactive = false;
+static char cmdline[1024];
+static char *newargv[255];
+static int newargc = 0;
-static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = {
- /* -n -s -q -z -r */
- /*CREATE*/ {'x', 'x', ' ', ' ', 'x'},
- /*DESTROY*/ {'x', 'x', ' ', ' ', 'x'},
- /*FLUSH*/ {'x', 'x', ' ', ' ', 'x'},
- /*RENAME*/ {'x', 'x', ' ', ' ', 'x'},
- /*SWAP*/ {'x', 'x', ' ', ' ', 'x'},
- /*LIST*/ {' ', ' ', 'x', ' ', ' '},
- /*SAVE*/ {'x', 'x', ' ', ' ', 'x'},
- /*RESTORE*/ {'x', 'x', ' ', ' ', 'x'},
- /*ADD*/ {'x', 'x', ' ', ' ', 'x'},
- /*DEL*/ {'x', 'x', ' ', ' ', 'x'},
- /*TEST*/ {'x', 'x', ' ', ' ', 'x'},
- /*HELP*/ {'x', 'x', 'x', ' ', 'x'},
- /*VERSION*/ {'x', 'x', 'x', ' ', 'x'},
+enum exittype {
+ NO_PROBLEM = 0,
+ OTHER_PROBLEM,
+ PARAMETER_PROBLEM,
+ VERSION_PROBLEM,
};
-/* Main parser function */
-int parse_commandline(int argc, char *argv[]);
-
-static void exit_tryhelp(int status)
+static void __attribute__((format(printf,2,3)))
+exit_error(int status, const char *msg, ...)
{
- fprintf(stderr,
- "Try `%s -H' or '%s --help' for more information.\n",
- program_name, program_name);
- exit(status);
-}
+ bool quiet = !interactive
+ && session
+ && ipset_envopt_test(session, IPSET_ENV_QUIET);
-void exit_error(int status, const char *msg, ...)
-{
- if (!option_quiet) {
+ if (status && msg && !quiet) {
va_list args;
- va_start(args, msg);
fprintf(stderr, "%s v%s: ", program_name, program_version);
+ va_start(args, msg);
vfprintf(stderr, msg, args);
va_end(args);
fprintf(stderr, "\n");
- if (restore_line)
- fprintf(stderr, "Restore failed at line %u:\n", restore_line);
+
if (status == PARAMETER_PROBLEM)
- exit_tryhelp(status);
- if (status == VERSION_PROBLEM)
fprintf(stderr,
- "Perhaps %s or your kernel needs to be upgraded.\n",
+ "Try `%s help' for more information.\n",
program_name);
}
-
- exit(status);
-}
-
-static void ipset_printf(const char *msg, ...)
-{
- if (!option_quiet) {
- va_list args;
-
- va_start(args, msg);
- vfprintf(stdout, msg, args);
- va_end(args);
- fprintf(stdout, "\n");
- }
-}
-
-static void generic_opt_check(int command, unsigned int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 1; j <= NUMBER_OF_CMD; j++) {
- if (command != j)
- continue;
-
- if (!(options & (1 << i))) {
- if (commands_v_options[j-1][i] == '+')
- exit_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j-1][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- exit_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char opt2char(unsigned int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
-static char cmd2char(int cmd)
-{
- if (cmd <= CMD_NONE || cmd > NUMBER_OF_CMD)
- return ' ';
-
- return cmdflags[cmd];
-}
-
-/* From iptables.c ... */
-static char *get_modprobe(void)
-{
- int procfile;
- char *ret;
-
-#define PROCFILE_BUFSIZ 1024
- procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
- if (procfile < 0)
- return NULL;
-
- ret = (char *) malloc(PROCFILE_BUFSIZ);
- if (ret) {
- memset(ret, 0, PROCFILE_BUFSIZ);
- switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
- case -1: goto fail;
- case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */
- default: ; /* nothing */
- }
- if (ret[strlen(ret)-1]=='\n')
- ret[strlen(ret)-1]=0;
- close(procfile);
- return ret;
- }
- fail:
- free(ret);
- close(procfile);
- return NULL;
-}
-
-static int ipset_insmod(const char *modname, const char *modprobe)
-{
- char *buf = NULL;
- char *argv[3];
- struct stat junk;
- int status;
-
- if (!stat(modprobe, &junk)) {
- /* Try to read out of the kernel */
- buf = get_modprobe();
- if (!buf)
- return -1;
- modprobe = buf;
- }
-
- switch (fork()) {
- case 0:
- argv[0] = (char *) modprobe;
- argv[1] = (char *) modname;
- argv[2] = NULL;
- execv(argv[0], argv);
-
- /* Should not reach */
- exit(1);
- case -1:
- return -1;
-
- default: /* parent */
- wait(&status);
- }
-
- free(buf);
-
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
- return 0;
- return -1;
-}
-
-static int kernel_getsocket(void)
-{
- int sockfd = -1;
-
- sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
- if (sockfd < 0)
- exit_error(OTHER_PROBLEM,
- "You need to be root to perform this command.");
-
- return sockfd;
-}
-
-static void kernel_error(unsigned cmd, int err)
-{
- unsigned int i;
- struct translate_error {
- int err;
- unsigned cmd;
- const char *message;
- } table[] =
- { /* Generic error codes */
- { EPERM, 0, "Missing capability" },
- { EBADF, 0, "Invalid socket option" },
- { EINVAL, 0, "Size mismatch for expected socket data" },
- { ENOMEM, 0, "Not enough memory" },
- { EFAULT, 0, "Failed to copy data" },
- { EPROTO, 0, "ipset kernel/userspace version mismatch" },
- { EBADMSG, 0, "Unknown command" },
- /* Per command error codes */
- /* Reserved ones for add/del/test to handle internally:
- * EEXIST
- */
- { ENOENT, CMD_CREATE, "Unknown set type" },
- { ENOENT, 0, "Unknown set" },
- { EAGAIN, 0, "Sets are busy, try again later" },
- { ERANGE, CMD_CREATE, "No free slot remained to add a new set" },
- { ERANGE, 0, "IP/port/element is outside of the set or set is full" },
- { ENOEXEC, CMD_CREATE, "Invalid parameters to create a set" },
- { ENOEXEC, CMD_SWAP, "Sets with different types cannot be swapped" },
- { EEXIST, CMD_CREATE, "Set already exists" },
- { EEXIST, CMD_RENAME, "Set with new name already exists" },
- { EEXIST, 0, "Set specified as element does not exist" },
- { EBUSY, 0, "Set is in use, operation not permitted" },
- };
- for (i = 0; i < sizeof(table)/sizeof(struct translate_error); i++) {
- if ((table[i].cmd == cmd || table[i].cmd == 0)
- && table[i].err == err)
- exit_error(err == EPROTO ? VERSION_PROBLEM
- : OTHER_PROBLEM,
- table[i].message);
- }
- exit_error(OTHER_PROBLEM, "Error from kernel: %s", strerror(err));
-}
-
-static inline int wrapped_getsockopt(void *data, socklen_t *size)
-{
- int res;
- int sockfd = kernel_getsocket();
-
- /* Send! */
- res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
- if (res != 0
- && errno == ENOPROTOOPT
- && ipset_insmod("ip_set", "/sbin/modprobe") == 0)
- res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
- DP("res=%d errno=%d", res, errno);
-
- return res;
-}
-
-static inline int wrapped_setsockopt(void *data, socklen_t size)
-{
- int res;
- int sockfd = kernel_getsocket();
-
- /* Send! */
- res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
- if (res != 0
- && errno == ENOPROTOOPT
- && ipset_insmod("ip_set", "/sbin/modprobe") == 0)
- res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
- DP("res=%d errno=%d", res, errno);
-
- return res;
-}
-
-static void kernel_getfrom(unsigned cmd, void *data, socklen_t * size)
-{
- int res = wrapped_getsockopt(data, size);
-
- if (res != 0)
- kernel_error(cmd, errno);
-}
-
-static int kernel_sendto_handleerrno(unsigned cmd,
- void *data, socklen_t size)
-{
- int res = wrapped_setsockopt(data, size);
-
- if (res != 0) {
- if (errno == EEXIST)
- return -1;
- else
- kernel_error(cmd, errno);
- }
-
- return 0; /* all ok */
-}
-
-static void kernel_sendto(unsigned cmd, void *data, size_t size)
-{
- int res = wrapped_setsockopt(data, size);
-
- if (res != 0)
- kernel_error(cmd, errno);
-}
-
-static int kernel_getfrom_handleerrno(unsigned cmd, void *data, socklen_t *size)
-{
- int res = wrapped_getsockopt(data, size);
-
- if (res != 0) {
- if (errno == EAGAIN)
- return -1;
- else
- kernel_error(cmd, errno);
- }
-
- return 0; /* all ok */
-}
-
-static void check_protocolversion(void)
-{
- struct ip_set_req_version req_version;
- socklen_t size = sizeof(struct ip_set_req_version);
- int res;
-
- if (protocol_version)
- return;
-
- req_version.op = IP_SET_OP_VERSION;
- res = wrapped_getsockopt(&req_version, &size);
-
- if (res != 0)
- exit_error(OTHER_PROBLEM,
- "Couldn't verify kernel module version!");
-
- if (!(req_version.version == IP_SET_PROTOCOL_VERSION
- || req_version.version == IP_SET_PROTOCOL_UNALIGNED))
- exit_error(OTHER_PROBLEM,
- "Kernel ip_set module is of protocol version %u."
- "I'm of protocol version %u.\n"
- "Please upgrade your kernel and/or ipset(8) utillity.",
- req_version.version, IP_SET_PROTOCOL_VERSION);
- protocol_version = req_version.version;
-}
-
-static void set_command(int *cmd, int newcmd)
-{
- if (*cmd != CMD_NONE)
- exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n",
- cmd2char(*cmd), cmd2char(newcmd));
- *cmd = newcmd;
-}
-
-static void add_option(unsigned int *options, unsigned int option)
-{
- if (*options & option)
- exit_error(PARAMETER_PROBLEM,
- "multiple -%c flags not allowed",
- opt2char(option));
- *options |= option;
-}
-
-void *ipset_malloc(size_t size)
-{
- void *p;
-
- if (size == 0)
- return NULL;
-
- if ((p = malloc(size)) == NULL) {
- perror("ipset: not enough memory");
- exit(1);
- }
- return p;
-}
-
-char *ipset_strdup(const char *s)
-{
- char *p;
-
- if ((p = strdup(s)) == NULL) {
- perror("ipset: not enough memory");
- exit(1);
- }
- return p;
-}
-
-void ipset_free(void *data)
-{
- if (data == NULL)
+ /* Ignore errors in interactive mode */
+ if (status && interactive) {
+ if (session)
+ ipset_session_report_reset(session);
return;
-
- free(data);
-}
-
-static struct option *merge_options(struct option *oldopts,
- const struct option *newopts,
- int *option_offset)
-{
- unsigned int num_old, num_new, i;
- struct option *merge;
-
- for (num_old = 0; oldopts[num_old].name; num_old++);
- for (num_new = 0; newopts[num_new].name; num_new++);
-
- global_option_offset += OPTION_OFFSET;
- *option_offset = global_option_offset;
-
- merge = ipset_malloc(sizeof(struct option) * (num_new + num_old + 1));
- memcpy(merge, oldopts, num_old * sizeof(struct option));
- for (i = 0; i < num_new; i++) {
- merge[num_old + i] = newopts[i];
- merge[num_old + i].val += *option_offset;
- }
- memset(merge + num_old + num_new, 0, sizeof(struct option));
-
- return merge;
-}
-
-static char *ip_tohost(const struct in_addr *addr)
-{
- struct hostent *host;
-
- if ((host = gethostbyaddr((char *) addr,
- sizeof(struct in_addr),
- AF_INET)) != NULL) {
- DP("%s", host->h_name);
- return (char *) host->h_name;
- }
-
- return (char *) NULL;
-}
-
-static char *ip_tonetwork(const struct in_addr *addr)
-{
- struct netent *net;
-
- if ((net = getnetbyaddr(ntohl(addr->s_addr),
- AF_INET)) != NULL) {
- DP("%s", net->n_name);
- return (char *) net->n_name;
- }
-
- return (char *) NULL;
-}
-
-/* Return a string representation of an IP address.
- * Please notice that a pointer to static char* area is returned.
- */
-char *ip_tostring(ip_set_ip_t ip, unsigned options)
-{
- struct in_addr addr;
- addr.s_addr = htonl(ip);
-
- if (!(options & OPT_NUMERIC)) {
- char *name;
- if ((name = ip_tohost(&addr)) != NULL ||
- (name = ip_tonetwork(&addr)) != NULL)
- return name;
- }
-
- return inet_ntoa(addr);
-}
-
-char *ip_tostring_numeric(ip_set_ip_t ip)
-{
- return ip_tostring(ip, OPT_NUMERIC);
-}
-
-/* Fills the 'ip' with the parsed ip or host in host byte order */
-void parse_ip(const char *str, ip_set_ip_t * ip)
-{
- struct hostent *host;
- struct in_addr addr;
-
- DP("%s", str);
-
- if (inet_aton(str, &addr) != 0) {
- *ip = ntohl(addr.s_addr); /* We want host byte order */
- return;
- }
-
- host = gethostbyname(str);
- if (host != NULL) {
- if (host->h_addrtype != AF_INET ||
- host->h_length != sizeof(struct in_addr))
- exit_error(PARAMETER_PROBLEM,
- "host/network `%s' not an internet name",
- str);
- if (host->h_addr_list[1] != 0)
- exit_error(PARAMETER_PROBLEM,
- "host/network `%s' resolves to serveral ip-addresses. "
- "Please specify one.", str);
-
- memcpy(&addr, host->h_addr_list[0], sizeof(struct in_addr));
- *ip = ntohl(addr.s_addr);
- return;
- }
-
- exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", str);
-}
-
-/* Fills 'mask' with the parsed mask in host byte order */
-void parse_mask(const char *str, ip_set_ip_t * mask)
-{
- struct in_addr addr;
- int bits;
-
- DP("%s", str);
-
- if (str == NULL) {
- /* no mask at all defaults to 32 bits */
- *mask = 0xFFFFFFFF;
- return;
- }
- if (strchr(str, '.') && inet_aton(str, &addr) != 0) {
- *mask = ntohl(addr.s_addr); /* We want host byte order */
- return;
- }
- if (sscanf(str, "%d", &bits) != 1 || bits < 0 || bits > 32)
- exit_error(PARAMETER_PROBLEM,
- "invalid mask `%s' specified", str);
-
- DP("bits: %d", bits);
-
- *mask = bits != 0 ? 0xFFFFFFFF << (32 - bits) : 0L;
-}
-
-/* Combines parse_ip and parse_mask */
-void
-parse_ipandmask(const char *str, ip_set_ip_t * ip, ip_set_ip_t * mask)
-{
- char buf[256];
- char *p;
-
- strncpy(buf, str, sizeof(buf) - 1);
- buf[255] = '\0';
-
- if ((p = strrchr(buf, '/')) != NULL) {
- *p = '\0';
- parse_mask(p + 1, mask);
- } else
- parse_mask(NULL, mask);
-
- /* if a null mask is given, the name is ignored, like in "any/0" */
- if (*mask == 0U)
- *ip = 0U;
- else
- parse_ip(buf, ip);
-
- DP("%s ip: %08X (%s) mask: %08X",
- str, *ip, ip_tostring_numeric(*ip), *mask);
-
- /* Apply the netmask */
- *ip &= *mask;
-
- DP("%s ip: %08X (%s) mask: %08X",
- str, *ip, ip_tostring_numeric(*ip), *mask);
-}
-
-/* Return a string representation of a port
- * Please notice that a pointer to static char* area is returned
- * and we assume TCP protocol.
- */
-char *port_tostring(ip_set_ip_t port, unsigned options)
-{
- struct servent *service;
- static char name[] = "65535";
-
- if (!(options & OPT_NUMERIC)) {
- if ((service = getservbyport(htons(port), "tcp")))
- return service->s_name;
}
- sprintf(name, "%u", port);
- return name;
-}
-int
-string_to_number(const char *str, unsigned int min, unsigned int max,
- ip_set_ip_t *port)
-{
- unsigned long number;
- char *end;
+ if (session)
+ ipset_session_fini(session);
- /* Handle hex, octal, etc. */
- errno = 0;
- number = strtoul(str, &end, 0);
- if (*end == '\0' && end != str) {
- /* we parsed a number, let's see if we want this */
- if (errno != ERANGE && min <= number && number <= max) {
- *port = number;
- return 0;
- }
- }
- return -1;
+ D("status: %u", status);
+ exit(status);
}
static int
-string_to_port(const char *str, ip_set_ip_t *port)
-{
- struct servent *service;
-
- if ((service = getservbyname(str, "tcp")) != NULL) {
- *port = ntohs((uint16_t) service->s_port);
- return 0;
- }
- return -1;
-}
-
-/* Fills the 'ip' with the parsed port in host byte order */
-void parse_port(const char *str, ip_set_ip_t *port)
-{
- if ((string_to_number(str, 0, 65535, port) != 0)
- && (string_to_port(str, port) != 0))
- exit_error(PARAMETER_PROBLEM,
- "Invalid TCP port `%s' specified", str);
-}
-
-/*
- * Settype functions
- */
-static struct settype *settype_find(const char *typename)
+handle_error(void)
{
- struct settype *runner = all_settypes;
-
- DP("%s", typename);
+ if (ipset_session_warning(session)
+ && !ipset_envopt_test(session, IPSET_ENV_QUIET))
+ fprintf(stderr, "Warning: %s\n",
+ ipset_session_warning(session));
+ if (ipset_session_error(session))
+ exit_error(OTHER_PROBLEM, "%s",
+ ipset_session_error(session));
- while (runner != NULL) {
- if (STREQ(runner->typename, typename))
- return runner;
-
- runner = runner->next;
+ if (!interactive) {
+ ipset_session_fini(session);
+ exit(OTHER_PROBLEM);
}
- return NULL; /* not found */
-}
-
-static struct settype *settype_load(const char *typename)
-{
- char path[sizeof(IPSET_LIB_DIR) + sizeof(IPSET_LIB_NAME) +
- strlen(typename)];
- struct settype *settype;
-
- /* do some search in list */
- settype = settype_find(typename);
- if (settype != NULL)
- return settype; /* found */
-
- /* Else we have to load it */
- sprintf(path, IPSET_LIB_DIR IPSET_LIB_NAME, typename);
-
- if (dlopen(path, RTLD_NOW)) {
- /* Found library. */
-
- settype = settype_find(typename);
-
- if (settype != NULL)
- return settype;
- }
-
- /* Can't load the settype */
- exit_error(PARAMETER_PROBLEM,
- "Couldn't load settype `%s':%s\n",
- typename, dlerror());
-
- return NULL; /* Never executed, but keep compilers happy */
-}
-
-static char *check_set_name(char *setname)
-{
- if (strlen(setname) > IP_SET_MAXNAMELEN - 1)
- exit_error(PARAMETER_PROBLEM,
- "Setname '%s' too long, max %d characters.",
- setname, IP_SET_MAXNAMELEN - 1);
-
- return setname;
-}
-
-static struct settype *check_set_typename(const char *typename)
-{
- if (strlen(typename) > IP_SET_MAXNAMELEN - 1)
- exit_error(PARAMETER_PROBLEM,
- "Typename '%s' too long, max %d characters.",
- typename, IP_SET_MAXNAMELEN - 1);
-
- return settype_load(typename);
-}
-
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-
-/* Register a new set type */
-void settype_register(struct settype *settype)
-{
- struct settype *chk;
- size_t size;
-
- DP("%s", settype->typename);
-
- /* Check if this typename already exists */
- chk = settype_find(settype->typename);
-
- if (chk != NULL)
- exit_error(OTHER_PROBLEM,
- "Set type '%s' already registered!\n",
- settype->typename);
-
- /* Check version */
- if (settype->protocol_version != IP_SET_PROTOCOL_VERSION)
- exit_error(OTHER_PROBLEM,
- "Set type %s is of wrong protocol version %u!"
- " I'm of version %u.\n", settype->typename,
- settype->protocol_version,
- IP_SET_PROTOCOL_VERSION);
-
- /* Initialize internal data */
- settype->header = ipset_malloc(settype->header_size);
- size = MAX(settype->create_size, settype->adt_size);
- settype->data = ipset_malloc(size);
-
- /* Insert first */
- settype->next = all_settypes;
- all_settypes = settype;
-
- DP("%s registered", settype->typename);
-}
-
-/* Find set functions */
-struct set *set_find_byid(ip_set_id_t id)
-{
- struct set *set = NULL;
- ip_set_id_t i;
-
- for (i = 0; i < max_sets; i++)
- if (set_list[i] && set_list[i]->id == id) {
- set = set_list[i];
- break;
- }
-
- if (set == NULL)
- exit_error(PARAMETER_PROBLEM,
- "Set identified by id %u is not found", id);
- return set;
-}
-
-struct set *set_find_byname(const char *name)
-{
- struct set *set = NULL;
- ip_set_id_t i;
-
- for (i = 0; i < max_sets; i++)
- if (set_list[i] != NULL && STREQ(set_list[i]->name, name)) {
- set = set_list[i];
- break;
- }
- if (set == NULL)
- exit_error(PARAMETER_PROBLEM,
- "Set %s is not found", name);
- return set;
-}
-
-static ip_set_id_t set_find_free_index(const char *name)
-{
- ip_set_id_t i, idx = IP_SET_INVALID_ID;
-
- for (i = 0; i < max_sets; i++) {
- if (idx == IP_SET_INVALID_ID
- && set_list[i] == NULL)
- idx = i;
- if (set_list[i] != NULL && STREQ(set_list[i]->name, name))
- exit_error(PARAMETER_PROBLEM,
- "Set %s is already defined, cannot be restored",
- name);
- }
-
- if (idx == IP_SET_INVALID_ID)
- exit_error(PARAMETER_PROBLEM,
- "Set %s cannot be restored, "
- "max number of set %u reached",
- name, max_sets);
-
- return idx;
-}
-
-/*
- * Send create set order to kernel
- */
-static void set_create(const char *name, struct settype *settype)
-{
- struct ip_set_req_create req_create;
- size_t size;
- void *data;
-
- DP("%s %s", name, settype->typename);
-
- req_create.op = IP_SET_OP_CREATE;
- req_create.version = protocol_version;
- strcpy(req_create.name, name);
- strcpy(req_create.typename, settype->typename);
-
- /* Final checks */
- settype->create_final(settype->data, settype->flags);
-
- /* Alloc memory for the data to send */
- size = sizeof(struct ip_set_req_create) + settype->create_size;
- data = ipset_malloc(size);
-
- /* Add up ip_set_req_create and the settype data */
- memcpy(data, &req_create, sizeof(struct ip_set_req_create));
- memcpy(data + sizeof(struct ip_set_req_create),
- settype->data, settype->create_size);
-
- kernel_sendto(CMD_CREATE, data, size);
- free(data);
-}
-
-static void set_restore_create(const char *name, struct settype *settype)
-{
- struct set *set;
-
- DP("%s %s %zu %zu %u %u", name, settype->typename,
- restore_offset, sizeof(struct ip_set_restore),
- settype->create_size, restore_size);
-
- /* Sanity checking */
- if (restore_offset
- + ALIGNED(sizeof(struct ip_set_restore))
- + ALIGNED(settype->create_size) > restore_size)
- exit_error(PARAMETER_PROBLEM,
- "Giving up, restore file is screwed up!");
-
- /* Final checks */
- settype->create_final(settype->data, settype->flags);
-
- /* Fill out restore_data */
- restore_set = (struct ip_set_restore *)
- (restore_data + restore_offset);
- strcpy(restore_set->name, name);
- strcpy(restore_set->typename, settype->typename);
- restore_set->index = set_find_free_index(name);
- restore_set->header_size = settype->create_size;
- restore_set->members_size = 0;
-
- DP("name %s, restore index %u", restore_set->name, restore_set->index);
- /* Add settype data */
-
- restore_offset += ALIGNED(sizeof(struct ip_set_restore));
- memcpy(restore_data + restore_offset, settype->data, settype->create_size);
-
- restore_offset += ALIGNED(settype->create_size);
- DP("restore_offset: %zu", restore_offset);
-
- /* Add set to set_list */
- set = ipset_malloc(sizeof(struct set));
- strcpy(set->name, name);
- set->settype = settype;
- set->index = restore_set->index;
- set_list[restore_set->index] = set;
-}
-
-/*
- * Send destroy/flush order to kernel for one or all sets
- */
-static void set_destroy(const char *name, unsigned op, unsigned cmd)
-{
- struct ip_set_req_std req;
-
- DP("%s %s", cmd == CMD_DESTROY ? "destroy" : "flush", name);
-
- req.op = op;
- req.version = protocol_version;
- strcpy(req.name, name);
-
- kernel_sendto(cmd, &req, sizeof(struct ip_set_req_std));
-}
-
-/*
- * Send rename/swap order to kernel
- */
-static void set_rename(const char *name, const char *newname,
- unsigned op, unsigned cmd)
-{
- struct ip_set_req_create req;
-
- DP("%s %s %s", cmd == CMD_RENAME ? "rename" : "swap",
- name, newname);
-
- req.op = op;
- req.version = protocol_version;
- strcpy(req.name, name);
- strcpy(req.typename, newname);
-
- kernel_sendto(cmd, &req,
- sizeof(struct ip_set_req_create));
-}
-
-/*
- * Send MAX_SETS, LIST_SIZE and/or SAVE_SIZE orders to kernel
- */
-static size_t load_set_list(const char name[IP_SET_MAXNAMELEN],
- ip_set_id_t *idx,
- unsigned op, unsigned cmd)
-{
- void *data = NULL;
- struct ip_set_req_max_sets req_max_sets;
- struct ip_set_name_list *name_list;
- struct set *set;
- ip_set_id_t i;
- socklen_t size, req_size;
- int repeated = 0, res = 0;
-
- DP("%s %s", cmd == CMD_MAX_SETS ? "MAX_SETS"
- : cmd == CMD_LIST_SIZE ? "LIST_SIZE"
- : "SAVE_SIZE",
- name);
-
-tryagain:
- if (set_list) {
- for (i = 0; i < max_sets; i++)
- if (set_list[i])
- free(set_list[i]);
- free(set_list);
- set_list = NULL;
- }
- /* Get max_sets */
- req_max_sets.op = IP_SET_OP_MAX_SETS;
- req_max_sets.version = protocol_version;
- strcpy(req_max_sets.set.name, name);
- size = sizeof(req_max_sets);
- kernel_getfrom(CMD_MAX_SETS, &req_max_sets, &size);
-
- DP("got MAX_SETS: sets %d, max_sets %d",
- req_max_sets.sets, req_max_sets.max_sets);
-
- max_sets = req_max_sets.max_sets;
- set_list = ipset_malloc(max_sets * sizeof(struct set *));
- memset(set_list, 0, max_sets * sizeof(struct set *));
- *idx = req_max_sets.set.index;
-
- if (req_max_sets.sets == 0)
- /* No sets in kernel */
- return 0;
-
- /* Get setnames */
- size = req_size = ALIGNED(sizeof(struct ip_set_req_setnames))
- + req_max_sets.sets * ALIGNED(sizeof(struct ip_set_name_list));
- data = ipset_malloc(size);
- ((struct ip_set_req_setnames *) data)->op = op;
- ((struct ip_set_req_setnames *) data)->index = *idx;
-
- res = kernel_getfrom_handleerrno(cmd, data, &size);
-
- if (res != 0 || size != req_size) {
- free(data);
- if (repeated++ < LIST_TRIES)
- goto tryagain;
- exit_error(OTHER_PROBLEM,
- "Tried to get sets from kernel %d times"
- " and failed. Please try again when the load on"
- " the sets has gone down.", LIST_TRIES);
- }
-
- /* Load in setnames */
- size = ALIGNED(sizeof(struct ip_set_req_setnames));
- while (size + ALIGNED(sizeof(struct ip_set_name_list)) <= req_size) {
- name_list = (struct ip_set_name_list *)
- (data + size);
- set = ipset_malloc(sizeof(struct set));
- strcpy(set->name, name_list->name);
- set->index = name_list->index;
- set->id = name_list->id;
- set->settype = settype_load(name_list->typename);
- set_list[name_list->index] = set;
- DP("loaded %s, type %s, index %u",
- set->name, set->settype->typename, set->index);
- size += ALIGNED(sizeof(struct ip_set_name_list));
- }
- /* Size to get set members */
- size = ((struct ip_set_req_setnames *)data)->size;
- free(data);
-
- return size;
+ ipset_session_report_reset(session);
+ return -1;
}
-/*
- * Save operation
- */
-static size_t save_set(void *data, size_t offset, size_t len)
+static void
+help(void)
{
- struct ip_set_save *set_save =
- (struct ip_set_save *) (data + offset);
- struct set *set;
- struct settype *settype;
- size_t used;
+ enum ipset_cmd cmd;
+ const struct ipset_envopts *opt = ipset_envopts;
- DP("offset %zu (%zu/%u/%u), len %zu", offset,
- sizeof(struct ip_set_save),
- set_save->header_size, set_save->members_size,
- len);
- if (offset + ALIGNED(sizeof(struct ip_set_save)) > len
- || offset + ALIGNED(sizeof(struct ip_set_save))
- + set_save->header_size + set_save->members_size > len)
- exit_error(OTHER_PROBLEM,
- "Save operation failed, try again later.");
+ printf("%s v%s\n\n"
+ "Usage: %s [options] COMMAND\n\nCommands:\n",
+ program_name, program_version, program_name);
- DP("index: %u", set_save->index);
- if (set_save->index == IP_SET_INVALID_ID) {
- /* Marker */
- return ALIGNED(sizeof(struct ip_set_save));
+ for (cmd = IPSET_CMD_NONE + 1; cmd < IPSET_CMD_MAX; cmd++) {
+ if (!ipset_commands[cmd-1].name[0])
+ continue;
+ printf("%s %s\n",
+ ipset_commands[cmd-1].name[0],
+ ipset_commands[cmd-1].help);
}
- set = set_list[set_save->index];
- if (!set)
- exit_error(OTHER_PROBLEM,
- "Save set failed, try again later.");
- settype = set->settype;
-
- /* Init set header */
- used = ALIGNED(sizeof(struct ip_set_save));
- settype->initheader(set, data + offset + used);
-
- /* Print create set */
- settype->saveheader(set, OPT_NUMERIC);
-
- /* Print add IPs */
- used += set_save->header_size;
- settype->saveips(set, data + offset + used,
- set_save->members_size, OPT_NUMERIC,
- DONT_ALIGN);
-
- return (used + set_save->members_size);
-}
-
-static int try_save_sets(const char name[IP_SET_MAXNAMELEN])
-{
- void *data = NULL;
- socklen_t size, req_size = 0;
- ip_set_id_t idx;
- int res = 0;
- time_t now = time(NULL);
-
- /* Load set_list from kernel */
- size = load_set_list(name, &idx,
- IP_SET_OP_SAVE_SIZE, CMD_SAVE);
+ printf("\nOptions:\n");
- if (size) {
- /* Get sets and print them */
- /* Take into account marker */
- req_size = (size += ALIGNED(sizeof(struct ip_set_save)));
- data = ipset_malloc(size);
- ((struct ip_set_req_list *) data)->op = IP_SET_OP_SAVE;
- ((struct ip_set_req_list *) data)->index = idx;
- res = kernel_getfrom_handleerrno(CMD_SAVE, data, &size);
-
- if (res != 0 || size != req_size) {
- DP("Try again: res: %i, size %u, req_size: %u",
- res, size, req_size);
- free(data);
- return -EAGAIN;
- }
- }
-
- printf("# Generated by ipset %s on %s", IPSET_VERSION, ctime(&now));
- size = 0;
- while (size < req_size) {
- DP("size: %u, req_size: %u", size, req_size);
- size += save_set(data, size, req_size);
+ while (opt->flag) {
+ if (opt->help)
+ printf("%s %s\n", opt->name[0], opt->help);
+ opt++;
}
- printf("COMMIT\n");
- now = time(NULL);
- printf("# Completed on %s", ctime(&now));
- ipset_free(data);
- return res;
-}
-
-/*
- * Performs a save to stdout
- */
-static void set_save(const char name[IP_SET_MAXNAMELEN])
-{
- int i;
-
- DP("%s", name);
- for (i = 0; i < LIST_TRIES; i++)
- if (try_save_sets(name) == 0)
- return;
-
- if (errno == EAGAIN)
- exit_error(OTHER_PROBLEM,
- "Tried to save sets from kernel %d times"
- " and failed. Please try again when the load on"
- " the sets has gone down.", LIST_TRIES);
- else
- kernel_error(CMD_SAVE, errno);
}
-/*
- * Restore operation
- */
-
-/* global new argv and argc */
-static char *newargv[255];
-static int newargc = 0;
-
/* Build faked argv from parsed line */
-static void build_argv(unsigned line, char *buffer) {
+static void
+build_argv(char *buffer)
+{
char *ptr;
int i;
/* Reset */
for (i = 1; i < newargc; i++)
- free(newargv[i]);
+ newargv[i] = NULL;
newargc = 1;
ptr = strtok(buffer, " \t\n");
- newargv[newargc++] = ipset_strdup(ptr);
+ newargv[newargc++] = ptr;
while ((ptr = strtok(NULL, " \t\n")) != NULL) {
if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
- newargv[newargc++] = ipset_strdup(ptr);
+ newargv[newargc++] = ptr;
else
exit_error(PARAMETER_PROBLEM,
- "Line %d is too long to restore\n", line);
+ "Line is too long to parse.");
}
}
-static FILE *create_tempfile(void)
-{
- char buffer[1024], __tmpdir[] = "/tmp";
- char *tmpdir = NULL;
- char *filename;
- int fd;
- FILE *file;
-
- if (!(tmpdir = getenv("TMPDIR")) && !(tmpdir = getenv("TMP")))
- tmpdir = __tmpdir;
- filename = ipset_malloc(strlen(tmpdir) + strlen(TEMPFILE_PATTERN) + 1);
- strcpy(filename, tmpdir);
- strcat(filename, TEMPFILE_PATTERN);
-
- (void) umask(077); /* Create with restrictive permissions */
- fd = mkstemp(filename);
- if (fd == -1)
- exit_error(OTHER_PROBLEM, "Could not create temporary file.");
- if (!(file = fdopen(fd, "r+")))
- exit_error(OTHER_PROBLEM, "Could not open temporary file.");
- if (unlink(filename) == -1)
- exit_error(OTHER_PROBLEM, "Could not unlink temporary file.");
- free(filename);
-
- while (fgets(buffer, sizeof(buffer), stdin)) {
- fputs(buffer, file);
- }
- fseek(file, 0L, SEEK_SET);
-
- return file;
-}
+/* Main parser function, workhorse */
+int parse_commandline(int argc, char *argv[]);
/*
- * Performs a restore from a file
+ * Performs a restore from stdin
*/
-static void set_restore(char *argv0)
+static int
+restore(char *argv0)
{
- char buffer[1024];
- char *ptr, *name = NULL;
- char cmd = ' ';
- int first_pass, i;
- struct settype *settype = NULL;
- struct ip_set_req_setnames *header;
- ip_set_id_t idx;
- FILE *in;
- int res;
-
- /* Create and store stdin in temporary file */
- in = create_tempfile();
-
- /* Load existing sets from kernel */
- load_set_list(IPSET_TOKEN_ALL, &idx,
- IP_SET_OP_LIST_SIZE, CMD_RESTORE);
-
- restore_line = 0;
- restore_size = ALIGNED(sizeof(struct ip_set_req_setnames)); /* header */
- DP("restore_size: %u", restore_size);
- /* First pass: calculate required amount of data */
- while (fgets(buffer, sizeof(buffer), in)) {
- restore_line++;
-
- if (buffer[0] == '\n')
- continue;
- else if (buffer[0] == '#')
- continue;
- else if (strcmp(buffer, "COMMIT\n") == 0) {
- /* Enable restore mode */
- restore = 1;
- break;
- }
-
- /* -N, -A or -B */
- ptr = strtok(buffer, " \t\n");
- DP("ptr: %s", ptr);
- if (ptr == NULL
- || ptr[0] != '-'
- || !(ptr[1] == 'N'
- || ptr[1] == 'A'
- || ptr[1] == 'B')
- || ptr[2] != '\0') {
- exit_error(PARAMETER_PROBLEM,
- "Line %u does not start as a valid restore command\n",
- restore_line);
- }
- cmd = ptr[1];
- /* setname */
- ptr = strtok(NULL, " \t\n");
- DP("setname: %s", ptr);
- if (ptr == NULL)
- exit_error(PARAMETER_PROBLEM,
- "Missing set name in line %u\n",
- restore_line);
- DP("cmd %c", cmd);
- switch (cmd) {
- case 'N': {
- name = check_set_name(ptr);
- /* settype */
- ptr = strtok(NULL, " \t\n");
- if (ptr == NULL)
- exit_error(PARAMETER_PROBLEM,
- "Missing settype in line %u\n",
- restore_line);
- settype = check_set_typename(ptr);
- restore_size += ALIGNED(sizeof(struct ip_set_restore))
- + ALIGNED(settype->create_size);
- DP("restore_size (N): %u", restore_size);
- break;
- }
- case 'A': {
- if (name == NULL
- || strncmp(name, ptr, sizeof(name)) != 0)
- exit_error(PARAMETER_PROBLEM,
- "Add IP to set %s in line %u without "
- "preceding corresponding create set line\n",
- ptr, restore_line);
- restore_size += ALIGNED(settype->adt_size);
- DP("restore_size (A): %u", restore_size);
- break;
- }
- default: {
- exit_error(PARAMETER_PROBLEM,
- "Unrecognized restore command in line %u\n",
- restore_line);
- }
- } /* end of switch */
- }
- /* Sanity checking */
- if (!restore)
- exit_error(PARAMETER_PROBLEM,
- "Missing COMMIT line\n");
- restore_size += ALIGNED(sizeof(struct ip_set_restore)); /* marker */
- DP("restore_size: %u", restore_size);
- restore_data = ipset_malloc(restore_size);
- header = (struct ip_set_req_setnames *) restore_data;
- header->op = IP_SET_OP_RESTORE;
- header->size = restore_size;
- restore_offset = ALIGNED(sizeof(struct ip_set_req_setnames));
-
- /* Rewind to scan the file again */
- fseek(in, 0L, SEEK_SET);
- first_pass = restore_line;
- restore_line = 0;
+ int ret = 0;
+ char *c;
/* Initialize newargv/newargc */
- newargv[newargc++] = ipset_strdup(argv0);
-
- /* Second pass: build up restore request */
- while (fgets(buffer, sizeof(buffer), in)) {
- restore_line++;
+ newargc = 0;
+ newargv[newargc++] = argv0;
- if (buffer[0] == '\n')
+ while (fgets(cmdline, sizeof(cmdline), stdin)) {
+ restore_line++;
+ c = cmdline;
+ while (isspace(c[0]))
+ c++;
+ if (c[0] == '\0' || c[0] == '#')
continue;
- else if (buffer[0] == '#')
+ else if (strcmp(c, "COMMIT\n") == 0) {
+ ret = ipset_commit(session);
+ if (ret < 0)
+ handle_error();
continue;
- else if (strcmp(buffer, "COMMIT\n") == 0)
- goto do_restore;
- DP("restoring: %s", buffer);
+ }
/* Build faked argv, argc */
- build_argv(restore_line, buffer);
- for (i = 0; i < newargc; i++)
- DP("argv[%u]: %s", i, newargv[i]);
+ build_argv(c);
- /* Parse line */
- parse_commandline(newargc, newargv);
- }
- exit_error(PARAMETER_PROBLEM,
- "Broken restore file\n");
- do_restore:
- if (restore_size == (restore_offset + ALIGNED(sizeof(struct ip_set_restore)))) {
- /* No bindings */
- struct ip_set_restore *marker =
- (struct ip_set_restore *) (restore_data + restore_offset);
-
- marker->index = IP_SET_INVALID_ID;
- marker->header_size = marker->members_size = 0;
- restore_offset += ALIGNED(sizeof(struct ip_set_restore));
- DP("restore marker, restore_offset: %zu", restore_offset);
+ /* Execute line */
+ ret = parse_commandline(newargc, newargv);
+ if (ret < 0)
+ handle_error();
}
- if (restore_size != restore_offset)
- exit_error(PARAMETER_PROBLEM,
- "Giving up, restore file is screwed up!");
- res = kernel_getfrom_handleerrno(CMD_RESTORE, restore_data, &restore_size);
+ /* implicit "COMMIT" at EOF */
+ ret = ipset_commit(session);
+ if (ret < 0)
+ handle_error();
- if (res != 0) {
- if (restore_size != sizeof(struct ip_set_req_setnames))
- exit_error(PARAMETER_PROBLEM,
- "Communication with kernel failed (%u %u)!",
- restore_size, sizeof(struct ip_set_req_setnames));
- /* Check errors */
- header = (struct ip_set_req_setnames *) restore_data;
- if (header->size != 0)
- exit_error(PARAMETER_PROBLEM,
- "Committing restoring failed at line %u!",
- header->size);
- }
+ return ret;
}
-/*
- * Send ADT_GET order to kernel for a set
- */
-static struct set *set_adt_get(const char *name)
-{
- struct ip_set_req_adt_get req_adt_get;
- struct set *set;
- socklen_t size;
-
- DP("%s", name);
-
- check_protocolversion();
-
- req_adt_get.op = IP_SET_OP_ADT_GET;
- req_adt_get.version = protocol_version;
- strcpy(req_adt_get.set.name, name);
- size = sizeof(struct ip_set_req_adt_get);
-
- kernel_getfrom(CMD_ADT_GET, (void *) &req_adt_get, &size);
-
- set = ipset_malloc(sizeof(struct set));
- strcpy(set->name, name);
- set->index = req_adt_get.set.index;
- set->settype = settype_load(req_adt_get.typename);
-
- return set;
-}
-
-/*
- * Send add/del/test order to kernel for a set
- */
-static int set_adtip(struct set *set, const char *adt,
- unsigned op, unsigned cmd)
-{
- struct ip_set_req_adt *req_adt;
- size_t size;
- void *data;
- int res = 0;
-
- DP("%s -> %s", set->name, adt);
-
- /* Alloc memory for the data to send */
- size = ALIGNED(sizeof(struct ip_set_req_adt)) + set->settype->adt_size ;
- DP("alloc size %zu", size);
- data = ipset_malloc(size);
-
- /* Fill out the request */
- req_adt = (struct ip_set_req_adt *) data;
- req_adt->op = op;
- req_adt->index = set->index;
- memcpy(data + ALIGNED(sizeof(struct ip_set_req_adt)),
- set->settype->data, set->settype->adt_size);
-
- if (kernel_sendto_handleerrno(cmd, data, size) == -1)
- switch (op) {
- case IP_SET_OP_ADD_IP:
- exit_error(OTHER_PROBLEM, "%s is already in set %s.",
- adt, set->name);
- break;
- case IP_SET_OP_DEL_IP:
- exit_error(OTHER_PROBLEM, "%s is not in set %s.",
- adt, set->name);
- break;
- case IP_SET_OP_TEST_IP:
- ipset_printf("%s is in set %s.", adt, set->name);
- res = 0;
- break;
- default:
- break;
- }
- else
- switch (op) {
- case IP_SET_OP_TEST_IP:
- ipset_printf("%s is NOT in set %s.", adt, set->name);
- res = 1;
- break;
- default:
- break;
- }
- free(data);
-
- return res;
-}
-
-static void set_restore_add(struct set *set, const char *adt UNUSED)
-{
- DP("%s %s", set->name, adt);
- /* Sanity checking */
- if (restore_offset + ALIGNED(set->settype->adt_size) > restore_size)
- exit_error(PARAMETER_PROBLEM,
- "Giving up, restore file is screwed up!");
-
- memcpy(restore_data + restore_offset,
- set->settype->data, set->settype->adt_size);
- restore_set->members_size += ALIGNED(set->settype->adt_size);
- restore_offset += ALIGNED(set->settype->adt_size);
-
- DP("restore_offset: %zu", restore_offset);
-}
-
-/*
- * Print operation
- */
-
-/* Help function to set_list() */
-static size_t print_set(void *data, unsigned options)
-{
- struct ip_set_list *setlist = data;
- struct set *set = set_list[setlist->index];
- struct settype *settype = set->settype;
- size_t offset;
-
- /* Pretty print the set */
- DP("header size: %u, members size: %u",
- setlist->header_size, setlist->members_size);
- printf("Name: %s\n", set->name);
- printf("Type: %s\n", settype->typename);
- printf("References: %d\n", setlist->ref);
-
- /* Init header */
- offset = ALIGNED(sizeof(struct ip_set_list));
- settype->initheader(set, data + offset);
-
- /* Pretty print the type header */
- printf("Header:");
- settype->printheader(set, options);
-
- /* Pretty print all IPs */
- printf("Members:\n");
- offset += setlist->header_size;
- DP("Aligned: %u, offset: %zu, members_size %u\n", !DONT_ALIGN, offset,
- setlist->members_size);
- if (options & OPT_SORTED)
- settype->printips_sorted(set, data + offset,
- setlist->members_size, options,
- DONT_ALIGN);
- else
- settype->printips(set, data + offset,
- setlist->members_size, options,
- DONT_ALIGN);
-
- printf("\n"); /* One newline between sets */
-
- return (offset + setlist->members_size);
-}
-
-static int try_list_sets(const char name[IP_SET_MAXNAMELEN],
- unsigned options)
-{
- void *data = NULL;
- ip_set_id_t idx;
- socklen_t size, req_size;
- int res = 0;
-
- /* Default is numeric listing */
- if (!(options & (OPT_RESOLVE|OPT_NUMERIC)))
- options |= OPT_NUMERIC;
-
- DP("%s", name);
- /* Load set_list from kernel */
- size = req_size = load_set_list(name, &idx,
- IP_SET_OP_LIST_SIZE, CMD_LIST);
-
- if (size) {
- /* Get sets and print them */
- data = ipset_malloc(size);
- ((struct ip_set_req_list *) data)->op = IP_SET_OP_LIST;
- ((struct ip_set_req_list *) data)->index = idx;
- res = kernel_getfrom_handleerrno(CMD_LIST, data, &size);
- DP("get_lists getsockopt() res=%d errno=%d", res, errno);
-
- if (res != 0 || size != req_size) {
- free(data);
- return -EAGAIN;
+static int
+call_parser(int argc, char *argv[], const struct ipset_arg *args)
+{
+ int i = 1, ret = 0;
+ const struct ipset_arg *arg;
+
+ /* Currently CREATE and ADD may have got additional arguments */
+ if (!args)
+ goto done;
+ for (arg = args; arg->opt; arg++) {
+ for (i = 1; i < argc; ) {
+ D("argc: %u, i: %u", argc, i);
+ if (!(ipset_name_match(argv[i], arg->name))) {
+ i++;
+ continue;
+ }
+ /* Shift off matched option */
+ D("match %s", arg->name[0]);
+ ipset_shift_argv(&argc, argv, i);
+ D("argc: %u, i: %u", argc, i);
+ switch (arg->has_arg) {
+ case IPSET_MANDATORY_ARG:
+ if (i + 1 > argc) {
+ exit_error(PARAMETER_PROBLEM,
+ "Missing mandatory argument of option `%s'",
+ arg->name[0]);
+ return 1;
+ }
+ /* Fall through */
+ case IPSET_OPTIONAL_ARG:
+ if (i + 1 <= argc) {
+ ret = arg->parse(session, arg->opt,
+ argv[i]);
+ if (ret < 0)
+ return ret;
+ ipset_shift_argv(&argc, argv, i);
+ }
+ break;
+ default:
+ ret = ipset_data_set(ipset_session_data(session),
+ arg->opt, arg->name[0]);
+ if (ret < 0)
+ return ret;
+ }
}
- size = 0;
}
- while (size != req_size)
- size += print_set(data + size, options);
-
- ipset_free(data);
- return res;
+done:
+ if (i < argc) {
+ exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'",
+ argv[i]);
+ return 1;
+ }
+ return ret;
}
-/* Print a set or all sets
- * All sets: name = NULL
- */
-static void list_sets(const char name[IP_SET_MAXNAMELEN], unsigned options)
+static void
+check_mandatory(const struct ipset_type *type, int cmd)
{
- int i;
-
- DP("%s", name);
- for (i = 0; i < LIST_TRIES; i++)
- if (try_list_sets(name, options) == 0)
- return;
+ uint64_t flags = ipset_data_flags(ipset_session_data(session));
+ uint64_t mandatory = type->mandatory[cmd];
+ const struct ipset_arg *arg = type->args[cmd];
- if (errno == EAGAIN)
- exit_error(OTHER_PROBLEM,
- "Tried to list sets from kernel %d times"
- " and failed. Please try again when the load on"
- " the sets has gone down.", LIST_TRIES);
- else
- kernel_error(CMD_LIST, errno);
-}
-
-/* Prints help
- * If settype is non null help for that type is printed as well
- */
-static void set_help(const struct settype *settype)
-{
- printf("%s v%s\n\n"
- "Usage: %s -N new-set settype [options]\n"
- " %s -[XFLSH] [set] [options]\n"
- " %s -[EW] from-set to-set\n"
- " %s -[ADT] set IP\n"
- " %s -R\n"
- " %s -v\n"
- " %s -h (print this help information)\n\n",
- program_name, program_version,
- program_name, program_name, program_name,
- program_name, program_name, program_name,
- program_name);
+ /* Range can be expressed by ip/cidr */
+ if (flags & IPSET_FLAG(IPSET_OPT_CIDR))
+ flags |= IPSET_FLAG(IPSET_OPT_IP_TO);
- printf("Commands:\n"
- "Either long or short options are allowed.\n"
- " --create -N setname settype <options>\n"
- " Create a new set\n"
- " --destroy -X [setname]\n"
- " Destroy a set or all sets\n"
- " --flush -F [setname]\n"
- " Flush a set or all sets\n"
- " --rename -E from-set to-set\n"
- " Rename from-set to to-set\n"
- " --swap -W from-set to-set\n"
- " Swap the content of two existing sets\n"
- " --list -L [setname] [options]\n"
- " List the IPs in a set or all sets\n"
- " --save -S [setname]\n"
- " Save the set or all sets to stdout\n"
- " --restore -R [option]\n"
- " Restores a saved state\n"
- " --add -A setname IP\n"
- " Add an IP to a set\n"
- " --del -D setname IP\n"
- " Deletes an IP from a set\n"
- " --test -T setname IP \n"
- " Tests if an IP exists in a set.\n"
- " --help -H [settype]\n"
- " Prints this help, and settype specific help\n"
- " --version -V\n"
- " Prints version information\n\n"
- "Options:\n"
- " --sorted -s Numeric sort of the IPs in -L\n"
- " --numeric -n Numeric output of addresses in a -L (default)\n"
- " --resolve -r Try to resolve addresses in a -L\n"
- " --quiet -q Suppress any output to stdout and stderr.\n");
-#ifdef IPSET_DEBUG
- printf(" --debug -z Enable debugging\n\n");
-#else
- printf("\n");
-#endif
+ mandatory &= ~flags;
+ if (!mandatory)
+ return;
- if (settype != NULL) {
- printf("Type '%s' specific:\n", settype->typename);
- settype->usage();
- }
+ for (; arg->opt; arg++)
+ if (mandatory & IPSET_FLAG(arg->opt))
+ exit_error(PARAMETER_PROBLEM,
+ "Mandatory option `%s' is missing",
+ arg->name[0]);
}
-static int find_cmd(int option)
+static const struct ipset_type *
+type_find(const char *name)
{
- int i;
+ const struct ipset_type *t = ipset_types();
- for (i = 1; i <= NUMBER_OF_CMD; i++)
- if (cmdflags[i] == option)
- return i;
-
- return CMD_NONE;
+ while (t) {
+ if (STREQ(t->name, name) || STREQ(t->alias, name))
+ return t;
+ t = t->next;
+ }
+ return NULL;
}
-static int parse_adt_cmdline(int command,
- const char *name,
- char *adt,
- struct set **set,
- struct settype **settype)
+static inline int cmd2cmd(int cmd)
{
- int res = 0;
-
- *set = restore ? set_find_byname(name) : set_adt_get(name);
-
- /* Reset space for adt data */
- *settype = (*set)->settype;
- memset((*settype)->data, 0, (*settype)->adt_size);
-
- res = (*settype)->adt_parser(command, adt, (*settype)->data);
-
- return res;
+ switch(cmd) {
+ case IPSET_CMD_ADD:
+ return IPSET_ADD;
+ case IPSET_CMD_DEL:
+ return IPSET_DEL;
+ case IPSET_CMD_TEST:
+ return IPSET_TEST;
+ case IPSET_CMD_CREATE:
+ return IPSET_CREATE;
+ default:
+ return 0;
+ }
}
-/* Main worker function */
-int parse_commandline(int argc, char *argv[])
-{
- int res = 0;
- int command = CMD_NONE;
- unsigned options = 0;
- int c;
-
- char *name = NULL; /* All except -H, -R */
- char *newname = NULL; /* -E, -W */
- char *adt = NULL; /* -A, -D, -T */
- struct set *set = NULL; /* -A, -D, -T */
- struct settype *settype = NULL; /* -N, -H */
- char all_sets[] = IPSET_TOKEN_ALL;
-
- struct option *opts = opts_long;
-
- /* Suppress error messages: we may add new options if we
- demand-load a protocol. */
- opterr = 0;
- /* Reset optind to 0 for restore */
- optind = 0;
-
- while ((c = getopt_long(argc, argv, opts_short, opts, NULL)) != -1) {
-
- DP("commandline parsed: opt %c (%s)", c, argv[optind]);
-
- switch (c) {
- /*
- * Command selection
- */
- case 'h':
- case 'H':{ /* Help: -H [typename [options]] */
- check_protocolversion();
- set_command(&command, CMD_HELP);
-
- if (optarg)
- settype = check_set_typename(optarg);
- else if (optind < argc
- && argv[optind][0] != '-')
- settype = check_set_typename(argv[optind++]);
-
- break;
- }
-
- case 'V':
- case 'v': { /* Version */
- printf("%s v%s, protocol version %u.\n",
- program_name, program_version,
- IP_SET_PROTOCOL_VERSION);
- check_protocolversion();
- printf("Kernel module protocol version %u.\n",
- protocol_version);
- exit(0);
+/* Workhorse */
+int
+parse_commandline(int argc, char *argv[])
+{
+ int ret = 0;
+ enum ipset_cmd cmd = IPSET_CMD_NONE;
+ int i = 0, j;
+ char *arg0 = NULL, *arg1 = NULL, *c;
+ const struct ipset_envopts *opt;
+ const struct ipset_commands *command;
+ const struct ipset_type *type;
+
+ /* Initialize session */
+ if (session == NULL) {
+ session = ipset_session_init(printf);
+ if (session == NULL)
+ exit_error(OTHER_PROBLEM,
+ "Cannot initialize ipset session, aborting.");
+ }
+
+ /* Commandline parsing, somewhat similar to that of 'ip' */
+
+ /* First: parse core options */
+ for (opt = ipset_envopts; opt->flag ; opt++) {
+ for (i = 1; i < argc; ) {
+ if (!ipset_name_match(argv[i], opt->name)) {
+ i++;
+ continue;
}
-
- case 'N':{ /* Create: -N name typename options */
- set_command(&command, CMD_CREATE);
-
- name = check_set_name(optarg);
-
- /* Protect reserved names */
- if (name[0] == ':')
+ /* Shift off matched option */
+ ipset_shift_argv(&argc, argv, i);
+ switch (opt->has_arg) {
+ case IPSET_MANDATORY_ARG:
+ if (i + 1 > argc)
exit_error(PARAMETER_PROBLEM,
- "setname might not start with colon",
- cmd2char(CMD_CREATE));
-
- if (optind < argc
- && argv[optind][0] != '-')
- settype = check_set_typename(argv[optind++]);
- else
- exit_error(PARAMETER_PROBLEM,
- "-%c requires setname and settype",
- cmd2char(CMD_CREATE));
-
- DP("merge options");
- /* Merge the create options */
- opts = merge_options(opts,
- settype->create_opts,
- &settype->option_offset);
-
- /* Reset space for create data */
- memset(settype->data, 0, settype->create_size);
-
- /* Zero the flags */
- settype->flags = 0;
-
- DP("call create_init");
- /* Call the settype create_init */
- settype->create_init(settype->data);
-
+ "Missing mandatory argument to option %s",
+ opt->name[0]);
+ /* Fall through */
+ case IPSET_OPTIONAL_ARG:
+ if (i + 1 <= argc) {
+ ret = opt->parse(session, opt->flag,
+ argv[i]);
+ if (ret < 0)
+ return handle_error();
+ ipset_shift_argv(&argc, argv, i);
+ }
break;
- }
-
- case 'X': /* Destroy */
- case 'F': /* Flush */
- case 'L': /* List */
- case 'S':{ /* Save */
- set_command(&command, find_cmd(c));
-
- if (optarg)
- name = check_set_name(optarg);
- else if (optind < argc
- && argv[optind][0] != '-')
- name = check_set_name(argv[optind++]);
- else
- name = all_sets;
-
+ default:
+ ret = opt->parse(session, opt->flag, argv[i]);
+ if (ret < 0)
+ return handle_error();
break;
}
+ }
+ }
- case 'R':{ /* Restore */
- set_command(&command, find_cmd(c));
-
- break;
+ /* Second: parse command */
+ for (j = IPSET_CMD_NONE + 1; j < IPSET_CMD_MAX; j++) {
+ command = &ipset_commands[j - 1];
+ if (!command->name[0])
+ continue;
+ for (i = 1; i < argc; ) {
+ if (!ipset_name_match(argv[i], command->name)) {
+ i++;
+ continue;
}
-
- case 'E': /* Rename */
- case 'W':{ /* Swap */
- set_command(&command, find_cmd(c));
- name = check_set_name(optarg);
-
- if (optind < argc
- && argv[optind][0] != '-')
- newname = check_set_name(argv[optind++]);
- else
- exit_error(PARAMETER_PROBLEM,
- "-%c requires a setname "
- "and the new name for that set",
- cmd2char(CMD_RENAME));
-
- break;
+ if (cmd != IPSET_CMD_NONE)
+ exit_error(PARAMETER_PROBLEM,
+ "Commands `%s' and `%s'"
+ "cannot be specified together.",
+ ipset_commands[cmd - 1].name[0],
+ command->name[0]);
+ if (restore_line != 0
+ && (j == IPSET_CMD_RESTORE
+ || j == IPSET_CMD_VERSION
+ || j == IPSET_CMD_HELP))
+ exit_error(PARAMETER_PROBLEM,
+ "Command `%s' is invalid in restore mode.",
+ command->name[0]);
+ if (interactive && j == IPSET_CMD_RESTORE) {
+ printf("Restore command ignored in interactive mode\n");
+ return 0;
}
- case 'A': /* Add IP */
- case 'D': /* Del IP */
- case 'T':{ /* Test IP */
- set_command(&command, find_cmd(c));
-
- name = check_set_name(optarg);
-
- /* IP */
- if (optind < argc
- && argv[optind][0] != '-')
- adt = argv[optind++];
- else
- exit_error(PARAMETER_PROBLEM,
- "-%c requires setname and IP",
- c);
-
- res = parse_adt_cmdline(command, name, adt,
- &set, &settype);
-
- if (!res)
+ /* Shift off matched command arg */
+ ipset_shift_argv(&argc, argv, i);
+ cmd = j;
+ switch (command->has_arg) {
+ case IPSET_MANDATORY_ARG:
+ case IPSET_MANDATORY_ARG2:
+ if (i + 1 > argc)
exit_error(PARAMETER_PROBLEM,
- "Unknown arg `%s'",
- argv[optind - 1]);
-
- res = 0;
+ "Missing mandatory argument to command %s",
+ command->name[0]);
+ /* Fall through */
+ case IPSET_OPTIONAL_ARG:
+ arg0 = argv[i];
+ if (i + 1 <= argc)
+ /* Shift off first arg */
+ ipset_shift_argv(&argc, argv, i);
+ break;
+ default:
break;
}
-
- /* options */
-
- case 'n':
- add_option(&options, OPT_NUMERIC);
- break;
-
- case 'r':
- if (!(options & OPT_NUMERIC))
- add_option(&options, OPT_RESOLVE);
- break;
-
- case 's':
- add_option(&options, OPT_SORTED);
- break;
-
- case 'q':
- add_option(&options, OPT_QUIET);
- option_quiet = 1;
- break;
-
-#ifdef IPSET_DEBUG
- case 'z': /* debug */
- add_option(&options, OPT_DEBUG);
- option_debug = 1;
- break;
-#endif
-
- case 1: /* non option */
- printf("Bad argument `%s'\n", optarg);
- exit_tryhelp(PARAMETER_PROBLEM);
- break; /*always good */
-
- default:{
- DP("default");
-
- switch (command) {
- case CMD_CREATE:
- res = settype->create_parse(
- c - settype->option_offset,
- argv,
- settype->data,
- &settype->flags);
- break;
-
- default:
- res = 0; /* failed */
- } /* switch (command) */
-
-
- if (!res)
+ if (command->has_arg == IPSET_MANDATORY_ARG2) {
+ if (i + 1 > argc)
exit_error(PARAMETER_PROBLEM,
- "Unknown arg `%s'",
- argv[optind - 1]);
-
- res = 0;
+ "Missing second mandatory argument to command %s",
+ command->name[0]);
+ arg1 = argv[i];
+ /* Shift off second arg */
+ ipset_shift_argv(&argc, argv, i);
}
+ }
+ }
- DP("next arg");
- } /* switch */
-
- } /* while( getopt_long() ) */
-
-
- if (optind < argc)
- exit_error(PARAMETER_PROBLEM,
- "unknown arguments found on commandline");
- if (command == CMD_NONE)
- exit_error(PARAMETER_PROBLEM, "no command specified");
-
- /* Check options */
- generic_opt_check(command, options);
-
- DP("cmd: %c", cmd2char(command));
-
- check_protocolversion();
-
- switch (command) {
- case CMD_CREATE:
- DP("CMD_CREATE");
- if (restore)
- set_restore_create(name, settype);
- else
- set_create(name, settype);
- break;
-
- case CMD_DESTROY:
- set_destroy(name, IP_SET_OP_DESTROY, CMD_DESTROY);
- break;
-
- case CMD_FLUSH:
- set_destroy(name, IP_SET_OP_FLUSH, CMD_FLUSH);
- break;
-
- case CMD_RENAME:
- set_rename(name, newname, IP_SET_OP_RENAME, CMD_RENAME);
- break;
-
- case CMD_SWAP:
- set_rename(name, newname, IP_SET_OP_SWAP, CMD_SWAP);
- break;
-
- case CMD_LIST:
- list_sets(name, options);
- break;
-
- case CMD_SAVE:
- set_save(name);
- break;
-
- case CMD_RESTORE:
- set_restore(argv[0]);
+ /* Third: catch interactive mode, handle help, version */
+ switch (cmd) {
+ case IPSET_CMD_NONE:
+ if (interactive) {
+ printf("No command specified\n");
+ return 0;
+ }
+ if (argc > 1 && STREQ(argv[1], "-")) {
+ interactive = true;
+ printf("%s> ", program_name);
+ /* Initialize newargv/newargc */
+ newargv[newargc++] = program_name;
+ while (fgets(cmdline, sizeof(cmdline), stdin)) {
+ c = cmdline;
+ while (isspace(c[0]))
+ c++;
+ if (c[0] == '\0' || c[0] == '#')
+ continue;
+ /* Build fake argv, argc */
+ build_argv(c);
+ /* Execute line: ignore errors */
+ parse_commandline(newargc, newargv);
+ printf("%s> ", program_name);
+ }
+ exit_error(NO_PROBLEM, NULL);
+ }
+ exit_error(PARAMETER_PROBLEM, "No command specified.");
+ case IPSET_CMD_VERSION:
+ printf("%s v%s.\n", program_name, program_version);
+ if (interactive)
+ return 0;
+ exit_error(NO_PROBLEM, NULL);
+ case IPSET_CMD_HELP:
+ help();
+
+ if (interactive
+ || !ipset_envopt_test(session, IPSET_ENV_QUIET)) {
+ if (arg0) {
+ /* Type-specific help, without kernel checking */
+ type = type_find(arg0);
+ if (!type)
+ exit_error(PARAMETER_PROBLEM,
+ "Unknown settype: `%s'", arg0);
+ printf("\n%s type specific options:\n\n%s",
+ type->name, type->usage);
+ if (type->family == AF_UNSPEC)
+ printf("\nType %s is family neutral.\n",
+ type->name);
+ else if (type->family == AF_INET46)
+ printf("\nType %s supports INET and INET6.\n",
+ type->name);
+ else
+ printf("\nType %s supports family %s only.\n",
+ type->name,
+ type->family == AF_INET ? "INET" : "INET6");
+ } else {
+ printf("\nSupported set types:\n");
+ type = ipset_types();
+ while (type) {
+ printf(" %s\n", type->name);
+ type = type->next;
+ }
+ }
+ }
+ if (interactive)
+ return 0;
+ exit_error(NO_PROBLEM, NULL);
+ default:
break;
-
- case CMD_ADD:
- if (restore)
- set_restore_add(set, adt);
- else
- set_adtip(set, adt, IP_SET_OP_ADD_IP, CMD_ADD);
+ }
+
+ /* Forth: parse command args and issue the command */
+ switch (cmd) {
+ case IPSET_CMD_CREATE:
+ /* Args: setname typename [type specific options] */
+ ret = ipset_parse_setname(session, IPSET_SETNAME, arg0);
+ if (ret < 0)
+ return handle_error();
+
+ ret = ipset_parse_typename(session, IPSET_OPT_TYPENAME, arg1);
+ if (ret < 0)
+ return handle_error();
+
+ type = ipset_type_get(session, cmd);
+ if (type == NULL)
+ return handle_error();
+
+ /* Parse create options */
+ ret = call_parser(argc, argv, type->args[IPSET_CREATE]);
+ if (ret < 0)
+ return handle_error();
+ else if (ret)
+ return ret;
+
+ /* Check mandatory options */
+ check_mandatory(type, IPSET_CREATE);
+
break;
-
- case CMD_DEL:
- set_adtip(set, adt, IP_SET_OP_DEL_IP, CMD_DEL);
+ case IPSET_CMD_DESTROY:
+ case IPSET_CMD_FLUSH:
+ case IPSET_CMD_LIST:
+ case IPSET_CMD_SAVE:
+ /* Args: [setname] */
+ if (arg0) {
+ ret = ipset_parse_setname(session, IPSET_SETNAME, arg0);
+ if (ret < 0)
+ return handle_error();
+ }
break;
- case CMD_TEST:
- res = set_adtip(set, adt, IP_SET_OP_TEST_IP, CMD_TEST);
+ case IPSET_CMD_RENAME:
+ case IPSET_CMD_SWAP:
+ /* Args: from-setname to-setname */
+ ret = ipset_parse_setname(session, IPSET_SETNAME, arg0);
+ if (ret < 0)
+ return handle_error();
+ ret = ipset_parse_name(session, IPSET_OPT_SETNAME2, arg1);
+ if (ret < 0)
+ return handle_error();
break;
- case CMD_HELP:
- set_help(settype);
+ case IPSET_CMD_RESTORE:
+ /* Restore mode */
+ return restore(argv[0]);
+ case IPSET_CMD_ADD:
+ case IPSET_CMD_DEL:
+ case IPSET_CMD_TEST:
+ D("ADT: setname %s", arg0);
+ /* Args: setname ip [options] */
+ ret = ipset_parse_setname(session, IPSET_SETNAME, arg0);
+ if (ret < 0)
+ return handle_error();
+
+ type = ipset_type_get(session, cmd);
+ if (type == NULL)
+ return handle_error();
+
+ ret = ipset_parse_elem(session, type->last_elem_optional, arg1);
+ if (ret < 0)
+ return handle_error();
+
+ /* Parse additional ADT options */
+ ret = call_parser(argc, argv, type->args[cmd2cmd(cmd)]);
+ if (ret < 0)
+ return handle_error();
+ else if (ret)
+ return ret;
+
+ /* Check mandatory options */
+ check_mandatory(type, cmd2cmd(cmd));
+
break;
-
default:
- /* Will never happen */
- break; /* Keep the compiler happy */
+ break;
+ }
- } /* switch( command ) */
+ ret = ipset_cmd(session, cmd, restore_line);
+ D("ret %d", ret);
+ /* Special case for TEST and non-quiet mode */
+ if (cmd == IPSET_CMD_TEST && ipset_session_warning(session)) {
+ if (!ipset_envopt_test(session, IPSET_ENV_QUIET))
+ fprintf(stderr, "%s\n", ipset_session_warning(session));
+ ipset_session_report_reset(session);
+ }
+ if (ret < 0)
+ handle_error();
- return res;
+ return ret;
}
-
-int main(int argc, char *argv[])
-{
+int
+main(int argc, char *argv[])
+{
return parse_commandline(argc, argv);
-
}