2
0

main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  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 (!(handle = fw3_ipt_open(family, table)))
  154. continue;
  155. info(" * %sing %s %s table", complete ? "Flush" : "Clear",
  156. fw3_flag_names[family], fw3_flag_names[table]);
  157. if (complete)
  158. {
  159. fw3_flush_all(handle);
  160. }
  161. else if (run_state)
  162. {
  163. fw3_flush_rules(handle, run_state, false);
  164. fw3_flush_zones(handle, run_state, false);
  165. }
  166. fw3_ipt_commit(handle);
  167. fw3_ipt_close(handle);
  168. }
  169. family_set(run_state, family, false);
  170. family_set(cfg_state, family, false);
  171. rv = 0;
  172. }
  173. if (run_state) {
  174. for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
  175. fw3_destroy_ipsets(run_state, family, false);
  176. }
  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. for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
  191. {
  192. if (!print_family)
  193. fw3_create_ipsets(cfg_state, family, false);
  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 (!(handle = fw3_ipt_open(family, table)))
  208. continue;
  209. info(" * Populating %s %s table",
  210. fw3_flag_names[family], fw3_flag_names[table]);
  211. fw3_print_default_chains(handle, cfg_state, false);
  212. fw3_print_zone_chains(handle, cfg_state, false);
  213. fw3_print_default_head_rules(handle, cfg_state, false);
  214. fw3_print_rules(handle, cfg_state);
  215. fw3_print_redirects(handle, cfg_state);
  216. fw3_print_snats(handle, cfg_state);
  217. fw3_print_forwards(handle, cfg_state);
  218. fw3_print_zone_rules(handle, cfg_state, false);
  219. fw3_print_default_tail_rules(handle, cfg_state, false);
  220. if (!print_family)
  221. fw3_ipt_commit(handle);
  222. fw3_ipt_close(handle);
  223. }
  224. if (!print_family)
  225. fw3_print_includes(cfg_state, family, false);
  226. family_set(run_state, family, true);
  227. family_set(cfg_state, family, true);
  228. rv = 0;
  229. }
  230. if (!rv)
  231. {
  232. fw3_flush_conntrack(run_state);
  233. fw3_set_defaults(cfg_state);
  234. if (!print_family)
  235. {
  236. fw3_run_includes(cfg_state, false);
  237. fw3_hotplug_zones(cfg_state, true);
  238. fw3_write_statefile(cfg_state);
  239. }
  240. }
  241. return rv;
  242. }
  243. static int
  244. reload(void)
  245. {
  246. int rv = 1;
  247. enum fw3_family family;
  248. enum fw3_table table;
  249. struct fw3_ipt_handle *handle;
  250. if (!run_state)
  251. return start();
  252. fw3_hotplug_zones(run_state, false);
  253. for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
  254. {
  255. if (!family_running(family))
  256. goto start;
  257. for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
  258. {
  259. if (!(handle = fw3_ipt_open(family, table)))
  260. continue;
  261. info(" * Clearing %s %s table",
  262. fw3_flag_names[family], fw3_flag_names[table]);
  263. fw3_flush_rules(handle, run_state, true);
  264. fw3_flush_zones(handle, run_state, true);
  265. fw3_ipt_commit(handle);
  266. fw3_ipt_close(handle);
  267. }
  268. fw3_ipsets_update_run_state(family, run_state, cfg_state);
  269. fw3_destroy_ipsets(run_state, family, true);
  270. family_set(run_state, family, false);
  271. family_set(cfg_state, family, false);
  272. start:
  273. if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
  274. continue;
  275. fw3_create_ipsets(cfg_state, family, true);
  276. for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
  277. {
  278. if (!(handle = fw3_ipt_open(family, table)))
  279. continue;
  280. info(" * Populating %s %s table",
  281. fw3_flag_names[family], fw3_flag_names[table]);
  282. fw3_print_default_chains(handle, cfg_state, true);
  283. fw3_print_zone_chains(handle, cfg_state, true);
  284. fw3_print_default_head_rules(handle, cfg_state, true);
  285. fw3_print_rules(handle, cfg_state);
  286. fw3_print_redirects(handle, cfg_state);
  287. fw3_print_snats(handle, cfg_state);
  288. fw3_print_forwards(handle, cfg_state);
  289. fw3_print_zone_rules(handle, cfg_state, true);
  290. fw3_print_default_tail_rules(handle, cfg_state, true);
  291. fw3_ipt_commit(handle);
  292. fw3_ipt_close(handle);
  293. }
  294. fw3_print_includes(cfg_state, family, true);
  295. family_set(run_state, family, true);
  296. family_set(cfg_state, family, true);
  297. rv = 0;
  298. }
  299. if (!rv)
  300. {
  301. fw3_flush_conntrack(run_state);
  302. fw3_set_defaults(cfg_state);
  303. fw3_run_includes(cfg_state, true);
  304. fw3_hotplug_zones(cfg_state, true);
  305. fw3_write_statefile(cfg_state);
  306. }
  307. return rv;
  308. }
  309. static int
  310. gc(void)
  311. {
  312. enum fw3_family family;
  313. enum fw3_table table;
  314. struct fw3_ipt_handle *handle;
  315. for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
  316. {
  317. if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
  318. continue;
  319. for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
  320. {
  321. if (!(handle = fw3_ipt_open(family, table)))
  322. continue;
  323. fw3_ipt_gc(handle);
  324. fw3_ipt_commit(handle);
  325. fw3_ipt_close(handle);
  326. }
  327. }
  328. return 0;
  329. }
  330. static int
  331. lookup_network(const char *net)
  332. {
  333. struct fw3_zone *z;
  334. struct fw3_device *d;
  335. list_for_each_entry(z, &cfg_state->zones, list)
  336. {
  337. list_for_each_entry(d, &z->networks, list)
  338. {
  339. if (!strcmp(d->name, net))
  340. {
  341. printf("%s\n", z->name);
  342. return 0;
  343. }
  344. }
  345. }
  346. return 1;
  347. }
  348. static int
  349. lookup_device(const char *dev)
  350. {
  351. struct fw3_zone *z;
  352. struct fw3_device *d;
  353. list_for_each_entry(z, &cfg_state->zones, list)
  354. {
  355. list_for_each_entry(d, &z->devices, list)
  356. {
  357. if (!strcmp(d->name, dev))
  358. {
  359. printf("%s\n", z->name);
  360. return 0;
  361. }
  362. }
  363. }
  364. return 1;
  365. }
  366. static int
  367. lookup_zone(const char *zone, const char *device)
  368. {
  369. struct fw3_zone *z;
  370. struct fw3_device *d;
  371. list_for_each_entry(z, &cfg_state->zones, list)
  372. {
  373. if (strcmp(z->name, zone))
  374. continue;
  375. list_for_each_entry(d, &z->devices, list)
  376. {
  377. if (device && strcmp(device, d->name))
  378. continue;
  379. printf("%s\n", d->name);
  380. if (device)
  381. return 0;
  382. }
  383. if (!device)
  384. return 0;
  385. }
  386. return 1;
  387. }
  388. static int
  389. usage(void)
  390. {
  391. fprintf(stderr, "fw3 [-4] [-6] [-q] print\n");
  392. fprintf(stderr, "fw3 [-q] {start|stop|flush|reload|restart}\n");
  393. fprintf(stderr, "fw3 [-q] network {net}\n");
  394. fprintf(stderr, "fw3 [-q] device {dev}\n");
  395. fprintf(stderr, "fw3 [-q] zone {zone} [dev]\n");
  396. return 1;
  397. }
  398. int main(int argc, char **argv)
  399. {
  400. int ch, rv = 1;
  401. enum fw3_family family = FW3_FAMILY_ANY;
  402. struct fw3_defaults *defs = NULL;
  403. while ((ch = getopt(argc, argv, "46dqh")) != -1)
  404. {
  405. switch (ch)
  406. {
  407. case '4':
  408. family = FW3_FAMILY_V4;
  409. break;
  410. case '6':
  411. family = FW3_FAMILY_V6;
  412. break;
  413. case 'd':
  414. fw3_pr_debug = true;
  415. break;
  416. case 'q':
  417. if (freopen("/dev/null", "w", stderr)) {}
  418. break;
  419. case 'h':
  420. rv = usage();
  421. goto out;
  422. }
  423. }
  424. build_state(false);
  425. defs = &cfg_state->defaults;
  426. if (optind >= argc)
  427. {
  428. rv = usage();
  429. goto out;
  430. }
  431. if (!strcmp(argv[optind], "print"))
  432. {
  433. if (family == FW3_FAMILY_ANY)
  434. {
  435. family = FW3_FAMILY_V4;
  436. }
  437. else if (family == FW3_FAMILY_V6)
  438. {
  439. if (defs->disable_ipv6)
  440. warn("IPv6 rules globally disabled in configuration");
  441. #ifdef DISABLE_IPV6
  442. else
  443. warn("IPv6 support is not compiled in");
  444. #endif
  445. }
  446. if (freopen("/dev/null", "w", stderr)) {};
  447. cfg_state->disable_ipsets = true;
  448. print_family = family;
  449. fw3_pr_debug = true;
  450. if (fw3_lock())
  451. {
  452. build_state(true);
  453. rv = start();
  454. fw3_unlock();
  455. }
  456. }
  457. else if (!strcmp(argv[optind], "start"))
  458. {
  459. if (fw3_lock())
  460. {
  461. build_state(true);
  462. rv = start();
  463. fw3_unlock();
  464. }
  465. }
  466. else if (!strcmp(argv[optind], "stop"))
  467. {
  468. if (fw3_lock())
  469. {
  470. build_state(true);
  471. rv = stop(false);
  472. fw3_unlock();
  473. }
  474. }
  475. else if (!strcmp(argv[optind], "flush"))
  476. {
  477. if (fw3_lock())
  478. {
  479. build_state(true);
  480. rv = stop(true);
  481. fw3_unlock();
  482. }
  483. }
  484. else if (!strcmp(argv[optind], "restart"))
  485. {
  486. if (fw3_lock())
  487. {
  488. build_state(true);
  489. stop(true);
  490. rv = start();
  491. fw3_unlock();
  492. }
  493. }
  494. else if (!strcmp(argv[optind], "reload"))
  495. {
  496. if (fw3_lock())
  497. {
  498. build_state(true);
  499. rv = reload();
  500. fw3_unlock();
  501. }
  502. }
  503. else if (!strcmp(argv[optind], "gc"))
  504. {
  505. if (fw3_lock())
  506. {
  507. rv = gc();
  508. fw3_unlock();
  509. }
  510. }
  511. else if (!strcmp(argv[optind], "network") && (optind + 1) < argc)
  512. {
  513. rv = lookup_network(argv[optind + 1]);
  514. }
  515. else if (!strcmp(argv[optind], "device") && (optind + 1) < argc)
  516. {
  517. rv = lookup_device(argv[optind + 1]);
  518. }
  519. else if (!strcmp(argv[optind], "zone") && (optind + 1) < argc)
  520. {
  521. rv = lookup_zone(argv[optind + 1], argv[optind + 2]);
  522. }
  523. else
  524. {
  525. rv = usage();
  526. }
  527. out:
  528. if (cfg_state)
  529. free_state(cfg_state);
  530. if (run_state)
  531. free_state(run_state);
  532. return rv;
  533. }