update to iptables-1.3.8
[iptables.git] / iptables-restore.c
index 95e2cbe..1cbade7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * This code is distributed under the terms of GNU GPL v2
  *
- * $Id: iptables-restore.c 3980 2005-06-12 15:54:15Z /C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kaber/emailAddress=kaber@netfilter.org $
+ * $Id: iptables-restore.c 6828 2007-05-10 15:00:39Z /C=EU/ST=EU/CN=Patrick McHardy/emailAddress=kaber@trash.net $
  */
 
 #include <getopt.h>
@@ -59,19 +59,19 @@ iptc_handle_t create_handle(const char *tablename, const char* modprobe )
 
        if (!handle) {
                /* try to insmod the module if iptc_init failed */
-               iptables_insmod("ip_tables", modprobe);
+               iptables_insmod("ip_tables", modprobe, 0);
                handle = iptc_init(tablename);
        }
 
        if (!handle) {
-               exit_error(PARAMETER_PROBLEM, "%s: unable to initialize"
+               exit_error(PARAMETER_PROBLEM, "%s: unable to initialize "
                        "table '%s'\n", program_name, tablename);
                exit(1);
        }
        return handle;
 }
 
-int parse_counters(char *string, struct ipt_counters *ctr)
+static int parse_counters(char *string, struct ipt_counters *ctr)
 {
        return (sscanf(string, "[%llu:%llu]", (unsigned long long *)&ctr->pcnt, (unsigned long long *)&ctr->bcnt) == 2);
 }
@@ -157,13 +157,13 @@ main(int argc, char *argv[])
        if (optind == argc - 1) {
                in = fopen(argv[optind], "r");
                if (!in) {
-                       fprintf(stderr, "Can't open %s: %s", argv[optind],
+                       fprintf(stderr, "Can't open %s: %s\n", argv[optind],
                                strerror(errno));
                        exit(1);
                }
        }
        else if (optind < argc) {
-               fprintf(stderr, "Unknown arguments found on commandline");
+               fprintf(stderr, "Unknown arguments found on commandline\n");
                exit(1);
        }
        else in = stdin;
@@ -269,7 +269,10 @@ main(int argc, char *argv[])
                                        char *ctrs;
                                        ctrs = strtok(NULL, " \t\n");
 
-                                       parse_counters(ctrs, &count);
+                                       if (!ctrs || !parse_counters(ctrs, &count))
+                                               exit_error(PARAMETER_PROBLEM,
+                                                          "invalid policy counters "
+                                                          "for chain '%s'\n", chain);
 
                                } else {
                                        memset(&count, 0, 
@@ -298,8 +301,9 @@ main(int argc, char *argv[])
                        char *parsestart;
 
                        /* the parser */
-                       char *param_start, *curchar;
+                       char *curchar;
                        int quote_open;
+                       int param_len;
 
                        /* reset the newargv */
                        newargc = 0;
@@ -346,9 +350,11 @@ main(int argc, char *argv[])
                         * longer a real hacker, but I can live with that */
 
                        quote_open = 0;
-                       param_start = parsestart;
+                       param_len = 0;
                        
                        for (curchar = parsestart; *curchar; curchar++) {
+                               char param_buffer[1024];
+
                                if (*curchar == '"') {
                                        /* quote_open cannot be true if there
                                         * was no previous character.  Thus, 
@@ -357,30 +363,27 @@ main(int argc, char *argv[])
                                            *(curchar-1) != '\\') {
                                                quote_open = 0;
                                                *curchar = ' ';
-                                       } else {
+                                       } else if (!quote_open) {
                                                quote_open = 1;
-                                               param_start++;
+                                               continue;
                                        }
                                } 
                                if (*curchar == ' '
                                    || *curchar == '\t'
                                    || * curchar == '\n') {
-                                       char param_buffer[1024];
-                                       int param_len = curchar-param_start;
 
-                                       if (quote_open)
+                                       if (quote_open) {
+                                               param_buffer[param_len++] = 
+                                                               *curchar;
                                                continue;
+                                       }
 
                                        if (!param_len) {
                                                /* two spaces? */
-                                               param_start++;
                                                continue;
                                        }
-                                       
-                                       /* end of one parameter */
-                                       strncpy(param_buffer, param_start,
-                                               param_len);
-                                       *(param_buffer+param_len) = '\0';
+
+                                       param_buffer[param_len] = '\0';
 
                                        /* check if table name specified */
                                        if (!strncmp(param_buffer, "-t", 3)
@@ -392,9 +395,26 @@ main(int argc, char *argv[])
                                        }
 
                                        add_argv(param_buffer);
-                                       param_start += param_len + 1;
+                                       param_len = 0;
                                } else {
-                                       /* regular character, skip */
+                                       /* Skip backslash that escapes quote: 
+                                        * the standard input does not require
+                                        * escaping. However, the output
+                                        * generated by iptables-save
+                                        * introduces bashlash to keep
+                                        * consistent with iptables
+                                        */
+                                       if (quote_open &&
+                                           *curchar == '\\' &&
+                                           *(curchar+1) == '"')
+                                               continue;
+
+                                       /* regular character, copy to buffer */
+                                       param_buffer[param_len++] = *curchar;
+
+                                       if (param_len >= sizeof(param_buffer))
+                                               exit_error(PARAMETER_PROBLEM, 
+                                                  "Parameter too long!");
                                }
                        }