ip6tables-restore.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /* Code to restore the iptables state, from file by ip6tables-save.
  2. * Author: Andras Kis-Szabo <kisza@sch.bme.hu>
  3. *
  4. * based on iptables-restore
  5. * Authors:
  6. * Harald Welte <laforge@gnumonks.org>
  7. * Rusty Russell <rusty@linuxcare.com.au>
  8. * This code is distributed under the terms of GNU GPL v2
  9. */
  10. #include <getopt.h>
  11. #include <sys/errno.h>
  12. #include <stdbool.h>
  13. #include <string.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include "ip6tables.h"
  17. #include "xtables.h"
  18. #include "libiptc/libip6tc.h"
  19. #include "ip6tables-multi.h"
  20. #ifdef DEBUG
  21. #define DEBUGP(x, args...) fprintf(stderr, x, ## args)
  22. #else
  23. #define DEBUGP(x, args...)
  24. #endif
  25. static int binary = 0, counters = 0, verbose = 0, noflush = 0;
  26. /* Keeping track of external matches and targets. */
  27. static const struct option options[] = {
  28. {.name = "binary", .has_arg = false, .val = 'b'},
  29. {.name = "counters", .has_arg = false, .val = 'c'},
  30. {.name = "verbose", .has_arg = false, .val = 'v'},
  31. {.name = "test", .has_arg = false, .val = 't'},
  32. {.name = "help", .has_arg = false, .val = 'h'},
  33. {.name = "noflush", .has_arg = false, .val = 'n'},
  34. {.name = "modprobe", .has_arg = true, .val = 'M'},
  35. {.name = "table", .has_arg = true, .val = 'T'},
  36. {NULL},
  37. };
  38. static void print_usage(const char *name, const char *version) __attribute__((noreturn));
  39. static void print_usage(const char *name, const char *version)
  40. {
  41. fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-t] [-h]\n"
  42. " [ --binary ]\n"
  43. " [ --counters ]\n"
  44. " [ --verbose ]\n"
  45. " [ --test ]\n"
  46. " [ --help ]\n"
  47. " [ --noflush ]\n"
  48. " [ --modprobe=<command>]\n", name);
  49. exit(1);
  50. }
  51. static struct xtc_handle *create_handle(const char *tablename)
  52. {
  53. struct xtc_handle *handle;
  54. handle = ip6tc_init(tablename);
  55. if (!handle) {
  56. /* try to insmod the module if iptc_init failed */
  57. xtables_load_ko(xtables_modprobe_program, false);
  58. handle = ip6tc_init(tablename);
  59. }
  60. if (!handle) {
  61. xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
  62. "table '%s'\n", ip6tables_globals.program_name,
  63. tablename);
  64. exit(1);
  65. }
  66. return handle;
  67. }
  68. static int parse_counters(char *string, struct xt_counters *ctr)
  69. {
  70. unsigned long long pcnt, bcnt;
  71. int ret;
  72. ret = sscanf(string, "[%llu:%llu]", &pcnt, &bcnt);
  73. ctr->pcnt = pcnt;
  74. ctr->bcnt = bcnt;
  75. return ret == 2;
  76. }
  77. /* global new argv and argc */
  78. static char *newargv[255];
  79. static int newargc;
  80. /* function adding one argument to newargv, updating newargc
  81. * returns true if argument added, false otherwise */
  82. static int add_argv(char *what) {
  83. DEBUGP("add_argv: %s\n", what);
  84. if (what && newargc + 1 < ARRAY_SIZE(newargv)) {
  85. newargv[newargc] = strdup(what);
  86. newargv[++newargc] = NULL;
  87. return 1;
  88. } else {
  89. xtables_error(PARAMETER_PROBLEM,
  90. "Parser cannot handle more arguments\n");
  91. return 0;
  92. }
  93. }
  94. static void free_argv(void) {
  95. int i;
  96. for (i = 0; i < newargc; i++)
  97. free(newargv[i]);
  98. }
  99. static void add_param_to_argv(char *parsestart)
  100. {
  101. int quote_open = 0, escaped = 0, param_len = 0;
  102. char param_buffer[1024], *curchar;
  103. /* After fighting with strtok enough, here's now
  104. * a 'real' parser. According to Rusty I'm now no
  105. * longer a real hacker, but I can live with that */
  106. for (curchar = parsestart; *curchar; curchar++) {
  107. if (quote_open) {
  108. if (escaped) {
  109. param_buffer[param_len++] = *curchar;
  110. escaped = 0;
  111. continue;
  112. } else if (*curchar == '\\') {
  113. escaped = 1;
  114. continue;
  115. } else if (*curchar == '"') {
  116. quote_open = 0;
  117. *curchar = ' ';
  118. } else {
  119. param_buffer[param_len++] = *curchar;
  120. continue;
  121. }
  122. } else {
  123. if (*curchar == '"') {
  124. quote_open = 1;
  125. continue;
  126. }
  127. }
  128. if (*curchar == ' '
  129. || *curchar == '\t'
  130. || * curchar == '\n') {
  131. if (!param_len) {
  132. /* two spaces? */
  133. continue;
  134. }
  135. param_buffer[param_len] = '\0';
  136. /* check if table name specified */
  137. if (!strncmp(param_buffer, "-t", 2)
  138. || !strncmp(param_buffer, "--table", 8)) {
  139. xtables_error(PARAMETER_PROBLEM,
  140. "The -t option (seen in line %u) cannot be "
  141. "used in ip6tables-restore.\n", line);
  142. exit(1);
  143. }
  144. add_argv(param_buffer);
  145. param_len = 0;
  146. } else {
  147. /* regular character, copy to buffer */
  148. param_buffer[param_len++] = *curchar;
  149. if (param_len >= sizeof(param_buffer))
  150. xtables_error(PARAMETER_PROBLEM,
  151. "Parameter too long!");
  152. }
  153. }
  154. }
  155. int ip6tables_restore_main(int argc, char *argv[])
  156. {
  157. struct xtc_handle *handle = NULL;
  158. char buffer[10240];
  159. int c;
  160. char curtable[XT_TABLE_MAXNAMELEN + 1];
  161. FILE *in;
  162. int in_table = 0, testing = 0;
  163. const char *tablename = NULL;
  164. const struct xtc_ops *ops = &ip6tc_ops;
  165. line = 0;
  166. ip6tables_globals.program_name = "ip6tables-restore";
  167. c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
  168. if (c < 0) {
  169. fprintf(stderr, "%s/%s Failed to initialize xtables\n",
  170. ip6tables_globals.program_name,
  171. ip6tables_globals.program_version);
  172. exit(1);
  173. }
  174. #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
  175. init_extensions();
  176. init_extensions6();
  177. #endif
  178. while ((c = getopt_long(argc, argv, "bcvthnM:T:", options, NULL)) != -1) {
  179. switch (c) {
  180. case 'b':
  181. binary = 1;
  182. break;
  183. case 'c':
  184. counters = 1;
  185. break;
  186. case 'v':
  187. verbose = 1;
  188. break;
  189. case 't':
  190. testing = 1;
  191. break;
  192. case 'h':
  193. print_usage("ip6tables-restore",
  194. IPTABLES_VERSION);
  195. break;
  196. case 'n':
  197. noflush = 1;
  198. break;
  199. case 'M':
  200. xtables_modprobe_program = optarg;
  201. break;
  202. case 'T':
  203. tablename = optarg;
  204. break;
  205. }
  206. }
  207. if (optind == argc - 1) {
  208. in = fopen(argv[optind], "re");
  209. if (!in) {
  210. fprintf(stderr, "Can't open %s: %s\n", argv[optind],
  211. strerror(errno));
  212. exit(1);
  213. }
  214. }
  215. else if (optind < argc) {
  216. fprintf(stderr, "Unknown arguments found on commandline\n");
  217. exit(1);
  218. }
  219. else in = stdin;
  220. /* Grab standard input. */
  221. while (fgets(buffer, sizeof(buffer), in)) {
  222. int ret = 0;
  223. line++;
  224. if (buffer[0] == '\n')
  225. continue;
  226. else if (buffer[0] == '#') {
  227. if (verbose)
  228. fputs(buffer, stdout);
  229. continue;
  230. } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
  231. if (!testing) {
  232. DEBUGP("Calling commit\n");
  233. ret = ops->commit(handle);
  234. ops->free(handle);
  235. handle = NULL;
  236. } else {
  237. DEBUGP("Not calling commit, testing\n");
  238. ret = 1;
  239. }
  240. in_table = 0;
  241. } else if ((buffer[0] == '*') && (!in_table)) {
  242. /* New table */
  243. char *table;
  244. table = strtok(buffer+1, " \t\n");
  245. DEBUGP("line %u, table '%s'\n", line, table);
  246. if (!table) {
  247. xtables_error(PARAMETER_PROBLEM,
  248. "%s: line %u table name invalid\n",
  249. xt_params->program_name, line);
  250. exit(1);
  251. }
  252. strncpy(curtable, table, XT_TABLE_MAXNAMELEN);
  253. curtable[XT_TABLE_MAXNAMELEN] = '\0';
  254. if (tablename != NULL && strcmp(tablename, table) != 0)
  255. continue;
  256. if (handle)
  257. ops->free(handle);
  258. handle = create_handle(table);
  259. if (noflush == 0) {
  260. DEBUGP("Cleaning all chains of table '%s'\n",
  261. table);
  262. for_each_chain6(flush_entries6, verbose, 1,
  263. handle);
  264. DEBUGP("Deleting all user-defined chains "
  265. "of table '%s'\n", table);
  266. for_each_chain6(delete_chain6, verbose, 0,
  267. handle);
  268. }
  269. ret = 1;
  270. in_table = 1;
  271. } else if ((buffer[0] == ':') && (in_table)) {
  272. /* New chain. */
  273. char *policy, *chain;
  274. chain = strtok(buffer+1, " \t\n");
  275. DEBUGP("line %u, chain '%s'\n", line, chain);
  276. if (!chain) {
  277. xtables_error(PARAMETER_PROBLEM,
  278. "%s: line %u chain name invalid\n",
  279. xt_params->program_name, line);
  280. exit(1);
  281. }
  282. if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
  283. xtables_error(PARAMETER_PROBLEM,
  284. "Invalid chain name `%s' "
  285. "(%u chars max)",
  286. chain, XT_EXTENSION_MAXNAMELEN - 1);
  287. if (ops->builtin(chain, handle) <= 0) {
  288. if (noflush && ops->is_chain(chain, handle)) {
  289. DEBUGP("Flushing existing user defined chain '%s'\n", chain);
  290. if (!ops->flush_entries(chain, handle))
  291. xtables_error(PARAMETER_PROBLEM,
  292. "error flushing chain "
  293. "'%s':%s\n", chain,
  294. strerror(errno));
  295. } else {
  296. DEBUGP("Creating new chain '%s'\n", chain);
  297. if (!ops->create_chain(chain, handle))
  298. xtables_error(PARAMETER_PROBLEM,
  299. "error creating chain "
  300. "'%s':%s\n", chain,
  301. strerror(errno));
  302. }
  303. }
  304. policy = strtok(NULL, " \t\n");
  305. DEBUGP("line %u, policy '%s'\n", line, policy);
  306. if (!policy) {
  307. xtables_error(PARAMETER_PROBLEM,
  308. "%s: line %u policy invalid\n",
  309. xt_params->program_name, line);
  310. exit(1);
  311. }
  312. if (strcmp(policy, "-") != 0) {
  313. struct xt_counters count;
  314. if (counters) {
  315. char *ctrs;
  316. ctrs = strtok(NULL, " \t\n");
  317. if (!ctrs || !parse_counters(ctrs, &count))
  318. xtables_error(PARAMETER_PROBLEM,
  319. "invalid policy counters "
  320. "for chain '%s'\n", chain);
  321. } else {
  322. memset(&count, 0, sizeof(count));
  323. }
  324. DEBUGP("Setting policy of chain %s to %s\n",
  325. chain, policy);
  326. if (!ops->set_policy(chain, policy, &count,
  327. handle))
  328. xtables_error(OTHER_PROBLEM,
  329. "Can't set policy `%s'"
  330. " on `%s' line %u: %s\n",
  331. policy, chain, line,
  332. ops->strerror(errno));
  333. }
  334. ret = 1;
  335. } else if (in_table) {
  336. int a;
  337. char *ptr = buffer;
  338. char *pcnt = NULL;
  339. char *bcnt = NULL;
  340. char *parsestart;
  341. /* reset the newargv */
  342. newargc = 0;
  343. if (buffer[0] == '[') {
  344. /* we have counters in our input */
  345. ptr = strchr(buffer, ']');
  346. if (!ptr)
  347. xtables_error(PARAMETER_PROBLEM,
  348. "Bad line %u: need ]\n",
  349. line);
  350. pcnt = strtok(buffer+1, ":");
  351. if (!pcnt)
  352. xtables_error(PARAMETER_PROBLEM,
  353. "Bad line %u: need :\n",
  354. line);
  355. bcnt = strtok(NULL, "]");
  356. if (!bcnt)
  357. xtables_error(PARAMETER_PROBLEM,
  358. "Bad line %u: need ]\n",
  359. line);
  360. /* start command parsing after counter */
  361. parsestart = ptr + 1;
  362. } else {
  363. /* start command parsing at start of line */
  364. parsestart = buffer;
  365. }
  366. add_argv(argv[0]);
  367. add_argv("-t");
  368. add_argv(curtable);
  369. if (counters && pcnt && bcnt) {
  370. add_argv("--set-counters");
  371. add_argv((char *) pcnt);
  372. add_argv((char *) bcnt);
  373. }
  374. add_param_to_argv(parsestart);
  375. DEBUGP("calling do_command6(%u, argv, &%s, handle):\n",
  376. newargc, curtable);
  377. for (a = 0; a < newargc; a++)
  378. DEBUGP("argv[%u]: %s\n", a, newargv[a]);
  379. ret = do_command6(newargc, newargv,
  380. &newargv[2], &handle);
  381. free_argv();
  382. fflush(stdout);
  383. }
  384. if (tablename != NULL && strcmp(tablename, curtable) != 0)
  385. continue;
  386. if (!ret) {
  387. fprintf(stderr, "%s: line %u failed\n",
  388. xt_params->program_name, line);
  389. exit(1);
  390. }
  391. }
  392. if (in_table) {
  393. fprintf(stderr, "%s: COMMIT expected at line %u\n",
  394. xt_params->program_name, line + 1);
  395. exit(1);
  396. }
  397. fclose(in);
  398. return 0;
  399. }