mapcalc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * mapcalc - MAP parameter calculation
  3. *
  4. * Author: Steven Barth <[email protected]>
  5. * Copyright (c) 2014 cisco Systems, Inc.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2
  9. * as published by the Free Software Foundation
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <arpa/inet.h>
  19. #include <errno.h>
  20. #include <libubus.h>
  21. #include <libubox/utils.h>
  22. struct blob_attr *dump = NULL;
  23. enum {
  24. DUMP_ATTR_INTERFACE,
  25. DUMP_ATTR_MAX
  26. };
  27. static const struct blobmsg_policy dump_attrs[DUMP_ATTR_MAX] = {
  28. [DUMP_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_ARRAY },
  29. };
  30. enum {
  31. IFACE_ATTR_INTERFACE,
  32. IFACE_ATTR_PREFIX,
  33. IFACE_ATTR_MAX,
  34. };
  35. static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
  36. [IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING },
  37. [IFACE_ATTR_PREFIX] = { .name = "ipv6-prefix", .type = BLOBMSG_TYPE_ARRAY },
  38. };
  39. enum {
  40. PREFIX_ATTR_ADDRESS,
  41. PREFIX_ATTR_MASK,
  42. PREFIX_ATTR_MAX,
  43. };
  44. static const struct blobmsg_policy prefix_attrs[PREFIX_ATTR_MAX] = {
  45. [PREFIX_ATTR_ADDRESS] = { .name = "address", .type = BLOBMSG_TYPE_STRING },
  46. [PREFIX_ATTR_MASK] = { .name = "mask", .type = BLOBMSG_TYPE_INT32 },
  47. };
  48. static int bmemcmp(const void *av, const void *bv, size_t bits)
  49. {
  50. const uint8_t *a = av, *b = bv;
  51. size_t bytes = bits / 8;
  52. bits %= 8;
  53. int res = memcmp(a, b, bytes);
  54. if (res == 0 && bits > 0)
  55. res = (a[bytes] >> (8 - bits)) - (b[bytes] >> (8 - bits));
  56. return res;
  57. }
  58. static void bmemcpy(void *av, const void *bv, size_t bits)
  59. {
  60. uint8_t *a = av;
  61. const uint8_t *b = bv;
  62. size_t bytes = bits / 8;
  63. bits %= 8;
  64. memcpy(a, b, bytes);
  65. if (bits > 0) {
  66. uint8_t mask = (1 << (8 - bits)) - 1;
  67. a[bytes] = (a[bytes] & mask) | ((~mask) & b[bytes]);
  68. }
  69. }
  70. static void bmemcpys64(void *av, const void *bv, size_t frombits, size_t nbits)
  71. {
  72. uint64_t buf = 0;
  73. const uint8_t *b = bv;
  74. size_t frombyte = frombits / 8, tobyte = (frombits + nbits) / 8;
  75. memcpy(&buf, &b[frombyte], tobyte - frombyte + 1);
  76. buf = cpu_to_be64(be64_to_cpu(buf) << (frombits % 8));
  77. bmemcpy(av, &buf, nbits);
  78. }
  79. static void handle_dump(struct ubus_request *req __attribute__((unused)),
  80. int type __attribute__((unused)), struct blob_attr *msg)
  81. {
  82. struct blob_attr *tb[DUMP_ATTR_INTERFACE];
  83. blobmsg_parse(dump_attrs, DUMP_ATTR_MAX, tb, blob_data(msg), blob_len(msg));
  84. if (!tb[DUMP_ATTR_INTERFACE])
  85. return;
  86. dump = blob_memdup(tb[DUMP_ATTR_INTERFACE]);
  87. }
  88. enum {
  89. OPT_TYPE,
  90. OPT_FMR,
  91. OPT_EALEN,
  92. OPT_PREFIX4LEN,
  93. OPT_PREFIX6LEN,
  94. OPT_IPV6PREFIX,
  95. OPT_IPV4PREFIX,
  96. OPT_OFFSET,
  97. OPT_PSIDLEN,
  98. OPT_PSID,
  99. OPT_BR,
  100. OPT_DMR,
  101. OPT_MAX
  102. };
  103. static char *const token[] = {
  104. [OPT_TYPE] = "type",
  105. [OPT_FMR] = "fmr",
  106. [OPT_EALEN] = "ealen",
  107. [OPT_PREFIX4LEN] = "prefix4len",
  108. [OPT_PREFIX6LEN] = "prefix6len",
  109. [OPT_IPV6PREFIX] = "ipv6prefix",
  110. [OPT_IPV4PREFIX] = "ipv4prefix",
  111. [OPT_OFFSET] = "offset",
  112. [OPT_PSIDLEN] = "psidlen",
  113. [OPT_PSID] = "psid",
  114. [OPT_BR] = "br",
  115. [OPT_DMR] = "dmr",
  116. [OPT_MAX] = NULL
  117. };
  118. int main(int argc, char *argv[])
  119. {
  120. int status = 0;
  121. const char *iface = argv[1];
  122. const char *legacy_env = getenv("LEGACY");
  123. bool legacy = legacy_env && atoi(legacy_env);
  124. if (argc < 3) {
  125. fprintf(stderr, "Usage: %s <interface|*> <rule1> [rule2] [...]\n", argv[0]);
  126. return 1;
  127. }
  128. uint32_t network_interface;
  129. struct ubus_context *ubus = ubus_connect(NULL);
  130. if (ubus) {
  131. ubus_lookup_id(ubus, "network.interface", &network_interface);
  132. ubus_invoke(ubus, network_interface, "dump", NULL, handle_dump, NULL, 5000);
  133. }
  134. int rulecnt = 0;
  135. for (int i = 2; i < argc; ++i) {
  136. bool lw4o6 = false;
  137. bool fmr = false;
  138. int ealen = -1;
  139. int addr4len = 32;
  140. int prefix4len = 32;
  141. int prefix6len = -1;
  142. int pdlen = -1;
  143. struct in_addr ipv4prefix = {INADDR_ANY};
  144. struct in_addr ipv4addr = {INADDR_ANY};
  145. struct in6_addr ipv6addr = IN6ADDR_ANY_INIT;
  146. struct in6_addr ipv6prefix = IN6ADDR_ANY_INIT;
  147. struct in6_addr pd = IN6ADDR_ANY_INIT;
  148. int offset = -1;
  149. int psidlen = -1;
  150. int psid = -1;
  151. uint16_t psid16 = 0;
  152. const char *dmr = NULL;
  153. const char *br = NULL;
  154. for (char *rule = strdup(argv[i]); *rule; ) {
  155. char *value;
  156. int intval;
  157. int idx = getsubopt(&rule, token, &value);
  158. errno = 0;
  159. if (idx == OPT_TYPE) {
  160. lw4o6 = (value && !strcmp(value, "lw4o6"));
  161. } else if (idx == OPT_FMR) {
  162. fmr = true;
  163. } else if (idx == OPT_EALEN && (intval = strtoul(value, NULL, 0)) <= 48 && !errno) {
  164. ealen = intval;
  165. } else if (idx == OPT_PREFIX4LEN && (intval = strtoul(value, NULL, 0)) <= 32 && !errno) {
  166. prefix4len = intval;
  167. } else if (idx == OPT_PREFIX6LEN && (intval = strtoul(value, NULL, 0)) <= 112 && !errno) {
  168. prefix6len = intval;
  169. } else if (idx == OPT_IPV4PREFIX && inet_pton(AF_INET, value, &ipv4prefix) == 1) {
  170. // dummy
  171. } else if (idx == OPT_IPV6PREFIX && inet_pton(AF_INET6, value, &ipv6prefix) == 1) {
  172. // dummy
  173. } else if (idx == OPT_OFFSET && (intval = strtoul(value, NULL, 0)) <= 16 && !errno) {
  174. offset = intval;
  175. } else if (idx == OPT_PSIDLEN && (intval = strtoul(value, NULL, 0)) <= 16 && !errno) {
  176. psidlen = intval;
  177. } else if (idx == OPT_PSID && (intval = strtoul(value, NULL, 0)) <= 65535 && !errno) {
  178. psid = intval;
  179. } else if (idx == OPT_DMR) {
  180. dmr = value;
  181. } else if (idx == OPT_BR) {
  182. br = value;
  183. } else {
  184. if (idx == -1 || idx >= OPT_MAX)
  185. fprintf(stderr, "Skipped invalid option: %s\n", value);
  186. else
  187. fprintf(stderr, "Skipped invalid value %s for option %s\n",
  188. value, token[idx]);
  189. }
  190. }
  191. if (offset < 0)
  192. offset = (lw4o6) ? 0 : (legacy) ? 4 : 6;
  193. // Find PD
  194. struct blob_attr *c, *cur;
  195. unsigned rem;
  196. blobmsg_for_each_attr(c, dump, rem) {
  197. struct blob_attr *tb[IFACE_ATTR_MAX];
  198. blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blobmsg_data(c), blobmsg_data_len(c));
  199. if (!tb[IFACE_ATTR_INTERFACE] || (strcmp(argv[1], "*") && strcmp(argv[1],
  200. blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]))))
  201. continue;
  202. if ((cur = tb[IFACE_ATTR_PREFIX])) {
  203. if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, NULL))
  204. continue;
  205. struct blob_attr *d;
  206. unsigned drem;
  207. blobmsg_for_each_attr(d, cur, drem) {
  208. struct blob_attr *ptb[PREFIX_ATTR_MAX];
  209. blobmsg_parse(prefix_attrs, PREFIX_ATTR_MAX, ptb,
  210. blobmsg_data(d), blobmsg_data_len(d));
  211. if (!ptb[PREFIX_ATTR_ADDRESS] || !ptb[PREFIX_ATTR_MASK])
  212. continue;
  213. struct in6_addr prefix = IN6ADDR_ANY_INIT;
  214. int mask = blobmsg_get_u32(ptb[PREFIX_ATTR_MASK]);
  215. inet_pton(AF_INET6, blobmsg_get_string(ptb[PREFIX_ATTR_ADDRESS]), &prefix);
  216. if (mask >= prefix6len && !bmemcmp(&prefix, &ipv6prefix, prefix6len)) {
  217. pd = prefix;
  218. pdlen = mask;
  219. iface = blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]);
  220. break;
  221. }
  222. }
  223. if (pdlen >= 0)
  224. break;
  225. }
  226. }
  227. if (ealen < 0 && pdlen >= 0)
  228. ealen = pdlen - prefix6len;
  229. if (psidlen < 0)
  230. psidlen = ealen - (32 - prefix4len);
  231. if (psid < 0 && psidlen <= 16 && psidlen >= 0 && pdlen >= 0 && ealen >= psidlen) {
  232. bmemcpys64(&psid16, &pd, prefix6len + ealen - psidlen, psidlen);
  233. psid = be16_to_cpu(psid16);
  234. }
  235. psid16 = cpu_to_be16(psid >> (16 - psidlen));
  236. if ((pdlen >= 0 || ealen == psidlen) && ealen >= psidlen) {
  237. bmemcpys64(&ipv4addr, &pd, prefix6len, ealen - psidlen);
  238. ipv4addr.s_addr = htonl(ntohl(ipv4addr.s_addr) >> prefix4len);
  239. bmemcpy(&ipv4addr, &ipv4prefix, prefix4len);
  240. if (prefix4len + ealen < 32)
  241. addr4len = prefix4len + ealen;
  242. }
  243. if (prefix4len < 0 || prefix6len < 0 || ealen < 0 || ealen < psidlen) {
  244. fprintf(stderr, "Skipping invalid or incomplete rule: %s\n", argv[i]);
  245. status = 1;
  246. continue;
  247. }
  248. if (pdlen < 0 && !fmr) {
  249. fprintf(stderr, "Skipping non-FMR without matching PD: %s\n", argv[i]);
  250. status = 1;
  251. continue;
  252. } else if (pdlen >= 0) {
  253. size_t v4offset = (legacy) ? 9 : 10;
  254. memcpy(&ipv6addr.s6_addr[v4offset], &ipv4addr, 4);
  255. memcpy(&ipv6addr.s6_addr[v4offset + 4], &psid16, 2);
  256. bmemcpy(&ipv6addr, &pd, pdlen);
  257. }
  258. ++rulecnt;
  259. char ipv4addrbuf[INET_ADDRSTRLEN];
  260. char ipv4prefixbuf[INET_ADDRSTRLEN];
  261. char ipv6prefixbuf[INET6_ADDRSTRLEN];
  262. char ipv6addrbuf[INET6_ADDRSTRLEN];
  263. char pdbuf[INET6_ADDRSTRLEN];
  264. inet_ntop(AF_INET, &ipv4addr, ipv4addrbuf, sizeof(ipv4addrbuf));
  265. inet_ntop(AF_INET, &ipv4prefix, ipv4prefixbuf, sizeof(ipv4prefixbuf));
  266. inet_ntop(AF_INET6, &ipv6prefix, ipv6prefixbuf, sizeof(ipv6prefixbuf));
  267. inet_ntop(AF_INET6, &ipv6addr, ipv6addrbuf, sizeof(ipv6addrbuf));
  268. inet_ntop(AF_INET6, &pd, pdbuf, sizeof(pdbuf));
  269. printf("RULE_%d_FMR=%d\n", rulecnt, fmr);
  270. printf("RULE_%d_EALEN=%d\n", rulecnt, ealen);
  271. printf("RULE_%d_PSIDLEN=%d\n", rulecnt, psidlen);
  272. printf("RULE_%d_OFFSET=%d\n", rulecnt, offset);
  273. printf("RULE_%d_PREFIX4LEN=%d\n", rulecnt, prefix4len);
  274. printf("RULE_%d_PREFIX6LEN=%d\n", rulecnt, prefix6len);
  275. printf("RULE_%d_IPV4PREFIX=%s\n", rulecnt, ipv4prefixbuf);
  276. printf("RULE_%d_IPV6PREFIX=%s\n", rulecnt, ipv6prefixbuf);
  277. if (pdlen >= 0) {
  278. printf("RULE_%d_IPV6PD=%s\n", rulecnt, pdbuf);
  279. printf("RULE_%d_PD6LEN=%d\n", rulecnt, pdlen);
  280. printf("RULE_%d_PD6IFACE=%s\n", rulecnt, iface);
  281. printf("RULE_%d_IPV6ADDR=%s\n", rulecnt, ipv6addrbuf);
  282. printf("RULE_BMR=%d\n", rulecnt);
  283. }
  284. if (ipv4addr.s_addr) {
  285. printf("RULE_%d_IPV4ADDR=%s\n", rulecnt, ipv4addrbuf);
  286. printf("RULE_%d_ADDR4LEN=%d\n", rulecnt, addr4len);
  287. }
  288. if (psidlen == 0) {
  289. printf("RULE_%d_PORTSETS=0-65535\n", rulecnt);
  290. } else if (psid >= 0) {
  291. printf("RULE_%d_PORTSETS='", rulecnt);
  292. for (int k = (offset) ? 1 : 0; k < (1 << offset); ++k) {
  293. int start = (k << (16 - offset)) | (psid >> offset);
  294. int end = start + (1 << (16 - offset - psidlen)) - 1;
  295. printf("%d-%d ", start, end);
  296. }
  297. printf("'\n");
  298. }
  299. if (dmr)
  300. printf("RULE_%d_DMR=%s\n", rulecnt, dmr);
  301. if (br)
  302. printf("RULE_%d_BR=%s\n", rulecnt, br);
  303. }
  304. printf("RULE_COUNT=%d\n", rulecnt);
  305. return status;
  306. }