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