New routers supported
[tomato.git] / release / src / router / ipset / ipset.c
blob3b8e24857dbe4447e00034fedbe14ea51f6b63f9
1 /* Copyright 2000-2002 Joakim Axelsson (gozem@linux.nu)
2 * Patrick Schaaf (bof@bof.de)
3 * Copyright 2003-2004 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
10 #include <stdio.h> /* *printf, perror, sscanf, fdopen */
11 #include <string.h> /* mem*, str* */
12 #include <errno.h> /* errno, perror */
13 #include <time.h> /* time, ctime */
14 #include <netdb.h> /* gethostby*, getnetby*, getservby* */
15 #include <stdlib.h> /* exit, malloc, free, strtol, getenv, mkstemp */
16 #include <unistd.h> /* read, close, fork, exec*, unlink */
17 #include <sys/types.h> /* open, wait, socket, *sockopt, umask */
18 #include <sys/stat.h> /* open, umask */
19 #include <sys/wait.h> /* wait */
20 #include <sys/socket.h> /* socket, *sockopt, gethostby*, inet_* */
21 #include <netinet/in.h> /* inet_* */
22 #include <fcntl.h> /* open */
23 #include <arpa/inet.h> /* htonl, inet_* */
24 #include <stdarg.h> /* va_* */
25 #include <dlfcn.h> /* dlopen */
27 #include "ipset.h"
29 #ifndef PROC_SYS_MODPROBE
30 #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
31 #endif
33 char program_name[] = "ipset";
34 char program_version[] = IPSET_VERSION;
35 static int protocol_version = 0;
37 #define STREQ(a,b) (strncmp(a,b,IP_SET_MAXNAMELEN) == 0)
38 #define DONT_ALIGN (protocol_version == IP_SET_PROTOCOL_UNALIGNED)
39 #define ALIGNED(len) IPSET_VALIGN(len, DONT_ALIGN)
41 /* The list of loaded set types */
42 static struct settype *all_settypes = NULL;
44 /* Array of sets */
45 struct set **set_list = NULL;
46 ip_set_id_t max_sets = 0;
48 /* Suppress output to stdout and stderr? */
49 static int option_quiet = 0;
51 /* Data for restore mode */
52 static int restore = 0;
53 void *restore_data = NULL;
54 struct ip_set_restore *restore_set = NULL;
55 size_t restore_offset = 0;
56 socklen_t restore_size;
57 unsigned restore_line = 0;
58 unsigned warn_once = 0;
60 #define TEMPFILE_PATTERN "/ipsetXXXXXX"
62 #ifdef IPSET_DEBUG
63 int option_debug = 0;
64 #endif
66 #define OPTION_OFFSET 256
67 static unsigned int global_option_offset = 0;
69 /* Most of these command parsing functions are borrowed from iptables.c */
71 static const char cmdflags[] = { ' ', /* CMD_NONE */
72 'N', 'X', 'F', 'E', 'W', 'L', 'S', 'R',
73 'A', 'D', 'T', 'H', 'V',
76 /* Options */
77 #define OPT_NONE 0x0000U
78 #define OPT_NUMERIC 0x0001U /* -n */
79 #define OPT_SORTED 0x0002U /* -s */
80 #define OPT_QUIET 0x0004U /* -q */
81 #define OPT_DEBUG 0x0008U /* -z */
82 #define OPT_RESOLVE 0x0020U /* -r */
83 #define NUMBER_OF_OPT 5
84 static const char optflags[] =
85 { 'n', 's', 'q', 'z', 'r' };
87 static struct option opts_long[] = {
88 /* set operations */
89 {"create", 1, 0, 'N'},
90 {"destroy", 2, 0, 'X'},
91 {"flush", 2, 0, 'F'},
92 {"rename", 1, 0, 'E'},
93 {"swap", 1, 0, 'W'},
94 {"list", 2, 0, 'L'},
96 {"save", 2, 0, 'S'},
97 {"restore", 0, 0, 'R'},
99 /* ip in set operations */
100 {"add", 1, 0, 'A'},
101 {"del", 1, 0, 'D'},
102 {"test", 1, 0, 'T'},
104 /* free options */
105 {"numeric", 0, 0, 'n'},
106 {"sorted", 0, 0, 's'},
107 {"quiet", 0, 0, 'q'},
108 {"resolve", 0, 0, 'r'},
110 #ifdef IPSET_DEBUG
111 /* debug (if compiled with it) */
112 {"debug", 0, 0, 'z'},
113 #endif
115 /* version and help */
116 {"version", 0, 0, 'V'},
117 {"help", 2, 0, 'H'},
119 /* end */
120 {NULL},
123 static char opts_short[] =
124 "-N:X::F::E:W:L::S::RA:D:T:nrsqzvVh::H::";
126 /* Table of legal combinations of commands and options. If any of the
127 * given commands make an option legal, that option is legal.
128 * Key:
129 * + compulsory
130 * x illegal
131 * optional
134 static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = {
135 /* -n -s -q -z -r */
136 /*CREATE*/ {'x', 'x', ' ', ' ', 'x'},
137 /*DESTROY*/ {'x', 'x', ' ', ' ', 'x'},
138 /*FLUSH*/ {'x', 'x', ' ', ' ', 'x'},
139 /*RENAME*/ {'x', 'x', ' ', ' ', 'x'},
140 /*SWAP*/ {'x', 'x', ' ', ' ', 'x'},
141 /*LIST*/ {' ', ' ', 'x', ' ', ' '},
142 /*SAVE*/ {'x', 'x', ' ', ' ', 'x'},
143 /*RESTORE*/ {'x', 'x', ' ', ' ', 'x'},
144 /*ADD*/ {'x', 'x', ' ', ' ', 'x'},
145 /*DEL*/ {'x', 'x', ' ', ' ', 'x'},
146 /*TEST*/ {'x', 'x', ' ', ' ', 'x'},
147 /*HELP*/ {'x', 'x', 'x', ' ', 'x'},
148 /*VERSION*/ {'x', 'x', 'x', ' ', 'x'},
151 /* Main parser function */
152 int parse_commandline(int argc, char *argv[]);
154 static void exit_tryhelp(int status)
156 fprintf(stderr,
157 "Try `%s -H' or '%s --help' for more information.\n",
158 program_name, program_name);
159 exit(status);
162 void exit_error(int status, const char *msg, ...)
164 if (!option_quiet) {
165 va_list args;
167 va_start(args, msg);
168 fprintf(stderr, "%s v%s: ", program_name, program_version);
169 vfprintf(stderr, msg, args);
170 va_end(args);
171 fprintf(stderr, "\n");
172 if (restore_line)
173 fprintf(stderr, "Restore failed at line %u:\n", restore_line);
174 if (status == PARAMETER_PROBLEM)
175 exit_tryhelp(status);
176 if (status == VERSION_PROBLEM)
177 fprintf(stderr,
178 "Perhaps %s or your kernel needs to be upgraded.\n",
179 program_name);
182 exit(status);
185 static void ipset_printf(const char *msg, ...)
187 if (!option_quiet) {
188 va_list args;
190 va_start(args, msg);
191 vfprintf(stdout, msg, args);
192 va_end(args);
193 fprintf(stdout, "\n");
197 static void generic_opt_check(int command, unsigned int options)
199 int i, j, legal = 0;
201 /* Check that commands are valid with options. Complicated by the
202 * fact that if an option is legal with *any* command given, it is
203 * legal overall (ie. -z and -l).
205 for (i = 0; i < NUMBER_OF_OPT; i++) {
206 legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
208 for (j = 1; j <= NUMBER_OF_CMD; j++) {
209 if (command != j)
210 continue;
212 if (!(options & (1 << i))) {
213 if (commands_v_options[j-1][i] == '+')
214 exit_error(PARAMETER_PROBLEM,
215 "You need to supply the `-%c' "
216 "option for this command\n",
217 optflags[i]);
218 } else {
219 if (commands_v_options[j-1][i] != 'x')
220 legal = 1;
221 else if (legal == 0)
222 legal = -1;
225 if (legal == -1)
226 exit_error(PARAMETER_PROBLEM,
227 "Illegal option `-%c' with this command\n",
228 optflags[i]);
232 static char opt2char(unsigned int option)
234 const char *ptr;
235 for (ptr = optflags; option > 1; option >>= 1, ptr++);
237 return *ptr;
240 static char cmd2char(int cmd)
242 if (cmd <= CMD_NONE || cmd > NUMBER_OF_CMD)
243 return ' ';
245 return cmdflags[cmd];
248 /* From iptables.c ... */
249 static char *get_modprobe(void)
251 int procfile;
252 char *ret;
254 #define PROCFILE_BUFSIZ 1024
255 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
256 if (procfile < 0)
257 return NULL;
259 ret = (char *) malloc(PROCFILE_BUFSIZ);
260 if (ret) {
261 memset(ret, 0, PROCFILE_BUFSIZ);
262 switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
263 case -1: goto fail;
264 case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */
265 default: ; /* nothing */
267 if (ret[strlen(ret)-1]=='\n')
268 ret[strlen(ret)-1]=0;
269 close(procfile);
270 return ret;
272 fail:
273 free(ret);
274 close(procfile);
275 return NULL;
278 static int ipset_insmod(const char *modname, const char *modprobe)
280 char *buf = NULL;
281 char *argv[3];
282 struct stat junk;
283 int status;
285 if (!stat(modprobe, &junk)) {
286 /* Try to read out of the kernel */
287 buf = get_modprobe();
288 if (!buf)
289 return -1;
290 modprobe = buf;
293 switch (fork()) {
294 case 0:
295 argv[0] = (char *) modprobe;
296 argv[1] = (char *) modname;
297 argv[2] = NULL;
298 execv(argv[0], argv);
300 /* Should not reach */
301 exit(1);
302 case -1:
303 return -1;
305 default: /* parent */
306 wait(&status);
309 free(buf);
311 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
312 return 0;
313 return -1;
316 static int kernel_getsocket(void)
318 int sockfd = -1;
320 sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
321 if (sockfd < 0)
322 exit_error(OTHER_PROBLEM,
323 "You need to be root to perform this command.");
325 return sockfd;
328 static void kernel_error(unsigned cmd, int err)
330 unsigned int i;
331 struct translate_error {
332 int err;
333 unsigned cmd;
334 const char *message;
335 } table[] =
336 { /* Generic error codes */
337 { EPERM, 0, "Missing capability" },
338 { EBADF, 0, "Invalid socket option" },
339 { EINVAL, 0, "Size mismatch for expected socket data" },
340 { ENOMEM, 0, "Not enough memory" },
341 { EFAULT, 0, "Failed to copy data" },
342 { EPROTO, 0, "ipset kernel/userspace version mismatch" },
343 { EBADMSG, 0, "Unknown command" },
344 /* Per command error codes */
345 /* Reserved ones for add/del/test to handle internally:
346 * EEXIST
348 { ENOENT, CMD_CREATE, "Unknown set type" },
349 { ENOENT, 0, "Unknown set" },
350 { EAGAIN, 0, "Sets are busy, try again later" },
351 { ERANGE, CMD_CREATE, "No free slot remained to add a new set" },
352 { ERANGE, 0, "IP/port/element is outside of the set or set is full" },
353 { ENOEXEC, CMD_CREATE, "Invalid parameters to create a set" },
354 { ENOEXEC, CMD_SWAP, "Sets with different types cannot be swapped" },
355 { EEXIST, CMD_CREATE, "Set already exists" },
356 { EEXIST, CMD_RENAME, "Set with new name already exists" },
357 { EEXIST, 0, "Set specified as element does not exist" },
358 { EBUSY, 0, "Set is in use, operation not permitted" },
360 for (i = 0; i < sizeof(table)/sizeof(struct translate_error); i++) {
361 if ((table[i].cmd == cmd || table[i].cmd == 0)
362 && table[i].err == err)
363 exit_error(err == EPROTO ? VERSION_PROBLEM
364 : OTHER_PROBLEM,
365 table[i].message);
367 exit_error(OTHER_PROBLEM, "Error from kernel: %s", strerror(err));
370 static inline int wrapped_getsockopt(void *data, socklen_t *size)
372 int res;
373 int sockfd = kernel_getsocket();
375 /* Send! */
376 res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
377 if (res != 0
378 && errno == ENOPROTOOPT
379 && ipset_insmod("ip_set", "/sbin/modprobe") == 0)
380 res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
381 DP("res=%d errno=%d", res, errno);
383 return res;
386 static inline int wrapped_setsockopt(void *data, socklen_t size)
388 int res;
389 int sockfd = kernel_getsocket();
391 /* Send! */
392 res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
393 if (res != 0
394 && errno == ENOPROTOOPT
395 && ipset_insmod("ip_set", "/sbin/modprobe") == 0)
396 res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
397 DP("res=%d errno=%d", res, errno);
399 return res;
402 static void kernel_getfrom(unsigned cmd, void *data, socklen_t * size)
404 int res = wrapped_getsockopt(data, size);
406 if (res != 0)
407 kernel_error(cmd, errno);
410 static int kernel_sendto_handleerrno(unsigned cmd,
411 void *data, socklen_t size)
413 int res = wrapped_setsockopt(data, size);
415 if (res != 0) {
416 if (errno == EEXIST)
417 return -1;
418 else
419 kernel_error(cmd, errno);
422 return 0; /* all ok */
425 static void kernel_sendto(unsigned cmd, void *data, size_t size)
427 int res = wrapped_setsockopt(data, size);
429 if (res != 0)
430 kernel_error(cmd, errno);
433 static int kernel_getfrom_handleerrno(unsigned cmd, void *data, socklen_t *size)
435 int res = wrapped_getsockopt(data, size);
437 if (res != 0) {
438 if (errno == EAGAIN)
439 return -1;
440 else
441 kernel_error(cmd, errno);
444 return 0; /* all ok */
447 static void check_protocolversion(void)
449 struct ip_set_req_version req_version;
450 socklen_t size = sizeof(struct ip_set_req_version);
451 int res;
453 if (protocol_version)
454 return;
456 req_version.op = IP_SET_OP_VERSION;
457 res = wrapped_getsockopt(&req_version, &size);
459 if (res != 0)
460 exit_error(OTHER_PROBLEM,
461 "Couldn't verify kernel module version!");
463 if (!(req_version.version == IP_SET_PROTOCOL_VERSION
464 || req_version.version == IP_SET_PROTOCOL_UNALIGNED))
465 exit_error(OTHER_PROBLEM,
466 "Kernel ip_set module is of protocol version %u."
467 "I'm of protocol version %u.\n"
468 "Please upgrade your kernel and/or ipset(8) utillity.",
469 req_version.version, IP_SET_PROTOCOL_VERSION);
470 protocol_version = req_version.version;
473 static void set_command(int *cmd, int newcmd)
475 if (*cmd != CMD_NONE)
476 exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n",
477 cmd2char(*cmd), cmd2char(newcmd));
478 *cmd = newcmd;
481 static void add_option(unsigned int *options, unsigned int option)
483 if (*options & option)
484 exit_error(PARAMETER_PROBLEM,
485 "multiple -%c flags not allowed",
486 opt2char(option));
487 *options |= option;
490 void *ipset_malloc(size_t size)
492 void *p;
494 if (size == 0)
495 return NULL;
497 if ((p = malloc(size)) == NULL) {
498 perror("ipset: not enough memory");
499 exit(1);
501 return p;
504 char *ipset_strdup(const char *s)
506 char *p;
508 if ((p = strdup(s)) == NULL) {
509 perror("ipset: not enough memory");
510 exit(1);
512 return p;
515 void ipset_free(void *data)
517 if (data == NULL)
518 return;
520 free(data);
523 static struct option *merge_options(struct option *oldopts,
524 const struct option *newopts,
525 int *option_offset)
527 unsigned int num_old, num_new, i;
528 struct option *merge;
530 for (num_old = 0; oldopts[num_old].name; num_old++);
531 for (num_new = 0; newopts[num_new].name; num_new++);
533 global_option_offset += OPTION_OFFSET;
534 *option_offset = global_option_offset;
536 merge = ipset_malloc(sizeof(struct option) * (num_new + num_old + 1));
537 memcpy(merge, oldopts, num_old * sizeof(struct option));
538 for (i = 0; i < num_new; i++) {
539 merge[num_old + i] = newopts[i];
540 merge[num_old + i].val += *option_offset;
542 memset(merge + num_old + num_new, 0, sizeof(struct option));
544 return merge;
547 static char *ip_tohost(const struct in_addr *addr)
549 struct hostent *host;
551 if ((host = gethostbyaddr((char *) addr,
552 sizeof(struct in_addr),
553 AF_INET)) != NULL) {
554 DP("%s", host->h_name);
555 return (char *) host->h_name;
558 return (char *) NULL;
561 static char *ip_tonetwork(const struct in_addr *addr)
563 struct netent *net;
565 if ((net = getnetbyaddr(ntohl(addr->s_addr),
566 AF_INET)) != NULL) {
567 DP("%s", net->n_name);
568 return (char *) net->n_name;
571 return (char *) NULL;
574 /* Return a string representation of an IP address.
575 * Please notice that a pointer to static char* area is returned.
577 char *ip_tostring(ip_set_ip_t ip, unsigned options)
579 struct in_addr addr;
580 addr.s_addr = htonl(ip);
582 if (!(options & OPT_NUMERIC)) {
583 char *name;
584 if ((name = ip_tohost(&addr)) != NULL ||
585 (name = ip_tonetwork(&addr)) != NULL)
586 return name;
589 return inet_ntoa(addr);
592 char *ip_tostring_numeric(ip_set_ip_t ip)
594 return ip_tostring(ip, OPT_NUMERIC);
597 /* Fills the 'ip' with the parsed ip or host in host byte order */
598 void parse_ip(const char *str, ip_set_ip_t * ip)
600 struct hostent *host;
601 struct in_addr addr;
603 DP("%s", str);
605 if (inet_aton(str, &addr) != 0) {
606 *ip = ntohl(addr.s_addr); /* We want host byte order */
607 return;
610 host = gethostbyname(str);
611 if (host != NULL) {
612 if (host->h_addrtype != AF_INET ||
613 host->h_length != sizeof(struct in_addr))
614 exit_error(PARAMETER_PROBLEM,
615 "host/network `%s' not an internet name",
616 str);
617 if (host->h_addr_list[1] != 0)
618 exit_error(PARAMETER_PROBLEM,
619 "host/network `%s' resolves to serveral ip-addresses. "
620 "Please specify one.", str);
622 memcpy(&addr, host->h_addr_list[0], sizeof(struct in_addr));
623 *ip = ntohl(addr.s_addr);
624 return;
627 exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", str);
630 /* Fills 'mask' with the parsed mask in host byte order */
631 void parse_mask(const char *str, ip_set_ip_t * mask)
633 struct in_addr addr;
634 int bits;
636 DP("%s", str);
638 if (str == NULL) {
639 /* no mask at all defaults to 32 bits */
640 *mask = 0xFFFFFFFF;
641 return;
643 if (strchr(str, '.') && inet_aton(str, &addr) != 0) {
644 *mask = ntohl(addr.s_addr); /* We want host byte order */
645 return;
647 if (sscanf(str, "%d", &bits) != 1 || bits < 0 || bits > 32)
648 exit_error(PARAMETER_PROBLEM,
649 "invalid mask `%s' specified", str);
651 DP("bits: %d", bits);
653 *mask = bits != 0 ? 0xFFFFFFFF << (32 - bits) : 0L;
656 /* Combines parse_ip and parse_mask */
657 void
658 parse_ipandmask(const char *str, ip_set_ip_t * ip, ip_set_ip_t * mask)
660 char buf[256];
661 char *p;
663 strncpy(buf, str, sizeof(buf) - 1);
664 buf[255] = '\0';
666 if ((p = strrchr(buf, '/')) != NULL) {
667 *p = '\0';
668 parse_mask(p + 1, mask);
669 } else
670 parse_mask(NULL, mask);
672 /* if a null mask is given, the name is ignored, like in "any/0" */
673 if (*mask == 0U)
674 *ip = 0U;
675 else
676 parse_ip(buf, ip);
678 DP("%s ip: %08X (%s) mask: %08X",
679 str, *ip, ip_tostring_numeric(*ip), *mask);
681 /* Apply the netmask */
682 *ip &= *mask;
684 DP("%s ip: %08X (%s) mask: %08X",
685 str, *ip, ip_tostring_numeric(*ip), *mask);
688 /* Return a string representation of a port
689 * Please notice that a pointer to static char* area is returned
690 * and we assume TCP protocol.
692 char *port_tostring(ip_set_ip_t port, unsigned options)
694 struct servent *service;
695 static char name[] = "65535";
697 if (!(options & OPT_NUMERIC)) {
698 if ((service = getservbyport(htons(port), "tcp")))
699 return service->s_name;
701 sprintf(name, "%u", port);
702 return name;
706 string_to_number(const char *str, unsigned int min, unsigned int max,
707 ip_set_ip_t *port)
709 unsigned long number;
710 char *end;
712 /* Handle hex, octal, etc. */
713 errno = 0;
714 number = strtoul(str, &end, 0);
715 if (*end == '\0' && end != str) {
716 /* we parsed a number, let's see if we want this */
717 if (errno != ERANGE && min <= number && number <= max) {
718 *port = number;
719 return 0;
722 return -1;
725 static int
726 string_to_port(const char *str, ip_set_ip_t *port)
728 struct servent *service;
730 if ((service = getservbyname(str, "tcp")) != NULL) {
731 *port = ntohs((uint16_t) service->s_port);
732 return 0;
734 return -1;
737 /* Fills the 'ip' with the parsed port in host byte order */
738 void parse_port(const char *str, ip_set_ip_t *port)
740 if ((string_to_number(str, 0, 65535, port) != 0)
741 && (string_to_port(str, port) != 0))
742 exit_error(PARAMETER_PROBLEM,
743 "Invalid TCP port `%s' specified", str);
747 * Settype functions
749 static struct settype *settype_find(const char *typename)
751 struct settype *runner = all_settypes;
753 DP("%s", typename);
755 while (runner != NULL) {
756 if (STREQ(runner->typename, typename))
757 return runner;
759 runner = runner->next;
762 return NULL; /* not found */
765 static struct settype *settype_load(const char *typename)
767 char path[sizeof(IPSET_LIB_DIR) + sizeof(IPSET_LIB_NAME) +
768 strlen(typename)];
769 struct settype *settype;
771 /* do some search in list */
772 settype = settype_find(typename);
773 if (settype != NULL)
774 return settype; /* found */
776 /* Else we have to load it */
777 sprintf(path, IPSET_LIB_DIR IPSET_LIB_NAME, typename);
779 if (dlopen(path, RTLD_NOW)) {
780 /* Found library. */
782 settype = settype_find(typename);
784 if (settype != NULL)
785 return settype;
788 /* Can't load the settype */
789 exit_error(PARAMETER_PROBLEM,
790 "Couldn't load settype `%s':%s\n",
791 typename, dlerror());
793 return NULL; /* Never executed, but keep compilers happy */
796 static char *check_set_name(char *setname)
798 if (strlen(setname) > IP_SET_MAXNAMELEN - 1)
799 exit_error(PARAMETER_PROBLEM,
800 "Setname '%s' too long, max %d characters.",
801 setname, IP_SET_MAXNAMELEN - 1);
803 return setname;
806 static struct settype *check_set_typename(const char *typename)
808 if (strlen(typename) > IP_SET_MAXNAMELEN - 1)
809 exit_error(PARAMETER_PROBLEM,
810 "Typename '%s' too long, max %d characters.",
811 typename, IP_SET_MAXNAMELEN - 1);
813 return settype_load(typename);
816 #define MAX(a,b) ((a) > (b) ? (a) : (b))
818 /* Register a new set type */
819 void settype_register(struct settype *settype)
821 struct settype *chk;
822 size_t size;
824 DP("%s", settype->typename);
826 /* Check if this typename already exists */
827 chk = settype_find(settype->typename);
829 if (chk != NULL)
830 exit_error(OTHER_PROBLEM,
831 "Set type '%s' already registered!\n",
832 settype->typename);
834 /* Check version */
835 if (settype->protocol_version != IP_SET_PROTOCOL_VERSION)
836 exit_error(OTHER_PROBLEM,
837 "Set type %s is of wrong protocol version %u!"
838 " I'm of version %u.\n", settype->typename,
839 settype->protocol_version,
840 IP_SET_PROTOCOL_VERSION);
842 /* Initialize internal data */
843 settype->header = ipset_malloc(settype->header_size);
844 size = MAX(settype->create_size, settype->adt_size);
845 settype->data = ipset_malloc(size);
847 /* Insert first */
848 settype->next = all_settypes;
849 all_settypes = settype;
851 DP("%s registered", settype->typename);
854 /* Find set functions */
855 struct set *set_find_byid(ip_set_id_t id)
857 struct set *set = NULL;
858 ip_set_id_t i;
860 for (i = 0; i < max_sets; i++)
861 if (set_list[i] && set_list[i]->id == id) {
862 set = set_list[i];
863 break;
866 if (set == NULL)
867 exit_error(PARAMETER_PROBLEM,
868 "Set identified by id %u is not found", id);
869 return set;
872 struct set *set_find_byname(const char *name)
874 struct set *set = NULL;
875 ip_set_id_t i;
877 for (i = 0; i < max_sets; i++)
878 if (set_list[i] != NULL && STREQ(set_list[i]->name, name)) {
879 set = set_list[i];
880 break;
882 if (set == NULL)
883 exit_error(PARAMETER_PROBLEM,
884 "Set %s is not found", name);
885 return set;
888 static ip_set_id_t set_find_free_index(const char *name)
890 ip_set_id_t i, idx = IP_SET_INVALID_ID;
892 for (i = 0; i < max_sets; i++) {
893 if (idx == IP_SET_INVALID_ID
894 && set_list[i] == NULL)
895 idx = i;
896 if (set_list[i] != NULL && STREQ(set_list[i]->name, name))
897 exit_error(PARAMETER_PROBLEM,
898 "Set %s is already defined, cannot be restored",
899 name);
902 if (idx == IP_SET_INVALID_ID)
903 exit_error(PARAMETER_PROBLEM,
904 "Set %s cannot be restored, "
905 "max number of set %u reached",
906 name, max_sets);
908 return idx;
912 * Send create set order to kernel
914 static void set_create(const char *name, struct settype *settype)
916 struct ip_set_req_create req_create;
917 size_t size;
918 void *data;
920 DP("%s %s", name, settype->typename);
922 req_create.op = IP_SET_OP_CREATE;
923 req_create.version = protocol_version;
924 strcpy(req_create.name, name);
925 strcpy(req_create.typename, settype->typename);
927 /* Final checks */
928 settype->create_final(settype->data, settype->flags);
930 /* Alloc memory for the data to send */
931 size = sizeof(struct ip_set_req_create) + settype->create_size;
932 data = ipset_malloc(size);
934 /* Add up ip_set_req_create and the settype data */
935 memcpy(data, &req_create, sizeof(struct ip_set_req_create));
936 memcpy(data + sizeof(struct ip_set_req_create),
937 settype->data, settype->create_size);
939 kernel_sendto(CMD_CREATE, data, size);
940 free(data);
943 static void set_restore_create(const char *name, struct settype *settype)
945 struct set *set;
947 DP("%s %s %zu %zu %u %u", name, settype->typename,
948 restore_offset, sizeof(struct ip_set_restore),
949 settype->create_size, restore_size);
951 /* Sanity checking */
952 if (restore_offset
953 + ALIGNED(sizeof(struct ip_set_restore))
954 + ALIGNED(settype->create_size) > restore_size)
955 exit_error(PARAMETER_PROBLEM,
956 "Giving up, restore file is screwed up!");
958 /* Final checks */
959 settype->create_final(settype->data, settype->flags);
961 /* Fill out restore_data */
962 restore_set = (struct ip_set_restore *)
963 (restore_data + restore_offset);
964 strcpy(restore_set->name, name);
965 strcpy(restore_set->typename, settype->typename);
966 restore_set->index = set_find_free_index(name);
967 restore_set->header_size = settype->create_size;
968 restore_set->members_size = 0;
970 DP("name %s, restore index %u", restore_set->name, restore_set->index);
971 /* Add settype data */
973 restore_offset += ALIGNED(sizeof(struct ip_set_restore));
974 memcpy(restore_data + restore_offset, settype->data, settype->create_size);
976 restore_offset += ALIGNED(settype->create_size);
977 DP("restore_offset: %zu", restore_offset);
979 /* Add set to set_list */
980 set = ipset_malloc(sizeof(struct set));
981 strcpy(set->name, name);
982 set->settype = settype;
983 set->index = restore_set->index;
984 set_list[restore_set->index] = set;
988 * Send destroy/flush order to kernel for one or all sets
990 static void set_destroy(const char *name, unsigned op, unsigned cmd)
992 struct ip_set_req_std req;
994 DP("%s %s", cmd == CMD_DESTROY ? "destroy" : "flush", name);
996 req.op = op;
997 req.version = protocol_version;
998 strcpy(req.name, name);
1000 kernel_sendto(cmd, &req, sizeof(struct ip_set_req_std));
1004 * Send rename/swap order to kernel
1006 static void set_rename(const char *name, const char *newname,
1007 unsigned op, unsigned cmd)
1009 struct ip_set_req_create req;
1011 DP("%s %s %s", cmd == CMD_RENAME ? "rename" : "swap",
1012 name, newname);
1014 req.op = op;
1015 req.version = protocol_version;
1016 strcpy(req.name, name);
1017 strcpy(req.typename, newname);
1019 kernel_sendto(cmd, &req,
1020 sizeof(struct ip_set_req_create));
1024 * Send MAX_SETS, LIST_SIZE and/or SAVE_SIZE orders to kernel
1026 static size_t load_set_list(const char name[IP_SET_MAXNAMELEN],
1027 ip_set_id_t *idx,
1028 unsigned op, unsigned cmd)
1030 void *data = NULL;
1031 struct ip_set_req_max_sets req_max_sets;
1032 struct ip_set_name_list *name_list;
1033 struct set *set;
1034 ip_set_id_t i;
1035 socklen_t size, req_size;
1036 int repeated = 0, res = 0;
1038 DP("%s %s", cmd == CMD_MAX_SETS ? "MAX_SETS"
1039 : cmd == CMD_LIST_SIZE ? "LIST_SIZE"
1040 : "SAVE_SIZE",
1041 name);
1043 tryagain:
1044 if (set_list) {
1045 for (i = 0; i < max_sets; i++)
1046 if (set_list[i])
1047 free(set_list[i]);
1048 free(set_list);
1049 set_list = NULL;
1051 /* Get max_sets */
1052 req_max_sets.op = IP_SET_OP_MAX_SETS;
1053 req_max_sets.version = protocol_version;
1054 strcpy(req_max_sets.set.name, name);
1055 size = sizeof(req_max_sets);
1056 kernel_getfrom(CMD_MAX_SETS, &req_max_sets, &size);
1058 DP("got MAX_SETS: sets %d, max_sets %d",
1059 req_max_sets.sets, req_max_sets.max_sets);
1061 max_sets = req_max_sets.max_sets;
1062 set_list = ipset_malloc(max_sets * sizeof(struct set *));
1063 memset(set_list, 0, max_sets * sizeof(struct set *));
1064 *idx = req_max_sets.set.index;
1066 if (req_max_sets.sets == 0)
1067 /* No sets in kernel */
1068 return 0;
1070 /* Get setnames */
1071 size = req_size = ALIGNED(sizeof(struct ip_set_req_setnames))
1072 + req_max_sets.sets * ALIGNED(sizeof(struct ip_set_name_list));
1073 data = ipset_malloc(size);
1074 ((struct ip_set_req_setnames *) data)->op = op;
1075 ((struct ip_set_req_setnames *) data)->index = *idx;
1077 res = kernel_getfrom_handleerrno(cmd, data, &size);
1079 if (res != 0 || size != req_size) {
1080 free(data);
1081 if (repeated++ < LIST_TRIES)
1082 goto tryagain;
1083 exit_error(OTHER_PROBLEM,
1084 "Tried to get sets from kernel %d times"
1085 " and failed. Please try again when the load on"
1086 " the sets has gone down.", LIST_TRIES);
1089 /* Load in setnames */
1090 size = ALIGNED(sizeof(struct ip_set_req_setnames));
1091 while (size + ALIGNED(sizeof(struct ip_set_name_list)) <= req_size) {
1092 name_list = (struct ip_set_name_list *)
1093 (data + size);
1094 set = ipset_malloc(sizeof(struct set));
1095 strcpy(set->name, name_list->name);
1096 set->index = name_list->index;
1097 set->id = name_list->id;
1098 set->settype = settype_load(name_list->typename);
1099 set_list[name_list->index] = set;
1100 DP("loaded %s, type %s, index %u",
1101 set->name, set->settype->typename, set->index);
1102 size += ALIGNED(sizeof(struct ip_set_name_list));
1104 /* Size to get set members */
1105 size = ((struct ip_set_req_setnames *)data)->size;
1106 free(data);
1108 return size;
1112 * Save operation
1114 static size_t save_set(void *data, size_t offset, size_t len)
1116 struct ip_set_save *set_save =
1117 (struct ip_set_save *) (data + offset);
1118 struct set *set;
1119 struct settype *settype;
1120 size_t used;
1122 DP("offset %zu (%zu/%u/%u), len %zu", offset,
1123 sizeof(struct ip_set_save),
1124 set_save->header_size, set_save->members_size,
1125 len);
1126 if (offset + ALIGNED(sizeof(struct ip_set_save)) > len
1127 || offset + ALIGNED(sizeof(struct ip_set_save))
1128 + set_save->header_size + set_save->members_size > len)
1129 exit_error(OTHER_PROBLEM,
1130 "Save operation failed, try again later.");
1132 DP("index: %u", set_save->index);
1133 if (set_save->index == IP_SET_INVALID_ID) {
1134 /* Marker */
1135 return ALIGNED(sizeof(struct ip_set_save));
1137 set = set_list[set_save->index];
1138 if (!set)
1139 exit_error(OTHER_PROBLEM,
1140 "Save set failed, try again later.");
1141 settype = set->settype;
1143 /* Init set header */
1144 used = ALIGNED(sizeof(struct ip_set_save));
1145 settype->initheader(set, data + offset + used);
1147 /* Print create set */
1148 settype->saveheader(set, OPT_NUMERIC);
1150 /* Print add IPs */
1151 used += set_save->header_size;
1152 settype->saveips(set, data + offset + used,
1153 set_save->members_size, OPT_NUMERIC,
1154 DONT_ALIGN);
1156 return (used + set_save->members_size);
1159 static int try_save_sets(const char name[IP_SET_MAXNAMELEN])
1161 void *data = NULL;
1162 socklen_t size, req_size = 0;
1163 ip_set_id_t idx;
1164 int res = 0;
1165 time_t now = time(NULL);
1167 /* Load set_list from kernel */
1168 size = load_set_list(name, &idx,
1169 IP_SET_OP_SAVE_SIZE, CMD_SAVE);
1171 if (size) {
1172 /* Get sets and print them */
1173 /* Take into account marker */
1174 req_size = (size += ALIGNED(sizeof(struct ip_set_save)));
1175 data = ipset_malloc(size);
1176 ((struct ip_set_req_list *) data)->op = IP_SET_OP_SAVE;
1177 ((struct ip_set_req_list *) data)->index = idx;
1178 res = kernel_getfrom_handleerrno(CMD_SAVE, data, &size);
1180 if (res != 0 || size != req_size) {
1181 DP("Try again: res: %i, size %u, req_size: %u",
1182 res, size, req_size);
1183 free(data);
1184 return -EAGAIN;
1188 printf("# Generated by ipset %s on %s", IPSET_VERSION, ctime(&now));
1189 size = 0;
1190 while (size < req_size) {
1191 DP("size: %u, req_size: %u", size, req_size);
1192 size += save_set(data, size, req_size);
1194 printf("COMMIT\n");
1195 now = time(NULL);
1196 printf("# Completed on %s", ctime(&now));
1197 ipset_free(data);
1198 return res;
1202 * Performs a save to stdout
1204 static void set_save(const char name[IP_SET_MAXNAMELEN])
1206 int i;
1208 DP("%s", name);
1209 for (i = 0; i < LIST_TRIES; i++)
1210 if (try_save_sets(name) == 0)
1211 return;
1213 if (errno == EAGAIN)
1214 exit_error(OTHER_PROBLEM,
1215 "Tried to save sets from kernel %d times"
1216 " and failed. Please try again when the load on"
1217 " the sets has gone down.", LIST_TRIES);
1218 else
1219 kernel_error(CMD_SAVE, errno);
1223 * Restore operation
1226 /* global new argv and argc */
1227 static char *newargv[255];
1228 static int newargc = 0;
1230 /* Build faked argv from parsed line */
1231 static void build_argv(unsigned line, char *buffer) {
1232 char *ptr;
1233 int i;
1235 /* Reset */
1236 for (i = 1; i < newargc; i++)
1237 free(newargv[i]);
1238 newargc = 1;
1240 ptr = strtok(buffer, " \t\n");
1241 newargv[newargc++] = ipset_strdup(ptr);
1242 while ((ptr = strtok(NULL, " \t\n")) != NULL) {
1243 if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
1244 newargv[newargc++] = ipset_strdup(ptr);
1245 else
1246 exit_error(PARAMETER_PROBLEM,
1247 "Line %d is too long to restore\n", line);
1251 static FILE *create_tempfile(void)
1253 char buffer[1024], __tmpdir[] = "/tmp";
1254 char *tmpdir = NULL;
1255 char *filename;
1256 int fd;
1257 FILE *file;
1259 if (!(tmpdir = getenv("TMPDIR")) && !(tmpdir = getenv("TMP")))
1260 tmpdir = __tmpdir;
1261 filename = ipset_malloc(strlen(tmpdir) + strlen(TEMPFILE_PATTERN) + 1);
1262 strcpy(filename, tmpdir);
1263 strcat(filename, TEMPFILE_PATTERN);
1265 (void) umask(077); /* Create with restrictive permissions */
1266 fd = mkstemp(filename);
1267 if (fd == -1)
1268 exit_error(OTHER_PROBLEM, "Could not create temporary file.");
1269 if (!(file = fdopen(fd, "r+")))
1270 exit_error(OTHER_PROBLEM, "Could not open temporary file.");
1271 if (unlink(filename) == -1)
1272 exit_error(OTHER_PROBLEM, "Could not unlink temporary file.");
1273 free(filename);
1275 while (fgets(buffer, sizeof(buffer), stdin)) {
1276 fputs(buffer, file);
1278 fseek(file, 0L, SEEK_SET);
1280 return file;
1284 * Performs a restore from a file
1286 static void set_restore(char *argv0)
1288 char buffer[1024];
1289 char *ptr, *name = NULL;
1290 char cmd = ' ';
1291 int first_pass, i;
1292 struct settype *settype = NULL;
1293 struct ip_set_req_setnames *header;
1294 ip_set_id_t idx;
1295 FILE *in;
1296 int res;
1298 /* Create and store stdin in temporary file */
1299 in = create_tempfile();
1301 /* Load existing sets from kernel */
1302 load_set_list(IPSET_TOKEN_ALL, &idx,
1303 IP_SET_OP_LIST_SIZE, CMD_RESTORE);
1305 restore_line = 0;
1306 restore_size = ALIGNED(sizeof(struct ip_set_req_setnames)); /* header */
1307 DP("restore_size: %u", restore_size);
1308 /* First pass: calculate required amount of data */
1309 while (fgets(buffer, sizeof(buffer), in)) {
1310 restore_line++;
1312 if (buffer[0] == '\n')
1313 continue;
1314 else if (buffer[0] == '#')
1315 continue;
1316 else if (strcmp(buffer, "COMMIT\n") == 0) {
1317 /* Enable restore mode */
1318 restore = 1;
1319 break;
1322 /* -N, -A or -B */
1323 ptr = strtok(buffer, " \t\n");
1324 DP("ptr: %s", ptr);
1325 if (ptr == NULL
1326 || ptr[0] != '-'
1327 || !(ptr[1] == 'N'
1328 || ptr[1] == 'A'
1329 || ptr[1] == 'B')
1330 || ptr[2] != '\0') {
1331 exit_error(PARAMETER_PROBLEM,
1332 "Line %u does not start as a valid restore command\n",
1333 restore_line);
1335 cmd = ptr[1];
1336 /* setname */
1337 ptr = strtok(NULL, " \t\n");
1338 DP("setname: %s", ptr);
1339 if (ptr == NULL)
1340 exit_error(PARAMETER_PROBLEM,
1341 "Missing set name in line %u\n",
1342 restore_line);
1343 DP("cmd %c", cmd);
1344 switch (cmd) {
1345 case 'N': {
1346 name = check_set_name(ptr);
1347 /* settype */
1348 ptr = strtok(NULL, " \t\n");
1349 if (ptr == NULL)
1350 exit_error(PARAMETER_PROBLEM,
1351 "Missing settype in line %u\n",
1352 restore_line);
1353 settype = check_set_typename(ptr);
1354 restore_size += ALIGNED(sizeof(struct ip_set_restore))
1355 + ALIGNED(settype->create_size);
1356 DP("restore_size (N): %u", restore_size);
1357 break;
1359 case 'A': {
1360 if (name == NULL
1361 || strncmp(name, ptr, sizeof(name)) != 0)
1362 exit_error(PARAMETER_PROBLEM,
1363 "Add IP to set %s in line %u without "
1364 "preceding corresponding create set line\n",
1365 ptr, restore_line);
1366 restore_size += ALIGNED(settype->adt_size);
1367 DP("restore_size (A): %u", restore_size);
1368 break;
1370 default: {
1371 exit_error(PARAMETER_PROBLEM,
1372 "Unrecognized restore command in line %u\n",
1373 restore_line);
1375 } /* end of switch */
1377 /* Sanity checking */
1378 if (!restore)
1379 exit_error(PARAMETER_PROBLEM,
1380 "Missing COMMIT line\n");
1381 restore_size += ALIGNED(sizeof(struct ip_set_restore)); /* marker */
1382 DP("restore_size: %u", restore_size);
1383 restore_data = ipset_malloc(restore_size);
1384 header = (struct ip_set_req_setnames *) restore_data;
1385 header->op = IP_SET_OP_RESTORE;
1386 header->size = restore_size;
1387 restore_offset = ALIGNED(sizeof(struct ip_set_req_setnames));
1389 /* Rewind to scan the file again */
1390 fseek(in, 0L, SEEK_SET);
1391 first_pass = restore_line;
1392 restore_line = 0;
1394 /* Initialize newargv/newargc */
1395 newargv[newargc++] = ipset_strdup(argv0);
1397 /* Second pass: build up restore request */
1398 while (fgets(buffer, sizeof(buffer), in)) {
1399 restore_line++;
1401 if (buffer[0] == '\n')
1402 continue;
1403 else if (buffer[0] == '#')
1404 continue;
1405 else if (strcmp(buffer, "COMMIT\n") == 0)
1406 goto do_restore;
1407 DP("restoring: %s", buffer);
1408 /* Build faked argv, argc */
1409 build_argv(restore_line, buffer);
1410 for (i = 0; i < newargc; i++)
1411 DP("argv[%u]: %s", i, newargv[i]);
1413 /* Parse line */
1414 parse_commandline(newargc, newargv);
1416 exit_error(PARAMETER_PROBLEM,
1417 "Broken restore file\n");
1418 do_restore:
1419 if (restore_size == (restore_offset + ALIGNED(sizeof(struct ip_set_restore)))) {
1420 /* No bindings */
1421 struct ip_set_restore *marker =
1422 (struct ip_set_restore *) (restore_data + restore_offset);
1424 marker->index = IP_SET_INVALID_ID;
1425 marker->header_size = marker->members_size = 0;
1426 restore_offset += ALIGNED(sizeof(struct ip_set_restore));
1427 DP("restore marker, restore_offset: %zu", restore_offset);
1429 if (restore_size != restore_offset)
1430 exit_error(PARAMETER_PROBLEM,
1431 "Giving up, restore file is screwed up!");
1432 res = kernel_getfrom_handleerrno(CMD_RESTORE, restore_data, &restore_size);
1434 if (res != 0) {
1435 if (restore_size != sizeof(struct ip_set_req_setnames))
1436 exit_error(PARAMETER_PROBLEM,
1437 "Communication with kernel failed (%u %u)!",
1438 restore_size, sizeof(struct ip_set_req_setnames));
1439 /* Check errors */
1440 header = (struct ip_set_req_setnames *) restore_data;
1441 if (header->size != 0)
1442 exit_error(PARAMETER_PROBLEM,
1443 "Committing restoring failed at line %u!",
1444 header->size);
1449 * Send ADT_GET order to kernel for a set
1451 static struct set *set_adt_get(const char *name)
1453 struct ip_set_req_adt_get req_adt_get;
1454 struct set *set;
1455 socklen_t size;
1457 DP("%s", name);
1459 check_protocolversion();
1461 req_adt_get.op = IP_SET_OP_ADT_GET;
1462 req_adt_get.version = protocol_version;
1463 strcpy(req_adt_get.set.name, name);
1464 size = sizeof(struct ip_set_req_adt_get);
1466 kernel_getfrom(CMD_ADT_GET, (void *) &req_adt_get, &size);
1468 set = ipset_malloc(sizeof(struct set));
1469 strcpy(set->name, name);
1470 set->index = req_adt_get.set.index;
1471 set->settype = settype_load(req_adt_get.typename);
1473 return set;
1477 * Send add/del/test order to kernel for a set
1479 static int set_adtip(struct set *set, const char *adt,
1480 unsigned op, unsigned cmd)
1482 struct ip_set_req_adt *req_adt;
1483 size_t size;
1484 void *data;
1485 int res = 0;
1487 DP("%s -> %s", set->name, adt);
1489 /* Alloc memory for the data to send */
1490 size = ALIGNED(sizeof(struct ip_set_req_adt)) + set->settype->adt_size ;
1491 DP("alloc size %zu", size);
1492 data = ipset_malloc(size);
1494 /* Fill out the request */
1495 req_adt = (struct ip_set_req_adt *) data;
1496 req_adt->op = op;
1497 req_adt->index = set->index;
1498 memcpy(data + ALIGNED(sizeof(struct ip_set_req_adt)),
1499 set->settype->data, set->settype->adt_size);
1501 if (kernel_sendto_handleerrno(cmd, data, size) == -1)
1502 switch (op) {
1503 case IP_SET_OP_ADD_IP:
1504 exit_error(OTHER_PROBLEM, "%s is already in set %s.",
1505 adt, set->name);
1506 break;
1507 case IP_SET_OP_DEL_IP:
1508 exit_error(OTHER_PROBLEM, "%s is not in set %s.",
1509 adt, set->name);
1510 break;
1511 case IP_SET_OP_TEST_IP:
1512 ipset_printf("%s is in set %s.", adt, set->name);
1513 res = 0;
1514 break;
1515 default:
1516 break;
1518 else
1519 switch (op) {
1520 case IP_SET_OP_TEST_IP:
1521 ipset_printf("%s is NOT in set %s.", adt, set->name);
1522 res = 1;
1523 break;
1524 default:
1525 break;
1527 free(data);
1529 return res;
1532 static void set_restore_add(struct set *set, const char *adt UNUSED)
1534 DP("%s %s", set->name, adt);
1535 /* Sanity checking */
1536 if (restore_offset + ALIGNED(set->settype->adt_size) > restore_size)
1537 exit_error(PARAMETER_PROBLEM,
1538 "Giving up, restore file is screwed up!");
1540 memcpy(restore_data + restore_offset,
1541 set->settype->data, set->settype->adt_size);
1542 restore_set->members_size += ALIGNED(set->settype->adt_size);
1543 restore_offset += ALIGNED(set->settype->adt_size);
1545 DP("restore_offset: %zu", restore_offset);
1549 * Print operation
1552 /* Help function to set_list() */
1553 static size_t print_set(void *data, unsigned options)
1555 struct ip_set_list *setlist = data;
1556 struct set *set = set_list[setlist->index];
1557 struct settype *settype = set->settype;
1558 size_t offset;
1560 /* Pretty print the set */
1561 DP("header size: %u, members size: %u",
1562 setlist->header_size, setlist->members_size);
1563 printf("Name: %s\n", set->name);
1564 printf("Type: %s\n", settype->typename);
1565 printf("References: %d\n", setlist->ref);
1567 /* Init header */
1568 offset = ALIGNED(sizeof(struct ip_set_list));
1569 settype->initheader(set, data + offset);
1571 /* Pretty print the type header */
1572 printf("Header:");
1573 settype->printheader(set, options);
1575 /* Pretty print all IPs */
1576 printf("Members:\n");
1577 offset += setlist->header_size;
1578 DP("Aligned: %u, offset: %zu, members_size %u\n", !DONT_ALIGN, offset,
1579 setlist->members_size);
1580 if (options & OPT_SORTED)
1581 settype->printips_sorted(set, data + offset,
1582 setlist->members_size, options,
1583 DONT_ALIGN);
1584 else
1585 settype->printips(set, data + offset,
1586 setlist->members_size, options,
1587 DONT_ALIGN);
1589 printf("\n"); /* One newline between sets */
1591 return (offset + setlist->members_size);
1594 static int try_list_sets(const char name[IP_SET_MAXNAMELEN],
1595 unsigned options)
1597 void *data = NULL;
1598 ip_set_id_t idx;
1599 socklen_t size, req_size;
1600 int res = 0;
1602 /* Default is numeric listing */
1603 if (!(options & (OPT_RESOLVE|OPT_NUMERIC)))
1604 options |= OPT_NUMERIC;
1606 DP("%s", name);
1607 /* Load set_list from kernel */
1608 size = req_size = load_set_list(name, &idx,
1609 IP_SET_OP_LIST_SIZE, CMD_LIST);
1611 if (size) {
1612 /* Get sets and print them */
1613 data = ipset_malloc(size);
1614 ((struct ip_set_req_list *) data)->op = IP_SET_OP_LIST;
1615 ((struct ip_set_req_list *) data)->index = idx;
1616 res = kernel_getfrom_handleerrno(CMD_LIST, data, &size);
1617 DP("get_lists getsockopt() res=%d errno=%d", res, errno);
1619 if (res != 0 || size != req_size) {
1620 free(data);
1621 return -EAGAIN;
1623 size = 0;
1625 while (size != req_size)
1626 size += print_set(data + size, options);
1628 ipset_free(data);
1629 return res;
1632 /* Print a set or all sets
1633 * All sets: name = NULL
1635 static void list_sets(const char name[IP_SET_MAXNAMELEN], unsigned options)
1637 int i;
1639 DP("%s", name);
1640 for (i = 0; i < LIST_TRIES; i++)
1641 if (try_list_sets(name, options) == 0)
1642 return;
1644 if (errno == EAGAIN)
1645 exit_error(OTHER_PROBLEM,
1646 "Tried to list sets from kernel %d times"
1647 " and failed. Please try again when the load on"
1648 " the sets has gone down.", LIST_TRIES);
1649 else
1650 kernel_error(CMD_LIST, errno);
1653 /* Prints help
1654 * If settype is non null help for that type is printed as well
1656 static void set_help(const struct settype *settype)
1658 printf("%s v%s\n\n"
1659 "Usage: %s -N new-set settype [options]\n"
1660 " %s -[XFLSH] [set] [options]\n"
1661 " %s -[EW] from-set to-set\n"
1662 " %s -[ADT] set IP\n"
1663 " %s -R\n"
1664 " %s -v\n"
1665 " %s -h (print this help information)\n\n",
1666 program_name, program_version,
1667 program_name, program_name, program_name,
1668 program_name, program_name, program_name,
1669 program_name);
1671 printf("Commands:\n"
1672 "Either long or short options are allowed.\n"
1673 " --create -N setname settype <options>\n"
1674 " Create a new set\n"
1675 " --destroy -X [setname]\n"
1676 " Destroy a set or all sets\n"
1677 " --flush -F [setname]\n"
1678 " Flush a set or all sets\n"
1679 " --rename -E from-set to-set\n"
1680 " Rename from-set to to-set\n"
1681 " --swap -W from-set to-set\n"
1682 " Swap the content of two existing sets\n"
1683 " --list -L [setname] [options]\n"
1684 " List the IPs in a set or all sets\n"
1685 " --save -S [setname]\n"
1686 " Save the set or all sets to stdout\n"
1687 " --restore -R [option]\n"
1688 " Restores a saved state\n"
1689 " --add -A setname IP\n"
1690 " Add an IP to a set\n"
1691 " --del -D setname IP\n"
1692 " Deletes an IP from a set\n"
1693 " --test -T setname IP \n"
1694 " Tests if an IP exists in a set.\n"
1695 " --help -H [settype]\n"
1696 " Prints this help, and settype specific help\n"
1697 " --version -V\n"
1698 " Prints version information\n\n"
1699 "Options:\n"
1700 " --sorted -s Numeric sort of the IPs in -L\n"
1701 " --numeric -n Numeric output of addresses in a -L (default)\n"
1702 " --resolve -r Try to resolve addresses in a -L\n"
1703 " --quiet -q Suppress any output to stdout and stderr.\n");
1704 #ifdef IPSET_DEBUG
1705 printf(" --debug -z Enable debugging\n\n");
1706 #else
1707 printf("\n");
1708 #endif
1710 if (settype != NULL) {
1711 printf("Type '%s' specific:\n", settype->typename);
1712 settype->usage();
1716 static int find_cmd(int option)
1718 int i;
1720 for (i = 1; i <= NUMBER_OF_CMD; i++)
1721 if (cmdflags[i] == option)
1722 return i;
1724 return CMD_NONE;
1727 static int parse_adt_cmdline(int command,
1728 const char *name,
1729 char *adt,
1730 struct set **set,
1731 struct settype **settype)
1733 int res = 0;
1735 *set = restore ? set_find_byname(name) : set_adt_get(name);
1737 /* Reset space for adt data */
1738 *settype = (*set)->settype;
1739 memset((*settype)->data, 0, (*settype)->adt_size);
1741 res = (*settype)->adt_parser(command, adt, (*settype)->data);
1743 return res;
1746 /* Main worker function */
1747 int parse_commandline(int argc, char *argv[])
1749 int res = 0;
1750 int command = CMD_NONE;
1751 unsigned options = 0;
1752 int c;
1754 char *name = NULL; /* All except -H, -R */
1755 char *newname = NULL; /* -E, -W */
1756 char *adt = NULL; /* -A, -D, -T */
1757 struct set *set = NULL; /* -A, -D, -T */
1758 struct settype *settype = NULL; /* -N, -H */
1759 char all_sets[] = IPSET_TOKEN_ALL;
1761 struct option *opts = opts_long;
1763 /* Suppress error messages: we may add new options if we
1764 demand-load a protocol. */
1765 opterr = 0;
1766 /* Reset optind to 0 for restore */
1767 optind = 0;
1769 while ((c = getopt_long(argc, argv, opts_short, opts, NULL)) != -1) {
1771 DP("commandline parsed: opt %c (%s)", c, argv[optind]);
1773 switch (c) {
1775 * Command selection
1777 case 'h':
1778 case 'H':{ /* Help: -H [typename [options]] */
1779 check_protocolversion();
1780 set_command(&command, CMD_HELP);
1782 if (optarg)
1783 settype = check_set_typename(optarg);
1784 else if (optind < argc
1785 && argv[optind][0] != '-')
1786 settype = check_set_typename(argv[optind++]);
1788 break;
1791 case 'V':
1792 case 'v': { /* Version */
1793 printf("%s v%s, protocol version %u.\n",
1794 program_name, program_version,
1795 IP_SET_PROTOCOL_VERSION);
1796 check_protocolversion();
1797 printf("Kernel module protocol version %u.\n",
1798 protocol_version);
1799 exit(0);
1802 case 'N':{ /* Create: -N name typename options */
1803 set_command(&command, CMD_CREATE);
1805 name = check_set_name(optarg);
1807 /* Protect reserved names */
1808 if (name[0] == ':')
1809 exit_error(PARAMETER_PROBLEM,
1810 "setname might not start with colon",
1811 cmd2char(CMD_CREATE));
1813 if (optind < argc
1814 && argv[optind][0] != '-')
1815 settype = check_set_typename(argv[optind++]);
1816 else
1817 exit_error(PARAMETER_PROBLEM,
1818 "-%c requires setname and settype",
1819 cmd2char(CMD_CREATE));
1821 DP("merge options");
1822 /* Merge the create options */
1823 opts = merge_options(opts,
1824 settype->create_opts,
1825 &settype->option_offset);
1827 /* Reset space for create data */
1828 memset(settype->data, 0, settype->create_size);
1830 /* Zero the flags */
1831 settype->flags = 0;
1833 DP("call create_init");
1834 /* Call the settype create_init */
1835 settype->create_init(settype->data);
1837 break;
1840 case 'X': /* Destroy */
1841 case 'F': /* Flush */
1842 case 'L': /* List */
1843 case 'S':{ /* Save */
1844 set_command(&command, find_cmd(c));
1846 if (optarg)
1847 name = check_set_name(optarg);
1848 else if (optind < argc
1849 && argv[optind][0] != '-')
1850 name = check_set_name(argv[optind++]);
1851 else
1852 name = all_sets;
1854 break;
1857 case 'R':{ /* Restore */
1858 set_command(&command, find_cmd(c));
1860 break;
1863 case 'E': /* Rename */
1864 case 'W':{ /* Swap */
1865 set_command(&command, find_cmd(c));
1866 name = check_set_name(optarg);
1868 if (optind < argc
1869 && argv[optind][0] != '-')
1870 newname = check_set_name(argv[optind++]);
1871 else
1872 exit_error(PARAMETER_PROBLEM,
1873 "-%c requires a setname "
1874 "and the new name for that set",
1875 cmd2char(CMD_RENAME));
1877 break;
1880 case 'A': /* Add IP */
1881 case 'D': /* Del IP */
1882 case 'T':{ /* Test IP */
1883 set_command(&command, find_cmd(c));
1885 name = check_set_name(optarg);
1887 /* IP */
1888 if (optind < argc
1889 && argv[optind][0] != '-')
1890 adt = argv[optind++];
1891 else
1892 exit_error(PARAMETER_PROBLEM,
1893 "-%c requires setname and IP",
1896 res = parse_adt_cmdline(command, name, adt,
1897 &set, &settype);
1899 if (!res)
1900 exit_error(PARAMETER_PROBLEM,
1901 "Unknown arg `%s'",
1902 argv[optind - 1]);
1904 res = 0;
1905 break;
1908 /* options */
1910 case 'n':
1911 add_option(&options, OPT_NUMERIC);
1912 break;
1914 case 'r':
1915 if (!(options & OPT_NUMERIC))
1916 add_option(&options, OPT_RESOLVE);
1917 break;
1919 case 's':
1920 add_option(&options, OPT_SORTED);
1921 break;
1923 case 'q':
1924 add_option(&options, OPT_QUIET);
1925 option_quiet = 1;
1926 break;
1928 #ifdef IPSET_DEBUG
1929 case 'z': /* debug */
1930 add_option(&options, OPT_DEBUG);
1931 option_debug = 1;
1932 break;
1933 #endif
1935 case 1: /* non option */
1936 printf("Bad argument `%s'\n", optarg);
1937 exit_tryhelp(PARAMETER_PROBLEM);
1938 break; /*always good */
1940 default:{
1941 DP("default");
1943 switch (command) {
1944 case CMD_CREATE:
1945 res = settype->create_parse(
1946 c - settype->option_offset,
1947 argv,
1948 settype->data,
1949 &settype->flags);
1950 break;
1952 default:
1953 res = 0; /* failed */
1954 } /* switch (command) */
1957 if (!res)
1958 exit_error(PARAMETER_PROBLEM,
1959 "Unknown arg `%s'",
1960 argv[optind - 1]);
1962 res = 0;
1965 DP("next arg");
1966 } /* switch */
1968 } /* while( getopt_long() ) */
1971 if (optind < argc)
1972 exit_error(PARAMETER_PROBLEM,
1973 "unknown arguments found on commandline");
1974 if (command == CMD_NONE)
1975 exit_error(PARAMETER_PROBLEM, "no command specified");
1977 /* Check options */
1978 generic_opt_check(command, options);
1980 DP("cmd: %c", cmd2char(command));
1982 check_protocolversion();
1984 switch (command) {
1985 case CMD_CREATE:
1986 DP("CMD_CREATE");
1987 if (restore)
1988 set_restore_create(name, settype);
1989 else
1990 set_create(name, settype);
1991 break;
1993 case CMD_DESTROY:
1994 set_destroy(name, IP_SET_OP_DESTROY, CMD_DESTROY);
1995 break;
1997 case CMD_FLUSH:
1998 set_destroy(name, IP_SET_OP_FLUSH, CMD_FLUSH);
1999 break;
2001 case CMD_RENAME:
2002 set_rename(name, newname, IP_SET_OP_RENAME, CMD_RENAME);
2003 break;
2005 case CMD_SWAP:
2006 set_rename(name, newname, IP_SET_OP_SWAP, CMD_SWAP);
2007 break;
2009 case CMD_LIST:
2010 list_sets(name, options);
2011 break;
2013 case CMD_SAVE:
2014 set_save(name);
2015 break;
2017 case CMD_RESTORE:
2018 set_restore(argv[0]);
2019 break;
2021 case CMD_ADD:
2022 if (restore)
2023 set_restore_add(set, adt);
2024 else
2025 set_adtip(set, adt, IP_SET_OP_ADD_IP, CMD_ADD);
2026 break;
2028 case CMD_DEL:
2029 set_adtip(set, adt, IP_SET_OP_DEL_IP, CMD_DEL);
2030 break;
2032 case CMD_TEST:
2033 res = set_adtip(set, adt, IP_SET_OP_TEST_IP, CMD_TEST);
2034 break;
2036 case CMD_HELP:
2037 set_help(settype);
2038 break;
2040 default:
2041 /* Will never happen */
2042 break; /* Keep the compiler happy */
2044 } /* switch( command ) */
2046 return res;
2050 int main(int argc, char *argv[])
2052 return parse_commandline(argc, argv);