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