This commit was manufactured by cvs2svn to create branch
[iptables.git] / ipset / ipset.c
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)
4  *
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  */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <time.h>
14 #include <ctype.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <sys/socket.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <arpa/inet.h>
21 #include <stdarg.h>
22 #include <netdb.h>
23 #include <dlfcn.h>
24 #ifndef __always_inline
25 #define __always_inline inline
26 #endif
27 #include <asm/bitops.h>
28
29 #include "ipset.h"
30
31 char program_name[] = "ipset";
32 char program_version[] = IPSET_VERSION;
33
34 /* The list of loaded set types */
35 static struct settype *all_settypes = NULL;
36
37 /* Array of sets */
38 struct set **set_list = NULL;
39 ip_set_id_t max_sets = 0;
40
41 /* Suppress output to stdout and stderr? */
42 static int option_quiet = 0;
43
44 /* Data for restore mode */
45 static int restore = 0;
46 void *restore_data = NULL;
47 struct ip_set_restore *restore_set = NULL;
48 size_t restore_offset = 0, restore_size;
49 unsigned line = 0;
50
51 #define TEMPFILE_PATTERN        "/ipsetXXXXXX"
52
53 #ifdef IPSET_DEBUG
54 int option_debug = 0;
55 #endif
56
57 #define OPTION_OFFSET 256
58 static unsigned int global_option_offset = 0;
59
60 /* Most of these command parsing functions are borrowed from iptables.c */
61
62 static const char cmdflags[] = { ' ',                   /* CMD_NONE */ 
63         'N', 'X', 'F', 'E', 'W', 'L', 'S', 'R', 
64         'A', 'D', 'T', 'B', 'U', 'H', 'V',
65 };
66
67 /* Options */
68 #define OPT_NONE                0x0000U
69 #define OPT_NUMERIC             0x0001U         /* -n */
70 #define OPT_SORTED              0x0002U         /* -s */
71 #define OPT_QUIET               0x0004U         /* -q */
72 #define OPT_DEBUG               0x0008U         /* -z */
73 #define OPT_BINDING             0x0010U         /* -b */
74 #define NUMBER_OF_OPT 5
75 static const char optflags[] =
76     { 'n', 's', 'q', 'z', 'b' };
77
78 static struct option opts_long[] = {
79         /* set operations */
80         {"create",  1, 0, 'N'},
81         {"destroy", 2, 0, 'X'},
82         {"flush",   2, 0, 'F'},
83         {"rename",  1, 0, 'E'},
84         {"swap",    1, 0, 'W'},
85         {"list",    2, 0, 'L'},
86
87         {"save",    2, 0, 'S'},
88         {"restore", 0, 0, 'R'},
89
90         /* ip in set operations */
91         {"add",     1, 0, 'A'},
92         {"del",     1, 0, 'D'},
93         {"test",    1, 0, 'T'},
94         
95         /* binding operations */
96         {"bind",    1, 0, 'B'},
97         {"unbind",  1, 0, 'U'},
98         
99         /* free options */
100         {"numeric", 0, 0, 'n'},
101         {"sorted",  0, 0, 's'},
102         {"quiet",   0, 0, 'q'},
103         {"binding", 1, 0, 'b'},
104
105 #ifdef IPSET_DEBUG
106         /* debug (if compiled with it) */
107         {"debug",   0, 0, 'z'},
108 #endif
109
110         /* version and help */
111         {"version", 0, 0, 'V'},
112         {"help",    2, 0, 'H'},
113
114         /* end */
115         {0}
116 };
117
118 static char opts_short[] =
119     "-N:X::F::E:W:L::S::RA:D:T:B:U:nsqzb:Vh::H::";
120
121 /* Table of legal combinations of commands and options. If any of the
122  * given commands make an option legal, that option is legal.
123  * Key:
124  *  +  compulsory
125  *  x  illegal
126  *     optional
127  */
128
129 static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = {
130         /*            -n   -s   -q   -z   -b  */
131          /*CREATE*/  {'x', 'x', ' ', ' ', 'x'},
132          /*DESTROY*/ {'x', 'x', ' ', ' ', 'x'},
133          /*FLUSH*/   {'x', 'x', ' ', ' ', 'x'},
134          /*RENAME*/  {'x', 'x', ' ', ' ', 'x'},
135          /*SWAP*/    {'x', 'x', ' ', ' ', 'x'},
136          /*LIST*/    {' ', ' ', 'x', ' ', 'x'},
137          /*SAVE*/    {'x', 'x', ' ', ' ', 'x'},
138          /*RESTORE*/ {'x', 'x', ' ', ' ', 'x'},
139          /*ADD*/     {'x', 'x', ' ', ' ', 'x'},
140          /*DEL*/     {'x', 'x', ' ', ' ', 'x'},
141          /*TEST*/    {'x', 'x', ' ', ' ', ' '},
142          /*BIND*/    {'x', 'x', ' ', ' ', '+'},
143          /*UNBIND*/  {'x', 'x', ' ', ' ', 'x'},
144          /*HELP*/    {'x', 'x', 'x', ' ', 'x'},
145          /*VERSION*/ {'x', 'x', 'x', ' ', 'x'},
146 };
147
148 /* Main parser function */
149 int parse_commandline(int argc, char *argv[]);
150
151 void exit_tryhelp(int status)
152 {
153         fprintf(stderr,
154                 "Try `%s -H' or '%s --help' for more information.\n",
155                 program_name, program_name);
156         exit(status);
157 }
158
159 void exit_error(enum exittype status, char *msg, ...)
160 {
161         va_list args;
162
163         if (!option_quiet) {
164                 va_start(args, msg);
165                 fprintf(stderr, "%s v%s: ", program_name, program_version);
166                 vfprintf(stderr, msg, args);
167                 va_end(args);
168                 fprintf(stderr, "\n");
169                 if (line)
170                         fprintf(stderr, "Restore failed at line %u:\n", line);
171                 if (status == PARAMETER_PROBLEM)
172                         exit_tryhelp(status);
173                 if (status == VERSION_PROBLEM)
174                         fprintf(stderr,
175                                 "Perhaps %s or your kernel needs to be upgraded.\n",
176                                 program_name);
177         }
178
179         exit(status);
180 }
181
182 void ipset_printf(char *msg, ...)
183 {
184         va_list args;
185
186         if (!option_quiet) {
187                 va_start(args, msg);
188                 vfprintf(stdout, msg, args);
189                 va_end(args);
190                 fprintf(stdout, "\n");
191         }
192 }
193
194 static void generic_opt_check(int command, int options)
195 {
196         int i, j, legal = 0;
197
198         /* Check that commands are valid with options.  Complicated by the
199          * fact that if an option is legal with *any* command given, it is
200          * legal overall (ie. -z and -l).
201          */
202         for (i = 0; i < NUMBER_OF_OPT; i++) {
203                 legal = 0;      /* -1 => illegal, 1 => legal, 0 => undecided. */
204
205                 for (j = 1; j <= NUMBER_OF_CMD; j++) {
206                         if (command != j)
207                                 continue;
208
209                         if (!(options & (1 << i))) {
210                                 if (commands_v_options[j-1][i] == '+')
211                                         exit_error(PARAMETER_PROBLEM,
212                                                    "You need to supply the `-%c' "
213                                                    "option for this command\n",
214                                                    optflags[i]);
215                         } else {
216                                 if (commands_v_options[j-1][i] != 'x')
217                                         legal = 1;
218                                 else if (legal == 0)
219                                         legal = -1;
220                         }
221                 }
222                 if (legal == -1)
223                         exit_error(PARAMETER_PROBLEM,
224                                    "Illegal option `-%c' with this command\n",
225                                    optflags[i]);
226         }
227 }
228
229 static char opt2char(int option)
230 {
231         const char *ptr;
232         for (ptr = optflags; option > 1; option >>= 1, ptr++);
233
234         return *ptr;
235 }
236
237 static char cmd2char(int option)
238 {
239         if (option <= CMD_NONE || option > NUMBER_OF_CMD)
240                 return ' '; 
241
242         return cmdflags[option];
243 }
244
245 static int kernel_getsocket(void)
246 {
247         int sockfd = -1;
248
249         sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
250         if (sockfd < 0)
251                 exit_error(OTHER_PROBLEM,
252                            "You need to be root to perform this command.");
253
254         return sockfd;
255 }
256
257 static void kernel_error(unsigned cmd, int err)
258 {
259         unsigned int i;
260         struct translate_error {
261                 int err;
262                 unsigned cmd;
263                 char *message;
264         } table[] =
265         { /* Generic error codes */
266           { EPERM, 0, "Missing capability" },
267           { EBADF, 0, "Invalid socket option" },
268           { EINVAL, 0, "Size mismatch for expected socket data" },
269           { ENOMEM, 0, "Not enough memory" },
270           { EFAULT, 0, "Failed to copy data" },
271           { EPROTO, 0, "ipset kernel/userspace version mismatch" },
272           { EBADMSG, 0, "Unknown command" },
273           /* Per command error codes */
274           /* Reserved ones for add/del/test to handle internally: 
275            *    EEXIST
276            */
277           { ENOENT, CMD_CREATE, "Unknown set type" },
278           { ENOENT, 0, "Unknown set" },
279           { EAGAIN, 0, "Sets are busy, try again later" },
280           { ERANGE, CMD_CREATE, "No free slot remained to add a new set" },
281           { ERANGE, 0, "IP/port is outside of the set" },
282           { ENOEXEC, CMD_CREATE, "Invalid parameters to create a set" },
283           { ENOEXEC, CMD_SWAP, "Sets with different types cannot be swapped" },
284           { EEXIST, CMD_CREATE, "Set already exists" },
285           { EEXIST, CMD_RENAME, "Set with new name already exists" },
286           { EBUSY, 0, "Set is in use, operation not permitted" },
287           };
288         for (i = 0; i < sizeof(table)/sizeof(struct translate_error); i++) {
289                 if ((table[i].cmd == cmd || table[i].cmd == 0)
290                     && table[i].err == err)
291                         exit_error(err == EPROTO ? VERSION_PROBLEM
292                                                  : OTHER_PROBLEM, 
293                                    table[i].message);
294         }
295         exit_error(OTHER_PROBLEM, "Error from kernel: %s", strerror(err));
296 }
297
298 static void kernel_getfrom(unsigned cmd, void *data, size_t * size)
299 {
300         int res;
301         int sockfd = kernel_getsocket();
302
303         /* Send! */
304         res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
305
306         DP("res=%d errno=%d", res, errno);
307
308         if (res != 0)
309                 kernel_error(cmd, errno);
310 }
311
312 static int kernel_sendto_handleerrno(unsigned cmd, unsigned op,
313                                      void *data, size_t size)
314 {
315         int res;
316         int sockfd = kernel_getsocket();
317
318         /* Send! */
319         res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
320
321         DP("res=%d errno=%d", res, errno);
322
323         if (res != 0) {
324                 if (errno == EEXIST)
325                         return -1;
326                 else
327                         kernel_error(cmd, errno);
328         }
329
330         return 0; /* all ok */
331 }
332
333 static void kernel_sendto(unsigned cmd, void *data, size_t size)
334 {
335         int res;
336         int sockfd = kernel_getsocket();
337
338         /* Send! */
339         res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
340
341         DP("res=%d errno=%d", res, errno);
342
343         if (res != 0)
344                 kernel_error(cmd, errno);
345 }
346
347 static int kernel_getfrom_handleerrno(unsigned cmd, void *data, size_t * size)
348 {
349         int res;
350         int sockfd = kernel_getsocket();
351
352         /* Send! */
353         res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
354
355         DP("res=%d errno=%d", res, errno);
356
357         if (res != 0) {
358                 if (errno == EAGAIN)
359                         return -1;
360                 else
361                         kernel_error(cmd, errno);
362         }
363
364         return 0; /* all ok */
365 }
366
367 static void check_protocolversion(void)
368 {
369         struct ip_set_req_version req_version;
370         size_t size = sizeof(struct ip_set_req_version);
371         int sockfd = kernel_getsocket();
372         int res;
373
374         req_version.op = IP_SET_OP_VERSION;
375         res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size);
376
377         if (res != 0) {
378                 ipset_printf("I'm of protocol version %u.\n"
379                              "Kernel module is not loaded in, "
380                              "cannot verify kernel version.",
381                              IP_SET_PROTOCOL_VERSION);
382                 return;
383         }
384         if (req_version.version != IP_SET_PROTOCOL_VERSION)
385                 exit_error(OTHER_PROBLEM,
386                            "Kernel ipset code is of protocol version %u."
387                            "I'm of protocol version %u.\n"
388                            "Please upgrade your kernel and/or ipset(8) utillity.",
389                            req_version.version, IP_SET_PROTOCOL_VERSION);
390 }
391
392 static void set_command(int *cmd, const int newcmd)
393 {
394         if (*cmd != CMD_NONE)
395                 exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n",
396                            cmd2char(*cmd), cmd2char(newcmd));
397         *cmd = newcmd;
398 }
399
400 static void add_option(unsigned int *options, unsigned int option)
401 {
402         if (*options & option)
403                 exit_error(PARAMETER_PROBLEM,
404                            "multiple -%c flags not allowed",
405                            opt2char(option));
406         *options |= option;
407 }
408
409 void *ipset_malloc(size_t size)
410 {
411         void *p;
412
413         if (size == 0)
414                 return NULL;
415
416         if ((p = malloc(size)) == NULL) {
417                 perror("ipset: not enough memory");
418                 exit(1);
419         }
420         return p;
421 }
422
423 char *ipset_strdup(const char *s)
424 {
425         char *p;
426
427         if ((p = strdup(s)) == NULL) {
428                 perror("ipset: not enough memory");
429                 exit(1);
430         }
431         return p;
432 }
433
434 void ipset_free(void **data)
435 {
436         if (*data == NULL)
437                 return;
438
439         free(*data);
440         *data = NULL;
441 }
442
443 static struct option *merge_options(struct option *oldopts,
444                                     const struct option *newopts,
445                                     unsigned int *option_offset)
446 {
447         unsigned int num_old, num_new, i;
448         struct option *merge;
449
450         for (num_old = 0; oldopts[num_old].name; num_old++);
451         for (num_new = 0; newopts[num_new].name; num_new++);
452
453         global_option_offset += OPTION_OFFSET;
454         *option_offset = global_option_offset;
455
456         merge = ipset_malloc(sizeof(struct option) * (num_new + num_old + 1));
457         memcpy(merge, oldopts, num_old * sizeof(struct option));
458         for (i = 0; i < num_new; i++) {
459                 merge[num_old + i] = newopts[i];
460                 merge[num_old + i].val += *option_offset;
461         }
462         memset(merge + num_old + num_new, 0, sizeof(struct option));
463
464         return merge;
465 }
466
467 static char *ip_tohost(const struct in_addr *addr)
468 {
469         struct hostent *host;
470
471         if ((host = gethostbyaddr((char *) addr,
472                                   sizeof(struct in_addr),
473                                   AF_INET)) != NULL) {
474                 DP("%s", host->h_name);
475                 return (char *) host->h_name;
476         }
477
478         return (char *) NULL;
479 }
480
481 static char *ip_tonetwork(const struct in_addr *addr)
482 {
483         struct netent *net;
484
485         if ((net = getnetbyaddr((long) ntohl(addr->s_addr), 
486                                 AF_INET)) != NULL) {
487                 DP("%s", net->n_name);
488                 return (char *) net->n_name;
489         }
490
491         return (char *) NULL;
492 }
493
494 /* Return a string representation of an IP address.
495  * Please notice that a pointer to static char* area is returned.
496  */
497 char *ip_tostring(ip_set_ip_t ip, unsigned options)
498 {
499         struct in_addr addr;
500         addr.s_addr = htonl(ip);
501
502         if (!(options & OPT_NUMERIC)) {
503                 char *name;
504                 if ((name = ip_tohost(&addr)) != NULL ||
505                     (name = ip_tonetwork(&addr)) != NULL)
506                         return name;
507         }
508         
509         return inet_ntoa(addr);
510 }
511
512 char *binding_ip_tostring(struct set *set, ip_set_ip_t ip, unsigned options)
513 {
514         return ip_tostring(ip, options);
515 }
516 char *ip_tostring_numeric(ip_set_ip_t ip)
517 {
518         return ip_tostring(ip, OPT_NUMERIC);
519 }
520
521 /* Fills the 'ip' with the parsed ip or host in host byte order */
522 void parse_ip(const char *str, ip_set_ip_t * ip)
523 {
524         struct hostent *host;
525         struct in_addr addr;
526
527         DP("%s", str);
528         
529         if (inet_aton(str, &addr) != 0) {
530                 *ip = ntohl(addr.s_addr);       /* We want host byte order */
531                 return;
532         }
533
534         host = gethostbyname(str);
535         if (host != NULL) {
536                 if (host->h_addrtype != AF_INET ||
537                     host->h_length != sizeof(struct in_addr))
538                         exit_error(PARAMETER_PROBLEM,
539                                    "host/network `%s' not an internet name",
540                                    str);
541                 if (host->h_addr_list[1] != 0)
542                         exit_error(PARAMETER_PROBLEM,
543                                    "host/network `%s' resolves to serveral ip-addresses. "
544                                    "Please specify one.", str);
545
546                 *ip = ntohl(((struct in_addr *) host->h_addr_list[0])->s_addr);
547                 return;
548         }
549
550         exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", str);
551 }
552
553 /* Fills 'mask' with the parsed mask in host byte order */
554 void parse_mask(const char *str, ip_set_ip_t * mask)
555 {
556         struct in_addr addr;
557         unsigned int bits;
558
559         DP("%s", str);
560
561         if (str == NULL) {
562                 /* no mask at all defaults to 32 bits */
563                 *mask = 0xFFFFFFFF;
564                 return;
565         }
566         if (strchr(str, '.') && inet_aton(str, &addr) != 0) {
567                 *mask = ntohl(addr.s_addr);     /* We want host byte order */
568                 return;
569         }
570         if (sscanf(str, "%d", &bits) != 1 || bits < 0 || bits > 32)
571                 exit_error(PARAMETER_PROBLEM,
572                            "invalid mask `%s' specified", str);
573
574         DP("bits: %d", bits);
575
576         *mask = bits != 0 ? 0xFFFFFFFF << (32 - bits) : 0L;
577 }
578
579 /* Combines parse_ip and parse_mask */
580 void
581 parse_ipandmask(const char *str, ip_set_ip_t * ip, ip_set_ip_t * mask)
582 {
583         char buf[256];
584         char *p;
585
586         strncpy(buf, str, sizeof(buf) - 1);
587         buf[255] = '\0';
588
589         if ((p = strrchr(buf, '/')) != NULL) {
590                 *p = '\0';
591                 parse_mask(p + 1, mask);
592         } else
593                 parse_mask(NULL, mask);
594
595         /* if a null mask is given, the name is ignored, like in "any/0" */
596         if (*mask == 0U)
597                 *ip = 0U;
598         else
599                 parse_ip(buf, ip);
600
601         DP("%s ip: %08X (%s) mask: %08X",
602            str, *ip, ip_tostring_numeric(*ip), *mask);
603
604         /* Apply the netmask */
605         *ip &= *mask;
606
607         DP("%s ip: %08X (%s) mask: %08X",
608            str, *ip, ip_tostring_numeric(*ip), *mask);
609 }
610
611 /* Return a string representation of a port
612  * Please notice that a pointer to static char* area is returned
613  * and we assume TCP protocol.
614  */
615 char *port_tostring(ip_set_ip_t port, unsigned options)
616 {
617         struct servent *service;
618         static char name[] = "65535";
619         
620         if (!(options & OPT_NUMERIC)) {
621                 if ((service = getservbyport(htons(port), "tcp")))
622                         return service->s_name;
623         }
624         sprintf(name, "%u", port);
625         return name;
626 }
627
628 int
629 string_to_number(const char *str, unsigned int min, unsigned int max,
630                  ip_set_ip_t *port)
631 {
632         long number;
633         char *end;
634
635         /* Handle hex, octal, etc. */
636         errno = 0;
637         number = strtol(str, &end, 0);
638         if (*end == '\0' && end != str) {
639                 /* we parsed a number, let's see if we want this */
640                 if (errno != ERANGE && min <= number && number <= max) {
641                         *port = number;
642                         return 0;
643                 }
644         }
645         return -1;
646 }
647
648 static int
649 string_to_port(const char *str, ip_set_ip_t *port)
650 {
651         struct servent *service;
652
653         if ((service = getservbyname(str, "tcp")) != NULL) {
654                 *port = ntohs((unsigned short) service->s_port);
655                 return 0;
656         }
657         
658         return -1;
659 }
660
661 /* Fills the 'ip' with the parsed port in host byte order */
662 void parse_port(const char *str, ip_set_ip_t *port)
663 {       
664         if ((string_to_number(str, 0, 65535, port) != 0)
665               && (string_to_port(str, port) != 0))
666                 exit_error(PARAMETER_PROBLEM, 
667                            "Invalid TCP port `%s' specified", str);     
668 }
669
670 /* 
671  * Settype functions
672  */
673 static struct settype *settype_find(const char *typename)
674 {
675         struct settype *runner = all_settypes;
676
677         DP("%s", typename);
678
679         while (runner != NULL) {
680                 if (strncmp(runner->typename, typename, 
681                             IP_SET_MAXNAMELEN) == 0)
682                         return runner;
683
684                 runner = runner->next;
685         }
686
687         return NULL;            /* not found */
688 }
689
690 static struct settype *settype_load(const char *typename)
691 {
692         char path[sizeof(IPSET_LIB_DIR) + sizeof(IPSET_LIB_NAME) +
693                   strlen(typename)];
694         struct settype *settype;
695
696         /* do some search in list */
697         settype = settype_find(typename);
698         if (settype != NULL)
699                 return settype; /* found */
700
701         /* Else we have to load it */
702         sprintf(path, IPSET_LIB_DIR IPSET_LIB_NAME, typename);
703
704         if (dlopen(path, RTLD_NOW)) {
705                 /* Found library. */
706
707                 settype = settype_find(typename);
708
709                 if (settype != NULL)
710                         return settype;
711         }
712
713         /* Can't load the settype */
714         exit_error(PARAMETER_PROBLEM,
715                    "Couldn't load settype `%s':%s\n",
716                    typename, dlerror());
717
718         return NULL;            /* Never executed, but keep compilers happy */
719 }
720
721 static char *check_set_name(char *setname)
722 {
723         if (strlen(setname) > IP_SET_MAXNAMELEN - 1)
724                 exit_error(PARAMETER_PROBLEM,
725                            "Setname '%s' too long, max %d characters.",
726                            setname, IP_SET_MAXNAMELEN - 1);
727
728         return setname;
729 }
730
731 static struct settype *check_set_typename(const char *typename)
732 {
733         if (strlen(typename) > IP_SET_MAXNAMELEN - 1)
734                 exit_error(PARAMETER_PROBLEM,
735                            "Typename '%s' too long, max %d characters.",
736                            typename, IP_SET_MAXNAMELEN - 1);
737
738         return settype_load(typename);
739 }
740
741 #define MAX(a,b)        ((a) > (b) ? (a) : (b))
742
743 /* Register a new set type */
744 void settype_register(struct settype *settype)
745 {
746         struct settype *chk;
747         size_t size;
748
749         DP("%s", settype->typename);
750
751         /* Check if this typename already exists */
752         chk = settype_find(settype->typename);
753
754         if (chk != NULL)
755                 exit_error(OTHER_PROBLEM,
756                            "Set type '%s' already registered!\n",
757                            settype->typename);
758
759         /* Check version */
760         if (settype->protocol_version != IP_SET_PROTOCOL_VERSION)
761                 exit_error(OTHER_PROBLEM,
762                            "Set type %s is of wrong protocol version %u!"
763                            " I'm of version %u.\n", settype->typename,
764                            settype->protocol_version,
765                            IP_SET_PROTOCOL_VERSION);
766
767         /* Initialize internal data */
768         settype->header = ipset_malloc(settype->header_size);
769         size = MAX(settype->create_size, settype->adt_size);
770         settype->data = ipset_malloc(size);
771
772         /* Insert first */
773         settype->next = all_settypes;
774         all_settypes = settype;
775
776         DP("%s registered", settype->typename);
777 }
778
779 /* Find set functions */
780 static struct set *set_find_byid(ip_set_id_t id)
781 {
782         struct set *set = NULL;
783         ip_set_id_t i;
784         
785         for (i = 0; i < max_sets; i++)
786                 if (set_list[i] && set_list[i]->id == id) {
787                         set = set_list[i];
788                         break;
789                 }
790                         
791         if (set == NULL)
792                 exit_error(PARAMETER_PROBLEM,
793                            "Set identified by id %u is not found", id);
794         return set;
795 }
796
797 static struct set *set_find_byname(const char *name)
798 {
799         struct set *set = NULL;
800         ip_set_id_t i;
801         
802         for (i = 0; i < max_sets; i++)
803                 if (set_list[i]
804                     && strncmp(set_list[i]->name, name,
805                                IP_SET_MAXNAMELEN) == 0) {
806                         set = set_list[i];
807                         break;
808                 }
809         if (set == NULL)
810                 exit_error(PARAMETER_PROBLEM,
811                            "Set %s is not found", name);
812         return set;
813 }
814
815 static ip_set_id_t set_find_free_index(const char *name)
816 {
817         ip_set_id_t i, index = IP_SET_INVALID_ID;
818
819         for (i = 0; i < max_sets; i++) {
820                 if (index == IP_SET_INVALID_ID
821                     && set_list[i] == NULL)
822                         index = i;
823                 if (set_list[i] != NULL
824                     && strncmp(set_list[i]->name, name,
825                                IP_SET_MAXNAMELEN) == 0)
826                         exit_error(PARAMETER_PROBLEM,
827                                    "Set %s is already defined, cannot be restored",
828                                    name);
829         }
830                         
831         if (index == IP_SET_INVALID_ID)         
832                 exit_error(PARAMETER_PROBLEM,
833                            "Set %s cannot be restored, "
834                            "max number of set %u reached",
835                            name, max_sets);
836
837         return index;
838 }
839
840 /* 
841  * Send create set order to kernel
842  */
843 static void set_create(const char *name, struct settype *settype)
844 {
845         struct ip_set_req_create req_create;
846         size_t size;
847         void *data;
848
849         DP("%s %s", name, settype->typename);
850
851         req_create.op = IP_SET_OP_CREATE;
852         req_create.version = IP_SET_PROTOCOL_VERSION;
853         strcpy(req_create.name, name);
854         strcpy(req_create.typename, settype->typename);
855
856         /* Final checks */
857         settype->create_final(settype->data, settype->flags);
858
859         /* Alloc memory for the data to send */
860         size = sizeof(struct ip_set_req_create) + settype->create_size;
861         data = ipset_malloc(size);
862
863         /* Add up ip_set_req_create and the settype data */
864         memcpy(data, &req_create, sizeof(struct ip_set_req_create));
865         memcpy(data + sizeof(struct ip_set_req_create),
866                settype->data, settype->create_size);
867
868         kernel_sendto(CMD_CREATE, data, size);
869         free(data);
870 }
871
872 static void set_restore_create(const char *name, struct settype *settype)
873 {
874         struct set *set;
875         
876         DP("%s %s %u %u %u %u", name, settype->typename,
877            restore_offset, sizeof(struct ip_set_restore),
878            settype->create_size, restore_size);
879
880         /* Sanity checking */
881         if (restore_offset
882             + sizeof(struct ip_set_restore)
883             + settype->create_size > restore_size)
884                 exit_error(PARAMETER_PROBLEM,
885                            "Giving up, restore file is screwed up!");
886                            
887         /* Final checks */
888         settype->create_final(settype->data, settype->flags);
889
890         /* Fill out restore_data */
891         restore_set = (struct ip_set_restore *) 
892                         (restore_data + restore_offset);
893         strcpy(restore_set->name, name);
894         strcpy(restore_set->typename, settype->typename);
895         restore_set->index = set_find_free_index(name);
896         restore_set->header_size = settype->create_size;
897         restore_set->members_size = 0;
898
899         DP("name %s, restore index %u", restore_set->name, restore_set->index);
900         /* Add settype data */
901         
902         memcpy(restore_data + restore_offset + sizeof(struct ip_set_restore),
903                settype->data, settype->create_size);
904
905         restore_offset += sizeof(struct ip_set_restore)
906                           + settype->create_size;       
907         
908         /* Add set to set_list */
909         set = ipset_malloc(sizeof(struct set));
910         strcpy(set->name, name);
911         set->settype = settype;
912         set->index = restore_set->index;
913         set_list[restore_set->index] = set;
914 }
915
916 /*
917  * Send destroy/flush order to kernel for one or all sets
918  */
919 static void set_destroy(const char *name, unsigned op, unsigned cmd)
920 {
921         struct ip_set_req_std req;
922
923         DP("%s %s", cmd == CMD_DESTROY ? "destroy" : "flush", name);
924
925         req.op = op;
926         req.version = IP_SET_PROTOCOL_VERSION;
927         strcpy(req.name, name);
928
929         kernel_sendto(cmd, &req, sizeof(struct ip_set_req_std));
930 }
931
932 /*
933  * Send rename/swap order to kernel
934  */
935 static void set_rename(const char *name, const char *newname,
936                        unsigned op, unsigned cmd)
937 {
938         struct ip_set_req_create req;
939
940         DP("%s %s %s", cmd == CMD_RENAME ? "rename" : "swap",
941                        name, newname);
942
943         req.op = op;
944         req.version = IP_SET_PROTOCOL_VERSION;
945         strcpy(req.name, name);
946         strcpy(req.typename, newname);
947
948         kernel_sendto(cmd, &req,
949                       sizeof(struct ip_set_req_create));
950 }
951
952 /*
953  * Send MAX_SETS, LIST_SIZE and/or SAVE_SIZE orders to kernel
954  */
955 static size_t load_set_list(const char name[IP_SET_MAXNAMELEN],
956                             ip_set_id_t *index,
957                             unsigned op, unsigned cmd)
958 {
959         void *data = NULL;
960         struct ip_set_req_max_sets req_max_sets;
961         struct ip_set_name_list *name_list;
962         struct set *set;
963         ip_set_id_t i;
964         size_t size, req_size;
965         int repeated = 0, res = 0;
966
967         DP("%s %s", cmd == CMD_MAX_SETS ? "MAX_SETS"
968                     : cmd == CMD_LIST_SIZE ? "LIST_SIZE"
969                     : "SAVE_SIZE",
970                     name);
971         
972 tryagain:
973         if (set_list) {
974                 for (i = 0; i < max_sets; i++)
975                         if (set_list[i])
976                                 free(set_list[i]);
977                 free(set_list);
978                 set_list = NULL;
979         }
980         /* Get max_sets */
981         req_max_sets.op = IP_SET_OP_MAX_SETS;
982         req_max_sets.version = IP_SET_PROTOCOL_VERSION;
983         strcpy(req_max_sets.set.name, name);
984         size = sizeof(req_max_sets);
985         kernel_getfrom(CMD_MAX_SETS, &req_max_sets, &size);
986
987         DP("got MAX_SETS: sets %d, max_sets %d",
988            req_max_sets.sets, req_max_sets.max_sets);
989
990         max_sets = req_max_sets.max_sets;
991         set_list = ipset_malloc(max_sets * sizeof(struct set *));
992         memset(set_list, 0, max_sets * sizeof(struct set *));
993         *index = req_max_sets.set.index;
994
995         if (req_max_sets.sets == 0)
996                 /* No sets in kernel */
997                 return 0;
998
999         /* Get setnames */
1000         size = req_size = sizeof(struct ip_set_req_setnames) 
1001                           + req_max_sets.sets * sizeof(struct ip_set_name_list);
1002         data = ipset_malloc(size);
1003         ((struct ip_set_req_setnames *) data)->op = op;
1004         ((struct ip_set_req_setnames *) data)->index = *index;
1005
1006         res = kernel_getfrom_handleerrno(cmd, data, &size);
1007
1008         if (res != 0 || size != req_size) {
1009                 free(data);
1010                 if (repeated++ < LIST_TRIES)
1011                         goto tryagain;
1012                 exit_error(OTHER_PROBLEM,
1013                            "Tried to get sets from kernel %d times"
1014                            " and failed. Please try again when the load on"
1015                            " the sets has gone down.", LIST_TRIES);
1016         }
1017                 
1018         /* Load in setnames */
1019         size = sizeof(struct ip_set_req_setnames);                      
1020         while (size + sizeof(struct ip_set_name_list) <= req_size) {
1021                 name_list = (struct ip_set_name_list *)
1022                         (data + size);
1023                 set = ipset_malloc(sizeof(struct set));
1024                 strcpy(set->name, name_list->name);
1025                 set->index = name_list->index;
1026                 set->id = name_list->id;
1027                 set->settype = settype_load(name_list->typename);
1028                 set_list[name_list->index] = set;
1029                 DP("loaded %s, type %s, index %u",
1030                    set->name, set->settype->typename, set->index);
1031                 size += sizeof(struct ip_set_name_list);
1032         }
1033         /* Size to get set members, bindings */
1034         size = ((struct ip_set_req_setnames *)data)->size;
1035         free(data);
1036         
1037         return size;
1038 }
1039
1040 /*
1041  * Save operation
1042  */
1043 static size_t save_bindings(void *data, size_t offset, size_t len)
1044 {
1045         struct ip_set_hash_save *hash =
1046                 (struct ip_set_hash_save *) (data + offset);
1047         struct set *set;
1048
1049         DP("offset %u, len %u", offset, len);
1050         if (offset + sizeof(struct ip_set_hash_save) > len)
1051                 exit_error(OTHER_PROBLEM,
1052                            "Save operation failed, try again later.");
1053
1054         set = set_find_byid(hash->id);
1055         if (!(set && set_list[hash->binding]))
1056                 exit_error(OTHER_PROBLEM,
1057                            "Save binding failed, try again later.");
1058         printf("-B %s %s -b %s\n",
1059                 set->name,
1060                 set->settype->bindip_tostring(set, hash->ip, OPT_NUMERIC),
1061                 set_list[hash->binding]->name);
1062
1063         return sizeof(struct ip_set_hash_save);
1064 }               
1065
1066 static size_t save_set(void *data, int *bindings,
1067                        size_t offset, size_t len)
1068 {
1069         struct ip_set_save *set_save =
1070                 (struct ip_set_save *) (data + offset);
1071         struct set *set;
1072         struct settype *settype;
1073         size_t used;
1074         
1075         DP("offset %u, len %u", offset, len);
1076         if (offset + sizeof(struct ip_set_save) > len
1077             || offset + sizeof(struct ip_set_save)
1078                + set_save->header_size + set_save->members_size > len)
1079                 exit_error(OTHER_PROBLEM,
1080                            "Save operation failed, try again later.");
1081
1082         if (set_save->index == IP_SET_INVALID_ID) {
1083                 /* Marker */
1084                 *bindings = 1;
1085                 return sizeof(struct ip_set_save);
1086         }
1087         set = set_list[set_save->index];
1088         if (!set)
1089                 exit_error(OTHER_PROBLEM,
1090                            "Save set failed, try again later.");
1091         settype = set->settype;
1092
1093         /* Init set header */
1094         used = sizeof(struct ip_set_save);
1095         settype->initheader(set, data + offset + used);
1096
1097         /* Print create set */
1098         settype->saveheader(set, OPT_NUMERIC);
1099
1100         /* Print add IPs */
1101         used += set_save->header_size;
1102         settype->saveips(set, data + offset + used,
1103                          set_save->members_size, OPT_NUMERIC);
1104
1105         return (used + set_save->members_size);
1106 }
1107
1108 static size_t save_default_bindings(void *data, int *bindings)
1109 {
1110         struct ip_set_save *set_save = (struct ip_set_save *) data;
1111         struct set *set;
1112         
1113         if (set_save->index == IP_SET_INVALID_ID) {
1114                 /* Marker */
1115                 *bindings = 1;
1116                 return sizeof(struct ip_set_save);
1117         }
1118
1119         set = set_list[set_save->index];
1120         DP("%s, binding %u", set->name, set_save->binding);
1121         if (set_save->binding != IP_SET_INVALID_ID) {
1122                 if (!set_list[set_save->binding])
1123                         exit_error(OTHER_PROBLEM,
1124                                    "Save set failed, try again later.");
1125
1126                 printf("-B %s %s -b %s\n",
1127                         set->name, IPSET_TOKEN_DEFAULT, 
1128                         set_list[set_save->binding]->name);
1129         }
1130         return (sizeof(struct ip_set_save)
1131                 + set_save->header_size
1132                 + set_save->members_size);
1133 }
1134
1135 static int try_save_sets(const char name[IP_SET_MAXNAMELEN])
1136 {
1137         void *data = NULL;
1138         size_t size, req_size = 0;
1139         ip_set_id_t index;
1140         int res = 0, bindings = 0;
1141         time_t now = time(NULL);
1142
1143         /* Load set_list from kernel */
1144         size = load_set_list(name, &index,
1145                              IP_SET_OP_SAVE_SIZE, CMD_SAVE);
1146         
1147         if (size) {
1148                 /* Get sets, bindings and print them */
1149                 /* Take into account marker */
1150                 req_size = (size += sizeof(struct ip_set_save));
1151                 data = ipset_malloc(size);
1152                 ((struct ip_set_req_list *) data)->op = IP_SET_OP_SAVE;
1153                 ((struct ip_set_req_list *) data)->index = index;
1154                 res = kernel_getfrom_handleerrno(CMD_SAVE, data, &size);
1155
1156                 if (res != 0 || size != req_size) {
1157                         free(data);
1158                         return -EAGAIN;
1159                 }
1160         }
1161
1162         printf("# Generated by ipset %s on %s", IPSET_VERSION, ctime(&now));
1163         size = 0;
1164         while (size < req_size) {
1165                 DP("size: %u, req_size: %u", size, req_size);
1166                 if (bindings)
1167                         size += save_bindings(data, size, req_size);
1168                 else
1169                         size += save_set(data, &bindings, size, req_size);
1170         }
1171         /* Re-read data to save default bindings */
1172         bindings = 0;
1173         size = 0;
1174         while (size < req_size && bindings == 0)
1175                 size += save_default_bindings(data + size, &bindings);
1176
1177         printf("COMMIT\n");
1178         now = time(NULL);
1179         printf("# Completed on %s", ctime(&now));
1180         ipset_free(&data);
1181         return res;
1182 }
1183
1184 /*
1185  * Performs a save to stdout
1186  */
1187 static void set_save(const char name[IP_SET_MAXNAMELEN])
1188 {
1189         int i;
1190
1191         DP("%s", name);
1192         for (i = 0; i < LIST_TRIES; i++)
1193                 if (try_save_sets(name) == 0)
1194                         return;
1195
1196         if (errno == EAGAIN)
1197                 exit_error(OTHER_PROBLEM,
1198                            "Tried to save sets from kernel %d times"
1199                            " and failed. Please try again when the load on"
1200                            " the sets has gone down.", LIST_TRIES);
1201         else
1202                 kernel_error(CMD_SAVE, errno);
1203 }
1204
1205 /*
1206  * Restore operation
1207  */
1208
1209 /* global new argv and argc */
1210 static char *newargv[255];
1211 static int newargc = 0;
1212
1213 /* Build faked argv from parsed line */
1214 static void build_argv(int line, char *buffer) {
1215         char *ptr;
1216         int i;
1217
1218         /* Reset */     
1219         for (i = 1; i < newargc; i++)
1220                 free(newargv[i]);
1221         newargc = 1;
1222
1223         ptr = strtok(buffer, " \t\n");
1224         newargv[newargc++] = ipset_strdup(ptr);
1225         while ((ptr = strtok(NULL, " \t\n")) != NULL) {
1226                 if ((newargc + 1) < sizeof(newargv)/sizeof(char *))
1227                         newargv[newargc++] = ipset_strdup(ptr);
1228                 else
1229                         exit_error(PARAMETER_PROBLEM,
1230                                    "Line %d is too long to restore\n", line);
1231         }
1232 }
1233
1234 static FILE *create_tempfile(void)
1235 {
1236         char buffer[1024];      
1237         char *tmpdir = NULL;
1238         char *filename;
1239         int fd;
1240         FILE *file;
1241         
1242         if (!(tmpdir = getenv("TMPDIR")) && !(tmpdir = getenv("TMP")))
1243                 tmpdir = "/tmp";
1244         filename = ipset_malloc(strlen(tmpdir) + strlen(TEMPFILE_PATTERN) + 1);
1245         strcpy(filename, tmpdir);
1246         strcat(filename, TEMPFILE_PATTERN);
1247         
1248         (void) umask(077);      /* Create with restrictive permissions */
1249         fd = mkstemp(filename);
1250         if (fd == -1)
1251                 exit_error(OTHER_PROBLEM, "Could not create temporary file.");
1252         if (!(file = fdopen(fd, "r+")))
1253                 exit_error(OTHER_PROBLEM, "Could not open temporary file.");
1254         if (unlink(filename) == -1)
1255                 exit_error(OTHER_PROBLEM, "Could not unlink temporary file.");
1256         free(filename);
1257
1258         while (fgets(buffer, sizeof(buffer), stdin)) {
1259                 fputs(buffer, file);
1260         }
1261         fseek(file, 0L, SEEK_SET);
1262
1263         return file;
1264 }
1265
1266 /*
1267  * Performs a restore from a file
1268  */
1269 static void set_restore(char *argv0)
1270 {
1271         char buffer[1024];      
1272         char *ptr, *name = NULL;
1273         char cmd = ' ';
1274         int line = 0, first_pass, i, bindings = 0;
1275         struct settype *settype = NULL;
1276         struct ip_set_req_setnames *header;
1277         ip_set_id_t index;
1278         FILE *in;
1279         int res;
1280         
1281         /* Create and store stdin in temporary file */
1282         in = create_tempfile();
1283         
1284         /* Load existing sets from kernel */
1285         load_set_list(IPSET_TOKEN_ALL, &index,
1286                       IP_SET_OP_LIST_SIZE, CMD_RESTORE);
1287         
1288         restore_size = sizeof(struct ip_set_req_setnames)/* header */
1289                        + sizeof(struct ip_set_restore);  /* marker */
1290         DP("restore_size: %u", restore_size);
1291         /* First pass: calculate required amount of data */
1292         while (fgets(buffer, sizeof(buffer), in)) {
1293                 line++;
1294
1295                 if (buffer[0] == '\n')
1296                         continue;
1297                 else if (buffer[0] == '#')
1298                         continue;
1299                 else if (strcmp(buffer, "COMMIT\n") == 0) {
1300                         /* Enable restore mode */
1301                         restore = 1;
1302                         break;
1303                 }
1304                         
1305                 /* -N, -A or -B */
1306                 ptr = strtok(buffer, " \t\n");
1307                 DP("ptr: %s", ptr);
1308                 if (ptr == NULL
1309                     || ptr[0] != '-'
1310                     || !(ptr[1] == 'N'
1311                          || ptr[1] == 'A'
1312                          || ptr[1] == 'B')
1313                     || ptr[2] != '\0') {
1314                         exit_error(PARAMETER_PROBLEM,
1315                                    "Line %u does not start as a valid restore command\n",
1316                                    line);
1317                 }
1318                 cmd = ptr[1];           
1319                 /* setname */
1320                 ptr = strtok(NULL, " \t\n");
1321                 DP("setname: %s", ptr);
1322                 if (ptr == NULL)
1323                         exit_error(PARAMETER_PROBLEM,
1324                                    "Missing set name in line %u\n",
1325                                    line);
1326                 DP("cmd %c", cmd);
1327                 switch (cmd) {
1328                 case 'N': {
1329                         name = check_set_name(ptr);
1330                         /* settype */
1331                         ptr = strtok(NULL, " \t\n");
1332                         if (ptr == NULL)
1333                                 exit_error(PARAMETER_PROBLEM,
1334                                            "Missing settype in line %u\n",
1335                                            line);
1336                         if (bindings)
1337                                 exit_error(PARAMETER_PROBLEM,
1338                                            "Invalid line %u: create must precede bindings\n",
1339                                            line);
1340                         settype = check_set_typename(ptr);
1341                         restore_size += sizeof(struct ip_set_restore)
1342                                         + settype->create_size;
1343                         DP("restore_size (N): %u", restore_size);
1344                         break; 
1345                 }
1346                 case 'A': {
1347                         if (name == NULL
1348                             || strncmp(name, ptr, sizeof(name)) != 0)
1349                                 exit_error(PARAMETER_PROBLEM,
1350                                            "Add IP to set %s in line %u without "
1351                                            "preceding corresponding create set line\n",
1352                                            ptr, line);
1353                         if (bindings)
1354                                 exit_error(PARAMETER_PROBLEM,
1355                                            "Invalid line %u: adding entries must precede bindings\n",
1356                                            line);
1357                         restore_size += settype->adt_size;
1358                         DP("restore_size (A): %u", restore_size);
1359                         break;
1360                 }
1361                 case 'B': {
1362                         bindings = 1;
1363                         restore_size += sizeof(struct ip_set_hash_save);
1364                         DP("restore_size (B): %u", restore_size);
1365                         break;
1366                 }
1367                 default: {
1368                         exit_error(PARAMETER_PROBLEM,
1369                                    "Unrecognized restore command in line %u\n",
1370                                    line);
1371                 }
1372                 } /* end of switch */
1373         }                       
1374         /* Sanity checking */
1375         if (!restore)
1376                 exit_error(PARAMETER_PROBLEM,
1377                            "Missing COMMIT line\n");
1378         DP("restore_size: %u", restore_size);
1379         restore_data = ipset_malloc(restore_size);
1380         header = (struct ip_set_req_setnames *) restore_data;
1381         header->op = IP_SET_OP_RESTORE; 
1382         header->size = restore_size; 
1383         restore_offset = sizeof(struct ip_set_req_setnames);
1384
1385         /* Rewind to scan the file again */
1386         fseek(in, 0L, SEEK_SET);
1387         first_pass = line;
1388         line = 0;
1389         
1390         /* Initialize newargv/newargc */
1391         newargv[newargc++] = ipset_strdup(argv0);
1392         
1393         /* Second pass: build up restore request */
1394         while (fgets(buffer, sizeof(buffer), in)) {             
1395                 line++;
1396
1397                 if (buffer[0] == '\n')
1398                         continue;
1399                 else if (buffer[0] == '#')
1400                         continue;
1401                 else if (strcmp(buffer, "COMMIT\n") == 0)
1402                         goto do_restore;
1403                 DP("restoring: %s", buffer);
1404                 /* Build faked argv, argc */
1405                 build_argv(line, buffer);
1406                 for (i = 0; i < newargc; i++)
1407                         DP("argv[%u]: %s", i, newargv[i]);
1408                 
1409                 /* Parse line */
1410                 parse_commandline(newargc, newargv);
1411         }
1412         exit_error(PARAMETER_PROBLEM,
1413                    "Broken restore file\n");
1414    do_restore:
1415         if (bindings == 0
1416             && restore_size == 
1417                (restore_offset + sizeof(struct ip_set_restore))) {
1418                 /* No bindings */
1419                 struct ip_set_restore *marker = 
1420                         (struct ip_set_restore *) (restore_data + restore_offset);
1421
1422                 DP("restore marker");
1423                 marker->index = IP_SET_INVALID_ID;
1424                 marker->header_size = marker->members_size = 0;
1425                 restore_offset += sizeof(struct ip_set_restore);
1426         }
1427         if (restore_size != restore_offset)
1428                 exit_error(PARAMETER_PROBLEM,
1429                            "Giving up, restore file is screwed up!");
1430         res = kernel_getfrom_handleerrno(CMD_RESTORE, restore_data, &restore_size);
1431
1432         if (res != 0) {
1433                 if (restore_size != sizeof(struct ip_set_req_setnames))
1434                         exit_error(PARAMETER_PROBLEM,
1435                                    "Communication with kernel failed (%u %u)!",
1436                                    restore_size, sizeof(struct ip_set_req_setnames));
1437                 /* Check errors  */
1438                 header = (struct ip_set_req_setnames *) restore_data;
1439                 if (header->size != 0) 
1440                         exit_error(PARAMETER_PROBLEM,
1441                                    "Committing restoring failed at line %u!",
1442                                    header->size);
1443         }
1444 }
1445
1446 /*
1447  * Send ADT_GET order to kernel for a set
1448  */
1449 static struct set *set_adt_get(const char *name)
1450 {
1451         struct ip_set_req_adt_get req_adt_get;
1452         struct set *set;
1453         size_t size;
1454
1455         DP("%s", name);
1456
1457         req_adt_get.op = IP_SET_OP_ADT_GET;
1458         req_adt_get.version = IP_SET_PROTOCOL_VERSION;
1459         strcpy(req_adt_get.set.name, name);
1460         size = sizeof(struct ip_set_req_adt_get);
1461
1462         kernel_getfrom(CMD_ADT_GET, &req_adt_get, &size);
1463
1464         set = ipset_malloc(sizeof(struct set));
1465         strcpy(set->name, name);
1466         set->index = req_adt_get.set.index;     
1467         set->settype = settype_load(req_adt_get.typename);
1468
1469         return set;
1470 }       
1471
1472 /*
1473  * Send add/del/test order to kernel for a set
1474  */
1475 static int set_adtip(struct set *set, const char *adt, 
1476                      unsigned op, unsigned cmd)
1477 {
1478         struct ip_set_req_adt *req_adt;
1479         size_t size;
1480         void *data;
1481         int res = 0;
1482
1483         DP("%s -> %s", set->name, adt);
1484
1485         /* Alloc memory for the data to send */
1486         size = sizeof(struct ip_set_req_adt) + set->settype->adt_size ;
1487         DP("alloc size %i", size);
1488         data = ipset_malloc(size);
1489
1490         /* Fill out the request */
1491         req_adt = (struct ip_set_req_adt *) data;
1492         req_adt->op = op;
1493         req_adt->index = set->index;
1494         memcpy(data + sizeof(struct ip_set_req_adt),
1495                set->settype->data, set->settype->adt_size);
1496         
1497         if (kernel_sendto_handleerrno(cmd, op, data, size) == -1)
1498                 switch (op) {
1499                 case IP_SET_OP_ADD_IP:
1500                         exit_error(OTHER_PROBLEM, "%s is already in set %s.",
1501                                    adt, set->name);
1502                         break;
1503                 case IP_SET_OP_DEL_IP:
1504                         exit_error(OTHER_PROBLEM, "%s is not in set %s.",
1505                                    adt, set->name);
1506                         break;
1507                 case IP_SET_OP_TEST_IP:
1508                         ipset_printf("%s is in set %s.", adt, set->name);
1509                         res = 0;
1510                         break;
1511                 default:
1512                         break;
1513                 }
1514         else
1515                 switch (op) {
1516                 case IP_SET_OP_TEST_IP:
1517                         ipset_printf("%s is NOT in set %s.", adt, set->name);
1518                         res = 1;
1519                         break;
1520                 default:
1521                         break;
1522                 }
1523         free(data);
1524
1525         return res;
1526 }
1527
1528 static void set_restore_add(struct set *set, const char *adt)
1529 {
1530         DP("%s %s", set->name, adt);
1531         /* Sanity checking */
1532         if (restore_offset + set->settype->adt_size > restore_size)
1533                 exit_error(PARAMETER_PROBLEM,
1534                            "Giving up, restore file is screwed up!");
1535                            
1536         memcpy(restore_data + restore_offset,
1537                set->settype->data, set->settype->adt_size);
1538         restore_set->members_size += set->settype->adt_size;
1539         restore_offset += set->settype->adt_size;
1540 }
1541
1542 /*
1543  * Send bind/unbind/test binding order to kernel for a set
1544  */
1545 static int set_bind(struct set *set, const char *adt,
1546                     const char *binding,
1547                     unsigned op, unsigned cmd)
1548 {
1549         struct ip_set_req_bind *req_bind;
1550         size_t size;
1551         void *data;
1552         int res = 0;
1553
1554         /* set may be null: '-U :all: :all:|:default:' */
1555         DP("(%s, %s) -> %s", set ? set->name : IPSET_TOKEN_ALL, adt, binding);
1556
1557         /* Alloc memory for the data to send */
1558         size = sizeof(struct ip_set_req_bind);
1559         if (op != IP_SET_OP_UNBIND_SET && adt[0] == ':')
1560                 /* Set default binding */
1561                 size += IP_SET_MAXNAMELEN;
1562         else if (!(op == IP_SET_OP_UNBIND_SET && set == NULL))
1563                 size += set->settype->adt_size;
1564         DP("alloc size %i", size);
1565         data = ipset_malloc(size);
1566
1567         /* Fill out the request */
1568         req_bind = (struct ip_set_req_bind *) data;
1569         req_bind->op = op;
1570         req_bind->index = set ? set->index : IP_SET_INVALID_ID;
1571         if (adt[0] == ':') {
1572                 /* ':default:' and ':all:' */
1573                 strncpy(req_bind->binding, adt, IP_SET_MAXNAMELEN);
1574                 if (op != IP_SET_OP_UNBIND_SET && adt[0] == ':')
1575                         strncpy(data + sizeof(struct ip_set_req_bind),
1576                                 binding, IP_SET_MAXNAMELEN);
1577         } else {
1578                 strncpy(req_bind->binding, binding, IP_SET_MAXNAMELEN);
1579                 memcpy(data + sizeof(struct ip_set_req_bind),
1580                        set->settype->data, set->settype->adt_size);
1581         }
1582
1583         if (op == IP_SET_OP_TEST_BIND_SET) {
1584                 if (kernel_sendto_handleerrno(cmd, op, data, size) == -1) {
1585                         ipset_printf("%s in set %s is bound to %s.",
1586                                      adt, set->name, binding);
1587                         res = 0;
1588                 } else {
1589                         ipset_printf("%s in set %s is NOT bound to %s.",
1590                                      adt, set->name, binding);
1591                         res = 1;
1592                 }
1593         } else  
1594                 kernel_sendto(cmd, data, size);
1595         free(data);
1596
1597         return res;
1598 }
1599
1600 static void set_restore_bind(struct set *set,
1601                              const char *adt,
1602                              const char *binding)
1603 {
1604         struct ip_set_hash_save *hash_restore;
1605
1606         if (restore == 1) {
1607                 /* Marker */
1608                 struct ip_set_restore *marker = 
1609                         (struct ip_set_restore *) (restore_data + restore_offset);
1610
1611                 DP("restore marker");
1612                 if (restore_offset + sizeof(struct ip_set_restore) 
1613                     > restore_size)
1614                         exit_error(PARAMETER_PROBLEM,
1615                                    "Giving up, restore file is screwed up!");
1616                 marker->index = IP_SET_INVALID_ID;
1617                 marker->header_size = marker->members_size = 0;
1618                 restore_offset += sizeof(struct ip_set_restore);
1619                 restore = 2;
1620         }
1621         /* Sanity checking */
1622         if (restore_offset + sizeof(struct ip_set_hash_save) > restore_size)
1623                 exit_error(PARAMETER_PROBLEM,
1624                            "Giving up, restore file is screwed up!");
1625
1626         hash_restore = (struct ip_set_hash_save *) (restore_data + restore_offset);
1627         DP("%s -> %s", adt, binding);
1628         if (strcmp(adt, IPSET_TOKEN_DEFAULT) == 0)
1629                 hash_restore->ip = 0;
1630         else
1631                 set->settype->bindip_parse(adt, &hash_restore->ip);
1632         hash_restore->id = set->index;                     
1633         hash_restore->binding = (set_find_byname(binding))->index;      
1634         DP("id %u, ip %u, binding %u",
1635            hash_restore->id, hash_restore->ip, hash_restore->binding);
1636         restore_offset += sizeof(struct ip_set_hash_save);
1637 }
1638
1639 /*
1640  * Print operation
1641  */
1642
1643 static void print_bindings(struct set *set,
1644                            void *data, size_t size, unsigned options,
1645                            char * (*printip)(struct set *set, 
1646                                              ip_set_ip_t ip, unsigned options))
1647 {
1648         size_t offset = 0;
1649         struct ip_set_hash_list *hash;
1650
1651         while (offset < size) {
1652                 hash = (struct ip_set_hash_list *) (data + offset);
1653                 printf("%s -> %s\n", 
1654                         printip(set, hash->ip, options),
1655                         set_list[hash->binding]->name);
1656                 offset += sizeof(struct ip_set_hash_list);
1657         }
1658 }
1659
1660 /* Help function to set_list() */
1661 static size_t print_set(void *data, unsigned options)
1662 {
1663         struct ip_set_list *setlist = (struct ip_set_list *) data;
1664         struct set *set = set_list[setlist->index];
1665         struct settype *settype = set->settype;
1666         size_t offset;
1667
1668         /* Pretty print the set */
1669         printf("Name: %s\n", set->name);
1670         printf("Type: %s\n", settype->typename);
1671         printf("References: %d\n", setlist->ref);
1672         printf("Default binding: %s\n",
1673                setlist->binding == IP_SET_INVALID_ID ? ""
1674                : set_list[setlist->binding]->name);
1675
1676         /* Init header */
1677         offset = sizeof(struct ip_set_list);
1678         settype->initheader(set, data + offset);
1679
1680         /* Pretty print the type header */
1681         printf("Header:");
1682         settype->printheader(set, options);
1683
1684         /* Pretty print all IPs */
1685         printf("Members:\n");
1686         offset += setlist->header_size;
1687         if (options & OPT_SORTED)
1688                 settype->printips_sorted(set, data + offset,
1689                                          setlist->members_size, options);
1690         else
1691                 settype->printips(set, data + offset,
1692                                   setlist->members_size, options);
1693
1694         /* Print bindings */
1695         printf("Bindings:\n");
1696         offset += setlist->members_size;
1697         print_bindings(set,
1698                        data + offset, setlist->bindings_size, options,
1699                        settype->bindip_tostring);
1700
1701         printf("\n");           /* One newline between sets */
1702         
1703         return (offset + setlist->bindings_size);
1704 }
1705
1706 static int try_list_sets(const char name[IP_SET_MAXNAMELEN],
1707                          unsigned options)
1708 {
1709         void *data = NULL;
1710         ip_set_id_t index;
1711         size_t size, req_size;
1712         int res = 0;
1713
1714         DP("%s", name);
1715         /* Load set_list from kernel */
1716         size = req_size = load_set_list(name, &index,
1717                                         IP_SET_OP_LIST_SIZE, CMD_LIST);
1718
1719         if (size) {
1720                 /* Get sets and print them */
1721                 data = ipset_malloc(size);
1722                 ((struct ip_set_req_list *) data)->op = IP_SET_OP_LIST;
1723                 ((struct ip_set_req_list *) data)->index = index;
1724                 res = kernel_getfrom_handleerrno(CMD_LIST, data, &size);
1725                 DP("get_lists getsockopt() res=%d errno=%d", res, errno);
1726
1727                 if (res != 0 || size != req_size) {
1728                         free(data);
1729                         return -EAGAIN;
1730                 }
1731                 size = 0;
1732         }
1733         while (size != req_size)
1734                 size += print_set(data + size, options);
1735
1736         ipset_free(&data);
1737         return res;
1738 }
1739
1740 /* Print a set or all sets
1741  * All sets: name = NULL
1742  */
1743 static void list_sets(const char name[IP_SET_MAXNAMELEN], unsigned options)
1744 {
1745         int i;
1746
1747         DP("%s", name);
1748         for (i = 0; i < LIST_TRIES; i++)
1749                 if (try_list_sets(name, options) == 0)
1750                         return;
1751
1752         if (errno == EAGAIN)
1753                 exit_error(OTHER_PROBLEM,
1754                            "Tried to list sets from kernel %d times"
1755                            " and failed. Please try again when the load on"
1756                            " the sets has gone down.", LIST_TRIES);
1757         else
1758                 kernel_error(CMD_LIST, errno);
1759 }
1760
1761 /* Prints help
1762  * If settype is non null help for that type is printed as well
1763  */
1764 static void set_help(const struct settype *settype)
1765 {
1766 #ifdef IPSET_DEBUG
1767         char debughelp[] =
1768                "  --debug      -z   Enable debugging\n\n";
1769 #else
1770         char debughelp[] = "\n";
1771 #endif
1772
1773         printf("%s v%s\n\n"
1774                "Usage: %s -N new-set settype [options]\n"
1775                "       %s -[XFLSH] [set] [options]\n"
1776                "       %s -[EW] from-set to-set\n"
1777                "       %s -[ADTU] set IP\n"
1778                "       %s -B set IP option\n"
1779                "       %s -R\n"
1780                "       %s -h (print this help information)\n\n",
1781                program_name, program_version, 
1782                program_name, program_name, program_name,
1783                program_name, program_name, program_name,
1784                program_name);
1785
1786         printf("Commands:\n"
1787                "Either long or short options are allowed.\n"
1788                "  --create  -N setname settype <options>\n"
1789                "                    Create a new set\n"
1790                "  --destroy -X [setname]\n"
1791                "                    Destroy a set or all sets\n"
1792                "  --flush   -F [setname]\n"
1793                "                    Flush a set or all sets\n"
1794                "  --rename  -E from-set to-set\n"
1795                "                    Rename from-set to to-set\n"
1796                "  --swap    -W from-set to-set\n"
1797                "                    Swap the content of two existing sets\n"
1798                "  --list    -L [setname] [options]\n"
1799                "                    List the IPs in a set or all sets\n"
1800                "  --save    -S [setname]\n"
1801                "                    Save the set or all sets to stdout\n"
1802                "  --restore -R [option]\n"
1803                "                    Restores a saved state\n"
1804                "  --add     -A setname IP\n"
1805                "                    Add an IP to a set\n"
1806                "  --del     -D setname IP\n"
1807                "                    Deletes an IP from a set\n"
1808                "  --test    -T setname IP \n"
1809                "                    Tests if an IP exists in a set.\n"
1810                "  --bind    -B setname IP|:default: -b bind-setname\n"
1811                "                    Bind the IP in setname to bind-setname.\n"
1812                "  --unbind  -U setname IP|:all:|:default:\n"
1813                "                    Delete binding belonging to IP,\n"
1814                "                    all bindings or default binding of setname.\n"
1815                "  --unbind  -U :all: :all:|:default:\n"
1816                "                    Delete all bindings or all default bindings.\n"
1817                "  --help    -H [settype]\n"
1818                "                    Prints this help, and settype specific help\n"
1819                "  --version -V\n"
1820                "                    Prints version information\n\n"
1821                "Options:\n"
1822                "  --sorted     -s   Numeric sort of the IPs in -L\n"
1823                "  --numeric    -n   Numeric output of addresses in a -L\n"
1824                "  --quiet      -q   Suppress any output to stdout and stderr.\n"
1825                "  --binding    -b   Specifies the binding for -B\n");
1826         printf(debughelp);
1827
1828         if (settype != NULL) {
1829                 printf("Type '%s' specific:\n", settype->typename);
1830                 settype->usage();
1831         }
1832 }
1833
1834 static int find_cmd(const char option)
1835 {
1836         int i;
1837         
1838         for (i = 1; i <= NUMBER_OF_CMD; i++)
1839                 if (cmdflags[i] == option)
1840                         return i;
1841                         
1842         return CMD_NONE;
1843 }
1844
1845 static int parse_adt_cmdline(unsigned command,
1846                              const char *name,
1847                              char *adt,
1848                              struct set **set,
1849                              struct settype **settype)
1850 {
1851         int res = 0;
1852
1853         /* -U :all: :all:|:default: */
1854         if (command == CMD_UNBIND) {
1855                 if (strcmp(name, IPSET_TOKEN_ALL) == 0) {
1856                         if (strcmp(adt, IPSET_TOKEN_DEFAULT) == 0
1857                             || strcmp(adt, IPSET_TOKEN_ALL) == 0) {
1858                                 *set = NULL;
1859                                 *settype = NULL;
1860                                 return 1;
1861                         } else
1862                                 exit_error(PARAMETER_PROBLEM,
1863                                            "-U %s requires %s or %s as binding name",
1864                                            IPSET_TOKEN_ALL,
1865                                            IPSET_TOKEN_DEFAULT,
1866                                            IPSET_TOKEN_ALL);
1867                 }
1868         }
1869         *set = restore ? set_find_byname(name)
1870                        : set_adt_get(name);
1871                                         
1872         /* Reset space for adt data */
1873         *settype = (*set)->settype;
1874         memset((*settype)->data, 0, (*settype)->adt_size);
1875
1876         if ((command == CMD_TEST
1877              || command == CMD_BIND
1878              || command == CMD_UNBIND)
1879             && (strcmp(adt, IPSET_TOKEN_DEFAULT) == 0
1880                 || strcmp(adt, IPSET_TOKEN_ALL) == 0))
1881                 res = 1;
1882         else
1883                 res = (*settype)->adt_parser(
1884                                 command,
1885                                 adt,
1886                                 (*settype)->data);
1887
1888         return res;
1889 }
1890
1891 /* Main worker function */
1892 int parse_commandline(int argc, char *argv[])
1893 {
1894         int res = 0;
1895         unsigned command = CMD_NONE;
1896         unsigned options = 0;
1897         int c;
1898         
1899         char *name = NULL;              /* All except -H, -R */
1900         char *newname = NULL;           /* -E, -W */
1901         char *adt = NULL;               /* -A, -D, -T, -B, -U */
1902         char *binding = NULL;           /* -B */
1903         struct set *set = NULL;         /* -A, -D, -T, -B, -U */
1904         struct settype *settype = NULL; /* -N, -H */
1905         char all_sets[] = IPSET_TOKEN_ALL;
1906         
1907         struct option *opts = opts_long;
1908
1909         /* Suppress error messages: we may add new options if we
1910            demand-load a protocol. */
1911         opterr = 0;
1912         /* Reset optind to 0 for restore */
1913         optind = 0;
1914         
1915         while ((c = getopt_long(argc, argv, opts_short, opts, NULL)) != -1) {
1916
1917                 DP("commandline parsed: opt %c (%s)", c, argv[optind]);
1918
1919                 switch (c) {
1920                         /*
1921                          * Command selection
1922                          */
1923                 case 'h':
1924                 case 'H':{      /* Help: -H [typename [options]] */
1925                                 check_protocolversion();
1926                                 set_command(&command, CMD_HELP);
1927                                 
1928                                 if (optarg)
1929                                         settype = check_set_typename(optarg);
1930                                 else if (optind < argc
1931                                          && argv[optind][0] != '-')
1932                                         settype = check_set_typename(argv[optind++]);
1933                                 
1934                                 break;
1935                         }
1936
1937                 case 'V':{      /* Version */
1938                                 printf("%s v%s Protocol version %u.\n",
1939                                        program_name, program_version,
1940                                        IP_SET_PROTOCOL_VERSION);
1941                                 check_protocolversion();
1942                                 exit(0);
1943                         }
1944
1945                 case 'N':{      /* Create: -N name typename options */
1946                                 set_command(&command, CMD_CREATE);
1947
1948                                 name = check_set_name(optarg);
1949                                 
1950                                 /* Protect reserved names (binding) */
1951                                 if (name[0] == ':')
1952                                         exit_error(PARAMETER_PROBLEM,
1953                                                    "setname might not start with colon",
1954                                                    cmd2char(CMD_CREATE));
1955                                 
1956                                 if (optind < argc
1957                                     && argv[optind][0] != '-')
1958                                         settype = check_set_typename(argv[optind++]);
1959                                 else
1960                                         exit_error(PARAMETER_PROBLEM,
1961                                                    "-%c requires setname and settype",
1962                                                    cmd2char(CMD_CREATE));
1963
1964                                 DP("merge options");
1965                                 /* Merge the create options */
1966                                 opts = merge_options(opts,
1967                                              settype->create_opts,
1968                                              &settype->option_offset);
1969
1970                                 /* Reset space for create data */
1971                                 memset(settype->data, 0, settype->create_size);
1972
1973                                 /* Zero the flags */
1974                                 settype->flags = 0;
1975
1976                                 DP("call create_init");
1977                                 /* Call the settype create_init */
1978                                 settype->create_init(settype->data);
1979
1980                                 break;
1981                         }
1982
1983                 case 'X':       /* Destroy */
1984                 case 'F':       /* Flush */
1985                 case 'L':       /* List */
1986                 case 'S':{      /* Save */
1987                                 set_command(&command, find_cmd(c));
1988
1989                                 if (optarg)
1990                                         name = check_set_name(optarg);
1991                                 else if (optind < argc
1992                                            && argv[optind][0] != '-')
1993                                         name = check_set_name(argv[optind++]);
1994                                 else
1995                                         name = all_sets;
1996
1997                                 break;
1998                         }
1999
2000                 case 'R':{      /* Restore */
2001                                 set_command(&command, find_cmd(c));
2002
2003                                 break;
2004                         }
2005
2006                 case 'E':       /* Rename */
2007                 case 'W':{      /* Swap */
2008                                 set_command(&command, find_cmd(c));
2009                                 name = check_set_name(optarg);
2010
2011                                 if (optind < argc
2012                                     && argv[optind][0] != '-')
2013                                         newname = check_set_name(argv[optind++]);
2014                                 else
2015                                         exit_error(PARAMETER_PROBLEM,
2016                                                    "-%c requires a setname "
2017                                                    "and the new name for that set",
2018                                                    cmd2char(CMD_RENAME));
2019
2020                                 break;
2021                         }
2022
2023                 case 'A':       /* Add IP */
2024                 case 'D':       /* Del IP */
2025                 case 'T':       /* Test IP */
2026                 case 'B':       /* Bind IP */
2027                 case 'U':{      /* Unbind IP */
2028                                 set_command(&command, find_cmd(c));
2029
2030                                 name = check_set_name(optarg);
2031
2032                                 /* IP */
2033                                 if (optind < argc
2034                                     && argv[optind][0] != '-')
2035                                         adt = argv[optind++];
2036                                 else
2037                                         exit_error(PARAMETER_PROBLEM,
2038                                                    "-%c requires setname and IP",
2039                                                    c);
2040
2041                                 res = parse_adt_cmdline(command, name, adt,
2042                                                         &set, &settype);
2043
2044                                 if (!res)
2045                                         exit_error(PARAMETER_PROBLEM,
2046                                                    "Unknown arg `%s'",
2047                                                    argv[optind - 1]);
2048
2049                                 break;
2050                         }
2051
2052                         /* options */
2053
2054                 case 'n':
2055                         add_option(&options, OPT_NUMERIC);
2056                         break;
2057
2058                 case 's':
2059                         add_option(&options, OPT_SORTED);
2060                         break;
2061
2062                 case 'q':
2063                         add_option(&options, OPT_QUIET);
2064                         option_quiet = 1;
2065                         break;
2066
2067 #ifdef IPSET_DEBUG
2068                 case 'z':       /* debug */
2069                         add_option(&options, OPT_DEBUG);
2070                         option_debug = 1;
2071                         break;
2072 #endif
2073
2074                 case 'b':
2075                         add_option(&options, OPT_BINDING);
2076                         binding = check_set_name(optarg);
2077                         break;
2078
2079                 case 1: /* non option */
2080                         printf("Bad argument `%s'\n", optarg);
2081                         exit_tryhelp(2);
2082                         break;  /*always good */
2083
2084                 default:{
2085                                 DP("default");
2086
2087                                 switch (command) {
2088                                 case CMD_CREATE:
2089                                         res = settype->create_parse(
2090                                                         c - settype->option_offset,
2091                                                         argv,
2092                                                         settype->data,
2093                                                         &settype->flags);
2094                                         break;
2095
2096                                 default:
2097                                         res = 0;        /* failed */
2098                                 }       /* switch (command) */
2099
2100
2101                                 if (!res)
2102                                         exit_error(PARAMETER_PROBLEM,
2103                                                    "Unknown arg `%s'",
2104                                                    argv[optind - 1]);
2105
2106                         }
2107
2108                         DP("next arg");
2109                 }       /* switch */
2110
2111         }       /* while( getopt_long() ) */
2112
2113
2114         if (optind < argc)
2115                 exit_error(PARAMETER_PROBLEM,
2116                            "unknown arguments found on commandline");
2117         if (command == CMD_NONE)
2118                 exit_error(PARAMETER_PROBLEM, "no command specified");
2119
2120         /* Check options */
2121         generic_opt_check(command, options);
2122
2123         DP("cmd: %c", cmd2char(command));
2124
2125         switch (command) {
2126         case CMD_CREATE:
2127                 DP("CMD_CREATE");
2128                 if (restore)
2129                         set_restore_create(name, settype);
2130                 else
2131                         set_create(name, settype);
2132                 break;
2133
2134         case CMD_DESTROY:
2135                 set_destroy(name, IP_SET_OP_DESTROY, CMD_DESTROY);
2136                 break;
2137
2138         case CMD_FLUSH:
2139                 set_destroy(name, IP_SET_OP_FLUSH, CMD_FLUSH);
2140                 break;
2141
2142         case CMD_RENAME:
2143                 set_rename(name, newname, IP_SET_OP_RENAME, CMD_RENAME);
2144                 break;
2145
2146         case CMD_SWAP:
2147                 set_rename(name, newname, IP_SET_OP_SWAP, CMD_SWAP);
2148                 break;
2149
2150         case CMD_LIST:
2151                 list_sets(name, options);
2152                 break;
2153
2154         case CMD_SAVE:
2155                 set_save(name);
2156                 break;
2157
2158         case CMD_RESTORE:
2159                 set_restore(argv[0]);
2160                 break;
2161
2162         case CMD_ADD:
2163                 if (restore)
2164                         set_restore_add(set, adt);
2165                 else
2166                         set_adtip(set, adt, IP_SET_OP_ADD_IP, CMD_ADD);
2167                 break;
2168
2169         case CMD_DEL:
2170                 set_adtip(set, adt, IP_SET_OP_DEL_IP, CMD_DEL);
2171                 break;
2172
2173         case CMD_TEST:
2174                 if (binding)
2175                         res = set_bind(set, adt, binding, 
2176                                        IP_SET_OP_TEST_BIND_SET, CMD_TEST);
2177                 else
2178                         res = set_adtip(set, adt, 
2179                                         IP_SET_OP_TEST_IP, CMD_TEST);
2180                 break;
2181
2182         case CMD_BIND:
2183                 if (restore)
2184                         set_restore_bind(set, adt, binding);
2185                 else
2186                         set_bind(set, adt, binding,
2187                                  IP_SET_OP_BIND_SET, CMD_BIND);
2188                 break;
2189
2190         case CMD_UNBIND:
2191                 set_bind(set, adt, "", IP_SET_OP_UNBIND_SET, CMD_UNBIND);
2192                 break;
2193
2194         case CMD_HELP:
2195                 set_help(settype);
2196                 break;
2197
2198         default:
2199                 /* Will never happen */
2200                 break; /* Keep the compiler happy */
2201
2202         }       /* switch( command ) */
2203
2204         return res;
2205 }
2206
2207
2208 int main(int argc, char *argv[])
2209 {       
2210         return parse_commandline(argc, argv);
2211
2212 }