ubus.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * firewall3 - 3rd OpenWrt UCI firewall implementation
  3. *
  4. * Copyright (C) 2013 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 "ubus.h"
  19. static struct blob_attr *interfaces = NULL;
  20. static struct blob_attr *procd_data;
  21. static void dump_cb(struct ubus_request *req, int type, struct blob_attr *msg)
  22. {
  23. static const struct blobmsg_policy policy = { "interface", BLOBMSG_TYPE_ARRAY };
  24. struct blob_attr *cur;
  25. blobmsg_parse(&policy, 1, &cur, blob_data(msg), blob_len(msg));
  26. if (cur)
  27. interfaces = blob_memdup(cur);
  28. }
  29. static void procd_data_cb(struct ubus_request *req, int type, struct blob_attr *msg)
  30. {
  31. procd_data = blob_memdup(msg);
  32. }
  33. bool
  34. fw3_ubus_connect(void)
  35. {
  36. bool status = false;
  37. uint32_t id;
  38. struct ubus_context *ctx = ubus_connect(NULL);
  39. struct blob_buf b = { };
  40. blob_buf_init(&b, 0);
  41. if (!ctx)
  42. goto out;
  43. if (ubus_lookup_id(ctx, "network.interface", &id))
  44. goto out;
  45. if (ubus_invoke(ctx, id, "dump", b.head, dump_cb, NULL, 2000))
  46. goto out;
  47. status = true;
  48. if (ubus_lookup_id(ctx, "service", &id))
  49. goto out;
  50. blobmsg_add_string(&b, "type", "firewall");
  51. ubus_invoke(ctx, id, "get_data", b.head, procd_data_cb, NULL, 2000);
  52. out:
  53. blob_buf_free(&b);
  54. if (ctx)
  55. ubus_free(ctx);
  56. return status;
  57. }
  58. void
  59. fw3_ubus_disconnect(void)
  60. {
  61. free(interfaces);
  62. interfaces = NULL;
  63. }
  64. static struct fw3_address *
  65. parse_subnet(enum fw3_family family, struct blob_attr *dict, int rem)
  66. {
  67. struct blob_attr *cur;
  68. struct fw3_address *addr;
  69. addr = calloc(1, sizeof(*addr));
  70. if (!addr)
  71. return NULL;
  72. addr->set = true;
  73. addr->family = family;
  74. __blob_for_each_attr(cur, dict, rem)
  75. {
  76. if (!strcmp(blobmsg_name(cur), "address"))
  77. inet_pton(family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
  78. blobmsg_get_string(cur), &addr->address.v6);
  79. else if (!strcmp(blobmsg_name(cur), "mask"))
  80. fw3_bitlen2netmask(family, blobmsg_get_u32(cur), &addr->mask.v6);
  81. }
  82. return addr;
  83. }
  84. static int
  85. parse_subnets(struct list_head *head, enum fw3_family family,
  86. struct blob_attr *list)
  87. {
  88. struct blob_attr *cur;
  89. struct fw3_address *addr;
  90. int rem, n = 0;
  91. if (!list)
  92. return 0;
  93. rem = blobmsg_data_len(list);
  94. __blob_for_each_attr(cur, blobmsg_data(list), rem)
  95. {
  96. addr = parse_subnet(family, blobmsg_data(cur), blobmsg_data_len(cur));
  97. if (addr)
  98. {
  99. list_add_tail(&addr->list, head);
  100. n++;
  101. }
  102. }
  103. return n;
  104. }
  105. struct fw3_device *
  106. fw3_ubus_device(const char *net)
  107. {
  108. enum {
  109. DEV_INTERFACE,
  110. DEV_DEVICE,
  111. DEV_L3_DEVICE,
  112. __DEV_MAX
  113. };
  114. static const struct blobmsg_policy policy[__DEV_MAX] = {
  115. [DEV_INTERFACE] = { "interface", BLOBMSG_TYPE_STRING },
  116. [DEV_DEVICE] = { "device", BLOBMSG_TYPE_STRING },
  117. [DEV_L3_DEVICE] = { "l3_device", BLOBMSG_TYPE_STRING },
  118. };
  119. struct fw3_device *dev = NULL;
  120. struct blob_attr *tb[__DEV_MAX];
  121. struct blob_attr *cur;
  122. char *name = NULL;
  123. int rem;
  124. if (!net || !interfaces)
  125. return NULL;
  126. blobmsg_for_each_attr(cur, interfaces, rem) {
  127. blobmsg_parse(policy, __DEV_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
  128. if (!tb[DEV_INTERFACE] ||
  129. strcmp(blobmsg_data(tb[DEV_INTERFACE]), net) != 0)
  130. continue;
  131. if (tb[DEV_L3_DEVICE])
  132. name = blobmsg_data(tb[DEV_L3_DEVICE]);
  133. else if (tb[DEV_DEVICE])
  134. name = blobmsg_data(tb[DEV_DEVICE]);
  135. else
  136. continue;
  137. break;
  138. }
  139. if (!name)
  140. return NULL;
  141. dev = calloc(1, sizeof(*dev));
  142. if (!dev)
  143. return NULL;
  144. snprintf(dev->name, sizeof(dev->name), "%s", name);
  145. dev->set = true;
  146. return dev;
  147. }
  148. int
  149. fw3_ubus_address(struct list_head *list, const char *net)
  150. {
  151. enum {
  152. ADDR_INTERFACE,
  153. ADDR_IPV4,
  154. ADDR_IPV6,
  155. ADDR_IPV6_PREFIX,
  156. __ADDR_MAX
  157. };
  158. static const struct blobmsg_policy policy[__ADDR_MAX] = {
  159. [ADDR_INTERFACE] = { "interface", BLOBMSG_TYPE_STRING },
  160. [ADDR_IPV4] = { "ipv4-address", BLOBMSG_TYPE_ARRAY },
  161. [ADDR_IPV6] = { "ipv6-address", BLOBMSG_TYPE_ARRAY },
  162. [ADDR_IPV6_PREFIX] = { "ipv6-prefix-assignment", BLOBMSG_TYPE_ARRAY },
  163. };
  164. struct blob_attr *tb[__ADDR_MAX];
  165. struct blob_attr *cur;
  166. int rem, n = 0;
  167. if (!net || !interfaces)
  168. return 0;
  169. blobmsg_for_each_attr(cur, interfaces, rem) {
  170. blobmsg_parse(policy, __ADDR_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
  171. if (!tb[ADDR_INTERFACE] ||
  172. strcmp(blobmsg_data(tb[ADDR_INTERFACE]), net) != 0)
  173. continue;
  174. n += parse_subnets(list, FW3_FAMILY_V4, tb[ADDR_IPV4]);
  175. n += parse_subnets(list, FW3_FAMILY_V6, tb[ADDR_IPV6]);
  176. n += parse_subnets(list, FW3_FAMILY_V6, tb[ADDR_IPV6_PREFIX]);
  177. }
  178. return n;
  179. }
  180. void
  181. fw3_ubus_zone_devices(struct fw3_zone *zone)
  182. {
  183. struct blob_attr *c, *cur, *dcur;
  184. unsigned r, rem, drem;
  185. const char *name;
  186. bool matches;
  187. blobmsg_for_each_attr(c, interfaces, r) {
  188. name = NULL;
  189. matches = false;
  190. blobmsg_for_each_attr(cur, c, rem) {
  191. if (!strcmp(blobmsg_name(cur), "interface"))
  192. name = blobmsg_get_string(cur);
  193. else if (!strcmp(blobmsg_name(cur), "data"))
  194. blobmsg_for_each_attr(dcur, cur, drem)
  195. if (!strcmp(blobmsg_name(dcur), "zone"))
  196. matches = !strcmp(blobmsg_get_string(dcur), zone->name);
  197. }
  198. if (name && matches)
  199. fw3_parse_device(&zone->networks, name, true);
  200. }
  201. }
  202. static void fw3_ubus_rules_add(struct blob_buf *b, const char *service,
  203. const char *instance, const char *device,
  204. const struct blob_attr *rule, unsigned n)
  205. {
  206. void *k = blobmsg_open_table(b, "");
  207. struct blob_attr *ropt;
  208. unsigned orem;
  209. char *type = NULL, *name = NULL;
  210. char comment[256];
  211. blobmsg_for_each_attr(ropt, rule, orem) {
  212. if (!strcmp(blobmsg_name(ropt), "type"))
  213. type = blobmsg_data(ropt);
  214. else if (!strcmp(blobmsg_name(ropt), "name"))
  215. name = blobmsg_data(ropt);
  216. if (device && !strcmp(blobmsg_name(ropt), "device"))
  217. device = blobmsg_get_string(ropt);
  218. else if (strcmp(blobmsg_name(ropt), "name"))
  219. blobmsg_add_blob(b, ropt);
  220. }
  221. if (!type || strcmp(type, "ipset")) {
  222. if (instance)
  223. snprintf(comment, sizeof(comment), "ubus:%s[%s] %s %d",
  224. service, instance, type ? type : "rule", n);
  225. else
  226. snprintf(comment, sizeof(comment), "ubus:%s %s %d",
  227. service, type ? type : "rule", n);
  228. blobmsg_add_string(b, "name", comment);
  229. }
  230. else if (name) {
  231. blobmsg_add_string(b, "name", name);
  232. }
  233. if (device)
  234. blobmsg_add_string(b, "device", device);
  235. blobmsg_close_table(b, k);
  236. }
  237. void
  238. fw3_ubus_rules(struct blob_buf *b)
  239. {
  240. blob_buf_init(b, 0);
  241. struct blob_attr *c, *cur, *dcur, *rule;
  242. unsigned n, r, rem, drem, rrem;
  243. blobmsg_for_each_attr(c, interfaces, r) {
  244. const char *l3_device = NULL;
  245. const char *iface_proto = "unknown";
  246. const char *iface_name = "unknown";
  247. struct blob_attr *data = NULL;
  248. blobmsg_for_each_attr(cur, c, rem) {
  249. if (!strcmp(blobmsg_name(cur), "l3_device"))
  250. l3_device = blobmsg_get_string(cur);
  251. else if (!strcmp(blobmsg_name(cur), "interface"))
  252. iface_name = blobmsg_get_string(cur);
  253. else if (!strcmp(blobmsg_name(cur), "proto"))
  254. iface_proto = blobmsg_get_string(cur);
  255. else if (!strcmp(blobmsg_name(cur), "data"))
  256. data = cur;
  257. }
  258. if (!data || !l3_device)
  259. continue;
  260. blobmsg_for_each_attr(dcur, data, drem) {
  261. if (strcmp(blobmsg_name(dcur), "firewall"))
  262. continue;
  263. n = 0;
  264. blobmsg_for_each_attr(rule, dcur, rrem)
  265. fw3_ubus_rules_add(b, iface_name, iface_proto,
  266. l3_device, rule, n++);
  267. }
  268. }
  269. if (!procd_data)
  270. return;
  271. /* service */
  272. blobmsg_for_each_attr(c, procd_data, r) {
  273. if (!blobmsg_check_attr(c, true))
  274. continue;
  275. /* instance */
  276. blobmsg_for_each_attr(cur, c, rem) {
  277. if (!blobmsg_check_attr(cur, true))
  278. continue;
  279. /* fw rules within the service itself */
  280. if (!strcmp(blobmsg_name(cur), "firewall")) {
  281. n = 0;
  282. blobmsg_for_each_attr(rule, cur, rrem)
  283. fw3_ubus_rules_add(b, blobmsg_name(c),
  284. NULL, NULL, rule, n++);
  285. continue;
  286. }
  287. /* type */
  288. blobmsg_for_each_attr(dcur, cur, drem) {
  289. if (!blobmsg_check_attr(dcur, true))
  290. continue;
  291. if (strcmp(blobmsg_name(dcur), "firewall"))
  292. continue;
  293. n = 0;
  294. blobmsg_for_each_attr(rule, dcur, rrem)
  295. fw3_ubus_rules_add(b, blobmsg_name(c),
  296. blobmsg_name(cur), NULL, rule, n++);
  297. }
  298. }
  299. }
  300. }