main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. /*
  2. * firewall3 - 3rd OpenWrt UCI firewall implementation
  3. *
  4. * Copyright (C) 2013-2014 Jo-Philipp Wich <jo@mein.io>
  5. *
  6. * Permission to use, copy, modify, and/or distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #include <stdio.h>
  19. #include <unistd.h>
  20. #include "options.h"
  21. #include "defaults.h"
  22. #include "zones.h"
  23. #include "rules.h"
  24. #include "redirects.h"
  25. #include "snats.h"
  26. #include "forwards.h"
  27. #include "ipsets.h"
  28. #include "includes.h"
  29. #include "ubus.h"
  30. #include "iptables.h"
  31. #include "helpers.h"
  32. static enum fw3_family print_family = FW3_FAMILY_ANY;
  33. static struct fw3_state *run_state = NULL;
  34. static struct fw3_state *cfg_state = NULL;
  35. static bool
  36. build_state(bool runtime)
  37. {
  38. struct fw3_state *state = NULL;
  39. struct uci_package *p = NULL;
  40. FILE *sf;
  41. state = calloc(1, sizeof(*state));
  42. if (!state)
  43. error("Out of memory");
  44. state->uci = uci_alloc_context();
  45. if (!state->uci)
  46. error("Out of memory");
  47. if (runtime)
  48. {
  49. sf = fopen(FW3_STATEFILE, "r");
  50. if (sf)
  51. {
  52. uci_import(state->uci, sf, "fw3_state", &p, true);
  53. fclose(sf);
  54. }
  55. if (!p)
  56. {
  57. uci_free_context(state->uci);
  58. free(state);
  59. return false;
  60. }
  61. state->statefile = true;
  62. run_state = state;
  63. }
  64. else
  65. {
  66. if (!fw3_ubus_connect())
  67. warn("Failed to connect to ubus");
  68. if (uci_load(state->uci, "firewall", &p))
  69. {
  70. uci_perror(state->uci, NULL);
  71. error("Failed to load /etc/config/firewall");
  72. }
  73. if (!fw3_find_command("ipset"))
  74. {
  75. warn("Unable to locate ipset utility, disabling ipset support");
  76. state->disable_ipsets = true;
  77. }
  78. cfg_state = state;
  79. }
  80. struct blob_buf b = {NULL, NULL, 0, NULL};
  81. fw3_ubus_rules(&b);
  82. fw3_load_defaults(state, p);
  83. fw3_load_cthelpers(state, p);
  84. fw3_load_ipsets(state, p, b.head);
  85. fw3_load_zones(state, p);
  86. fw3_load_rules(state, p, b.head);
  87. fw3_load_redirects(state, p, b.head);
  88. fw3_load_snats(state, p, b.head);
  89. fw3_load_forwards(state, p, b.head);
  90. fw3_load_includes(state, p, b.head);
  91. return true;
  92. }
  93. static void
  94. free_state(struct fw3_state *state)
  95. {
  96. struct list_head *cur, *tmp;
  97. list_for_each_safe(cur, tmp, &state->zones)
  98. fw3_free_zone((struct fw3_zone *)cur);
  99. list_for_each_safe(cur, tmp, &state->rules)
  100. fw3_free_rule((struct fw3_rule *)cur);
  101. list_for_each_safe(cur, tmp, &state->redirects)
  102. fw3_free_redirect((struct fw3_redirect *)cur);
  103. list_for_each_safe(cur, tmp, &state->snats)
  104. fw3_free_snat((struct fw3_snat *)cur);
  105. list_for_each_safe(cur, tmp, &state->forwards)
  106. fw3_free_forward((struct fw3_forward *)cur);
  107. list_for_each_safe(cur, tmp, &state->ipsets)
  108. fw3_free_ipset((struct fw3_ipset *)cur);
  109. list_for_each_safe(cur, tmp, &state->includes)
  110. fw3_free_include((struct fw3_include *)cur);
  111. list_for_each_safe(cur, tmp, &state->cthelpers)
  112. fw3_free_cthelper((struct fw3_cthelper *)cur);
  113. uci_free_context(state->uci);
  114. free(state);
  115. fw3_ubus_disconnect();
  116. }
  117. static bool
  118. family_running(enum fw3_family family)
  119. {
  120. return (run_state && has(run_state->defaults.flags, family, family));
  121. }
  122. static void
  123. family_set(struct fw3_state *state, enum fw3_family family, bool set)
  124. {
  125. if (!state)
  126. return;
  127. if (set)
  128. set(state->defaults.flags, family, family);
  129. else
  130. del(state->defaults.flags, family, family);
  131. }
  132. static int
  133. stop(bool complete)
  134. {
  135. int rv = 1;
  136. enum fw3_family family;
  137. enum fw3_table table;
  138. struct fw3_ipt_handle *handle;
  139. if (!complete && !run_state)
  140. {
  141. warn("The firewall appears to be stopped. "
  142. "Use the 'flush' command to forcefully purge all rules.");
  143. return rv;
  144. }
  145. if (!print_family && run_state)
  146. fw3_hotplug_zones(run_state, false);
  147. for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
  148. {
  149. if (!complete && !family_running(family))
  150. continue;
  151. for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
  152. {
  153. if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
  154. continue;
  155. if (!(handle = fw3_ipt_open(family, table)))
  156. continue;
  157. info(" * %sing %s %s table", complete ? "Flush" : "Clear",
  158. fw3_flag_names[family], fw3_flag_names[table]);
  159. if (complete)
  160. {
  161. fw3_flush_all(handle);
  162. }
  163. else if (run_state)
  164. {
  165. fw3_flush_rules(handle, run_state, false);
  166. fw3_flush_zones(handle, run_state, false);
  167. }
  168. fw3_ipt_commit(handle);
  169. fw3_ipt_close(handle);
  170. }
  171. family_set(run_state, family, false);
  172. family_set(cfg_state, family, false);
  173. rv = 0;
  174. }
  175. if (run_state)
  176. fw3_destroy_ipsets(run_state);
  177. if (complete)
  178. fw3_flush_conntrack(NULL);
  179. if (!rv && run_state)
  180. fw3_write_statefile(run_state);
  181. return rv;
  182. }
  183. static int
  184. start(void)
  185. {
  186. int rv = 1;
  187. enum fw3_family family;
  188. enum fw3_table table;
  189. struct fw3_ipt_handle *handle;
  190. if (!print_family)
  191. fw3_create_ipsets(cfg_state);
  192. for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
  193. {
  194. if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
  195. continue;
  196. if (print_family && family != print_family)
  197. continue;
  198. if (!print_family && family_running(family))
  199. {
  200. warn("The %s firewall appears to be started already. "
  201. "If it is indeed empty, remove the %s file and retry.",
  202. fw3_flag_names[family], FW3_STATEFILE);
  203. continue;
  204. }
  205. for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
  206. {
  207. if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
  208. continue;
  209. if (!(handle = fw3_ipt_open(family, table)))
  210. continue;
  211. info(" * Populating %s %s table",
  212. fw3_flag_names[family], fw3_flag_names[table]);
  213. fw3_print_default_chains(handle, cfg_state, false);
  214. fw3_print_zone_chains(handle, cfg_state, false);
  215. fw3_print_default_head_rules(handle, cfg_state, false);
  216. fw3_print_rules(handle, cfg_state);
  217. fw3_print_redirects(handle, cfg_state);
  218. fw3_print_snats(handle, cfg_state);
  219. fw3_print_forwards(handle, cfg_state);
  220. fw3_print_zone_rules(handle, cfg_state, false);
  221. fw3_print_default_tail_rules(handle, cfg_state, false);
  222. if (!print_family)
  223. fw3_ipt_commit(handle);
  224. fw3_ipt_close(handle);
  225. }
  226. if (!print_family)
  227. fw3_print_includes(cfg_state, family, false);
  228. family_set(run_state, family, true);
  229. family_set(cfg_state, family, true);
  230. rv = 0;
  231. }
  232. if (!rv)
  233. {
  234. fw3_flush_conntrack(run_state);
  235. fw3_set_defaults(cfg_state);
  236. if (!print_family)
  237. {
  238. fw3_run_includes(cfg_state, false);
  239. fw3_hotplug_zones(cfg_state, true);
  240. fw3_write_statefile(cfg_state);
  241. }
  242. }
  243. return rv;
  244. }
  245. static int
  246. reload(void)
  247. {
  248. int rv = 1;
  249. enum fw3_family family;
  250. enum fw3_table table;
  251. struct fw3_ipt_handle *handle;
  252. if (!run_state)
  253. return start();
  254. fw3_hotplug_zones(run_state, false);
  255. for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
  256. {
  257. if (!family_running(family))
  258. goto start;
  259. for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
  260. {
  261. if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
  262. continue;
  263. if (!(handle = fw3_ipt_open(family, table)))
  264. continue;
  265. info(" * Clearing %s %s table",
  266. fw3_flag_names[family], fw3_flag_names[table]);
  267. fw3_flush_rules(handle, run_state, true);
  268. fw3_flush_zones(handle, run_state, true);
  269. fw3_ipt_commit(handle);
  270. fw3_ipt_close(handle);
  271. }
  272. family_set(run_state, family, false);
  273. family_set(cfg_state, family, false);
  274. start:
  275. if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
  276. continue;
  277. for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
  278. {
  279. if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
  280. continue;
  281. if (!(handle = fw3_ipt_open(family, table)))
  282. continue;
  283. info(" * Populating %s %s table",
  284. fw3_flag_names[family], fw3_flag_names[table]);
  285. fw3_print_default_chains(handle, cfg_state, true);
  286. fw3_print_zone_chains(handle, cfg_state, true);
  287. fw3_print_default_head_rules(handle, cfg_state, true);
  288. fw3_print_rules(handle, cfg_state);
  289. fw3_print_redirects(handle, cfg_state);
  290. fw3_print_snats(handle, cfg_state);
  291. fw3_print_forwards(handle, cfg_state);
  292. fw3_print_zone_rules(handle, cfg_state, true);
  293. fw3_print_default_tail_rules(handle, cfg_state, true);
  294. fw3_ipt_commit(handle);
  295. fw3_ipt_close(handle);
  296. }
  297. fw3_print_includes(cfg_state, family, true);
  298. family_set(run_state, family, true);
  299. family_set(cfg_state, family, true);
  300. rv = 0;
  301. }
  302. if (!rv)
  303. {
  304. fw3_flush_conntrack(run_state);
  305. fw3_set_defaults(cfg_state);
  306. fw3_run_includes(cfg_state, true);
  307. fw3_hotplug_zones(cfg_state, true);
  308. fw3_write_statefile(cfg_state);
  309. }
  310. return rv;
  311. }
  312. static int
  313. gc(void)
  314. {
  315. enum fw3_family family;
  316. enum fw3_table table;
  317. struct fw3_ipt_handle *handle;
  318. for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
  319. {
  320. if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
  321. continue;
  322. for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
  323. {
  324. if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
  325. continue;
  326. if (!(handle = fw3_ipt_open(family, table)))
  327. continue;
  328. fw3_ipt_gc(handle);
  329. fw3_ipt_commit(handle);
  330. fw3_ipt_close(handle);
  331. }
  332. }
  333. return 0;
  334. }
  335. static int
  336. lookup_network(const char *net)
  337. {
  338. struct fw3_zone *z;
  339. struct fw3_device *d;
  340. list_for_each_entry(z, &cfg_state->zones, list)
  341. {
  342. list_for_each_entry(d, &z->networks, list)
  343. {
  344. if (!strcmp(d->name, net))
  345. {
  346. printf("%s\n", z->name);
  347. return 0;
  348. }
  349. }
  350. }
  351. return 1;
  352. }
  353. static int
  354. lookup_device(const char *dev)
  355. {
  356. struct fw3_zone *z;
  357. struct fw3_device *d;
  358. list_for_each_entry(z, &cfg_state->zones, list)
  359. {
  360. list_for_each_entry(d, &z->devices, list)
  361. {
  362. if (!strcmp(d->name, dev))
  363. {
  364. printf("%s\n", z->name);
  365. return 0;
  366. }
  367. }
  368. }
  369. return 1;
  370. }
  371. static int
  372. lookup_zone(const char *zone, const char *device)
  373. {
  374. struct fw3_zone *z;
  375. struct fw3_device *d;
  376. list_for_each_entry(z, &cfg_state->zones, list)
  377. {
  378. if (strcmp(z->name, zone))
  379. continue;
  380. list_for_each_entry(d, &z->devices, list)
  381. {
  382. if (device && strcmp(device, d->name))
  383. continue;
  384. printf("%s\n", d->name);
  385. if (device)
  386. return 0;
  387. }
  388. if (!device)
  389. return 0;
  390. }
  391. return 1;
  392. }
  393. static int
  394. usage(void)
  395. {
  396. fprintf(stderr, "fw3 [-4] [-6] [-q] print\n");
  397. fprintf(stderr, "fw3 [-q] {start|stop|flush|reload|restart}\n");
  398. fprintf(stderr, "fw3 [-q] network {net}\n");
  399. fprintf(stderr, "fw3 [-q] device {dev}\n");
  400. fprintf(stderr, "fw3 [-q] zone {zone} [dev]\n");
  401. return 1;
  402. }
  403. int main(int argc, char **argv)
  404. {
  405. int ch, rv = 1;
  406. enum fw3_family family = FW3_FAMILY_ANY;
  407. struct fw3_defaults *defs = NULL;
  408. while ((ch = getopt(argc, argv, "46dqh")) != -1)
  409. {
  410. switch (ch)
  411. {
  412. case '4':
  413. family = FW3_FAMILY_V4;
  414. break;
  415. case '6':
  416. family = FW3_FAMILY_V6;
  417. break;
  418. case 'd':
  419. fw3_pr_debug = true;
  420. break;
  421. case 'q':
  422. if (freopen("/dev/null", "w", stderr)) {}
  423. break;
  424. case 'h':
  425. rv = usage();
  426. goto out;
  427. }
  428. }
  429. build_state(false);
  430. defs = &cfg_state->defaults;
  431. if (optind >= argc)
  432. {
  433. rv = usage();
  434. goto out;
  435. }
  436. if (!strcmp(argv[optind], "print"))
  437. {
  438. if (family == FW3_FAMILY_ANY)
  439. {
  440. family = FW3_FAMILY_V4;
  441. }
  442. else if (family == FW3_FAMILY_V6)
  443. {
  444. if (defs->disable_ipv6)
  445. warn("IPv6 rules globally disabled in configuration");
  446. #ifdef DISABLE_IPV6
  447. else
  448. warn("IPv6 support is not compiled in");
  449. #endif
  450. }
  451. if (freopen("/dev/null", "w", stderr)) {};
  452. cfg_state->disable_ipsets = true;
  453. print_family = family;
  454. fw3_pr_debug = true;
  455. if (fw3_lock())
  456. {
  457. build_state(true);
  458. rv = start();
  459. fw3_unlock();
  460. }
  461. }
  462. else if (!strcmp(argv[optind], "start"))
  463. {
  464. if (fw3_lock())
  465. {
  466. build_state(true);
  467. rv = start();
  468. fw3_unlock();
  469. }
  470. }
  471. else if (!strcmp(argv[optind], "stop"))
  472. {
  473. if (fw3_lock())
  474. {
  475. build_state(true);
  476. rv = stop(false);
  477. fw3_unlock();
  478. }
  479. }
  480. else if (!strcmp(argv[optind], "flush"))
  481. {
  482. if (fw3_lock())
  483. {
  484. build_state(true);
  485. rv = stop(true);
  486. fw3_unlock();
  487. }
  488. }
  489. else if (!strcmp(argv[optind], "restart"))
  490. {
  491. if (fw3_lock())
  492. {
  493. build_state(true);
  494. stop(true);
  495. rv = start();
  496. fw3_unlock();
  497. }
  498. }
  499. else if (!strcmp(argv[optind], "reload"))
  500. {
  501. if (fw3_lock())
  502. {
  503. build_state(true);
  504. rv = reload();
  505. fw3_unlock();
  506. }
  507. }
  508. else if (!strcmp(argv[optind], "gc"))
  509. {
  510. if (fw3_lock())
  511. {
  512. rv = gc();
  513. fw3_unlock();
  514. }
  515. }
  516. else if (!strcmp(argv[optind], "network") && (optind + 1) < argc)
  517. {
  518. rv = lookup_network(argv[optind + 1]);
  519. }
  520. else if (!strcmp(argv[optind], "device") && (optind + 1) < argc)
  521. {
  522. rv = lookup_device(argv[optind + 1]);
  523. }
  524. else if (!strcmp(argv[optind], "zone") && (optind + 1) < argc)
  525. {
  526. rv = lookup_zone(argv[optind + 1], argv[optind + 2]);
  527. }
  528. else
  529. {
  530. rv = usage();
  531. }
  532. out:
  533. if (cfg_state)
  534. free_state(cfg_state);
  535. if (run_state)
  536. free_state(run_state);
  537. return rv;
  538. }