helpers.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. * firewall3 - 3rd OpenWrt UCI firewall implementation
  3. *
  4. * Copyright (C) 2018 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 "helpers.h"
  19. const struct fw3_option fw3_cthelper_opts[] = {
  20. FW3_OPT("enabled", bool, cthelper, enabled),
  21. FW3_OPT("name", string, cthelper, name),
  22. FW3_OPT("module", string, cthelper, module),
  23. FW3_OPT("description", string, cthelper, description),
  24. FW3_OPT("family", family, cthelper, family),
  25. FW3_LIST("proto", protocol, cthelper, proto),
  26. FW3_OPT("port", port, cthelper, port),
  27. { }
  28. };
  29. static bool
  30. test_module(struct fw3_cthelper *helper)
  31. {
  32. struct stat s;
  33. char path[sizeof("/sys/module/nf_conntrack_xxxxxxxxxxxxxxxx")];
  34. snprintf(path, sizeof(path), "/sys/module/%s", helper->module);
  35. if (stat(path, &s) || !S_ISDIR(s.st_mode))
  36. return false;
  37. return true;
  38. }
  39. static bool
  40. check_cthelper_proto(const struct fw3_cthelper *helper)
  41. {
  42. struct fw3_protocol *proto;
  43. if (list_empty(&helper->proto))
  44. return false;
  45. list_for_each_entry(proto, &helper->proto, list)
  46. {
  47. if (!proto->protocol || proto->any || proto->invert)
  48. return false;
  49. }
  50. return true;
  51. }
  52. static bool
  53. check_cthelper(struct fw3_state *state, struct fw3_cthelper *helper, struct uci_element *e)
  54. {
  55. if (!helper->name || !*helper->name)
  56. {
  57. warn_section("helper", helper, e, "must have a name assigned");
  58. }
  59. else if (!helper->module || !*helper->module)
  60. {
  61. warn_section("helper", helper, e, "must have a module assigned");
  62. }
  63. else if (!check_cthelper_proto(helper))
  64. {
  65. warn_section("helper", helper, e, "must specify a protocol");
  66. }
  67. else if (helper->port.set && helper->port.invert)
  68. {
  69. warn_section("helper", helper, e, "must not specify negated ports");
  70. }
  71. else
  72. {
  73. return true;
  74. }
  75. return false;
  76. }
  77. static struct fw3_cthelper *
  78. fw3_alloc_cthelper(struct fw3_state *state)
  79. {
  80. struct fw3_cthelper *helper;
  81. helper = calloc(1, sizeof(*helper));
  82. if (!helper)
  83. return NULL;
  84. helper->enabled = true;
  85. helper->family = FW3_FAMILY_ANY;
  86. INIT_LIST_HEAD(&helper->proto);
  87. list_add_tail(&helper->list, &state->cthelpers);
  88. return helper;
  89. }
  90. static void
  91. load_cthelpers(struct fw3_state *state, struct uci_package *p)
  92. {
  93. struct fw3_cthelper *helper;
  94. struct uci_section *s;
  95. struct uci_element *e;
  96. uci_foreach_element(&p->sections, e)
  97. {
  98. s = uci_to_section(e);
  99. if (strcmp(s->type, "helper"))
  100. continue;
  101. helper = fw3_alloc_cthelper(state);
  102. if (!helper)
  103. continue;
  104. if (!fw3_parse_options(helper, fw3_cthelper_opts, s))
  105. warn_elem(e, "has invalid options");
  106. if (!check_cthelper(state, helper, e))
  107. fw3_free_cthelper(helper);
  108. }
  109. }
  110. void
  111. fw3_load_cthelpers(struct fw3_state *state, struct uci_package *p)
  112. {
  113. struct uci_package *hp = NULL;
  114. FILE *fp;
  115. INIT_LIST_HEAD(&state->cthelpers);
  116. fp = fopen(FW3_HELPERCONF, "r");
  117. if (fp) {
  118. uci_import(state->uci, fp, "fw3_ct_helpers", &hp, true);
  119. fclose(fp);
  120. if (hp)
  121. load_cthelpers(state, hp);
  122. }
  123. load_cthelpers(state, p);
  124. }
  125. struct fw3_cthelper *
  126. fw3_lookup_cthelper(struct fw3_state *state, const char *name)
  127. {
  128. struct fw3_cthelper *h;
  129. if (list_empty(&state->cthelpers))
  130. return NULL;
  131. list_for_each_entry(h, &state->cthelpers, list)
  132. {
  133. if (strcasecmp(h->name, name))
  134. continue;
  135. return h;
  136. }
  137. return NULL;
  138. }
  139. bool
  140. fw3_cthelper_check_proto(const struct fw3_cthelper *h, const struct fw3_protocol *proto)
  141. {
  142. struct fw3_protocol *p;
  143. list_for_each_entry(p, &h->proto, list)
  144. {
  145. if (p->protocol == proto->protocol)
  146. return true;
  147. }
  148. return false;
  149. }
  150. struct fw3_cthelper *
  151. fw3_lookup_cthelper_by_proto_port(struct fw3_state *state,
  152. struct fw3_protocol *proto,
  153. struct fw3_port *port)
  154. {
  155. struct fw3_cthelper *h;
  156. if (list_empty(&state->cthelpers))
  157. return NULL;
  158. if (!proto || !proto->protocol || proto->any || proto->invert)
  159. return NULL;
  160. if (port && port->invert)
  161. return NULL;
  162. list_for_each_entry(h, &state->cthelpers, list)
  163. {
  164. if (!h->enabled)
  165. continue;
  166. if (!fw3_cthelper_check_proto(h, proto))
  167. continue;
  168. if (h->port.set && (!port || !port->set))
  169. continue;
  170. if (!h->port.set && (!port || !port->set))
  171. return h;
  172. if (h->port.set && port && port->set &&
  173. h->port.port_min <= port->port_min &&
  174. h->port.port_max >= port->port_max)
  175. return h;
  176. }
  177. return NULL;
  178. }
  179. static void
  180. print_helper_rule(struct fw3_ipt_handle *handle, struct fw3_cthelper *helper,
  181. struct fw3_zone *zone, struct fw3_protocol *proto)
  182. {
  183. struct fw3_ipt_rule *r;
  184. r = fw3_ipt_rule_create(handle, proto, NULL, NULL, NULL, NULL);
  185. if (helper->description && *helper->description)
  186. fw3_ipt_rule_comment(r, helper->description);
  187. else
  188. fw3_ipt_rule_comment(r, helper->name);
  189. fw3_ipt_rule_sport_dport(r, NULL, &helper->port);
  190. fw3_ipt_rule_target(r, "CT");
  191. fw3_ipt_rule_addarg(r, false, "--helper", helper->name);
  192. fw3_ipt_rule_replace(r, "zone_%s_helper", zone->name);
  193. }
  194. static void
  195. expand_helper_rule(struct fw3_ipt_handle *handle, struct fw3_cthelper *helper,
  196. struct fw3_zone *zone)
  197. {
  198. struct fw3_protocol *proto;
  199. list_for_each_entry(proto, &helper->proto, list)
  200. print_helper_rule(handle, helper, zone, proto);
  201. }
  202. void
  203. fw3_print_cthelpers(struct fw3_ipt_handle *handle, struct fw3_state *state,
  204. struct fw3_zone *zone)
  205. {
  206. struct fw3_cthelper *helper;
  207. struct fw3_cthelpermatch *match;
  208. if (handle->table != FW3_TABLE_RAW)
  209. return;
  210. if (!fw3_is_family(zone, handle->family))
  211. return;
  212. if (list_empty(&zone->cthelpers))
  213. {
  214. if (zone->masq || !zone->auto_helper)
  215. return;
  216. if (list_empty(&state->cthelpers))
  217. return;
  218. info(" - Using automatic conntrack helper attachment");
  219. list_for_each_entry(helper, &state->cthelpers, list)
  220. {
  221. if (!helper || !helper->enabled)
  222. continue;
  223. if (!fw3_is_family(helper, handle->family))
  224. continue;
  225. if (!test_module(helper))
  226. continue;
  227. expand_helper_rule(handle, helper, zone);
  228. }
  229. }
  230. else
  231. {
  232. list_for_each_entry(match, &zone->cthelpers, list)
  233. {
  234. helper = match->ptr;
  235. if (!helper || !helper->enabled)
  236. continue;
  237. if (!fw3_is_family(helper, handle->family))
  238. continue;
  239. if (!test_module(helper))
  240. {
  241. info(" ! Conntrack module '%s' for helper '%s' is not loaded",
  242. helper->module, helper->name);
  243. continue;
  244. }
  245. expand_helper_rule(handle, helper, zone);
  246. }
  247. }
  248. }