libip4tc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /* Library which manipulates firewall rules. Version 0.1. */
  2. /* Architecture of firewall rules is as follows:
  3. *
  4. * Chains go INPUT, FORWARD, OUTPUT then user chains.
  5. * Each user chain starts with an ERROR node.
  6. * Every chain ends with an unconditional jump: a RETURN for user chains,
  7. * and a POLICY for built-ins.
  8. */
  9. /* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
  10. COPYING for details). */
  11. #include <assert.h>
  12. #include <string.h>
  13. #include <errno.h>
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <unistd.h>
  17. #ifdef DEBUG_CONNTRACK
  18. #define inline
  19. #endif
  20. #if !defined(__GLIBC__) || (__GLIBC__ < 2)
  21. typedef unsigned int socklen_t;
  22. #endif
  23. #include "libiptc/libiptc.h"
  24. #define IP_VERSION 4
  25. #define IP_OFFSET 0x1FFF
  26. #define HOOK_PRE_ROUTING NF_IP_PRE_ROUTING
  27. #define HOOK_LOCAL_IN NF_IP_LOCAL_IN
  28. #define HOOK_FORWARD NF_IP_FORWARD
  29. #define HOOK_LOCAL_OUT NF_IP_LOCAL_OUT
  30. #define HOOK_POST_ROUTING NF_IP_POST_ROUTING
  31. #define STRUCT_ENTRY_TARGET struct xt_entry_target
  32. #define STRUCT_ENTRY struct ipt_entry
  33. #define STRUCT_ENTRY_MATCH struct xt_entry_match
  34. #define STRUCT_GETINFO struct ipt_getinfo
  35. #define STRUCT_GET_ENTRIES struct ipt_get_entries
  36. #define STRUCT_COUNTERS struct xt_counters
  37. #define STRUCT_COUNTERS_INFO struct xt_counters_info
  38. #define STRUCT_STANDARD_TARGET struct xt_standard_target
  39. #define STRUCT_REPLACE struct ipt_replace
  40. #define ENTRY_ITERATE IPT_ENTRY_ITERATE
  41. #define TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
  42. #define FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
  43. #define GET_TARGET ipt_get_target
  44. #define ERROR_TARGET XT_ERROR_TARGET
  45. #define NUMHOOKS NF_IP_NUMHOOKS
  46. #define IPT_CHAINLABEL xt_chainlabel
  47. #define TC_DUMP_ENTRIES dump_entries
  48. #define TC_IS_CHAIN iptc_is_chain
  49. #define TC_FIRST_CHAIN iptc_first_chain
  50. #define TC_NEXT_CHAIN iptc_next_chain
  51. #define TC_FIRST_RULE iptc_first_rule
  52. #define TC_NEXT_RULE iptc_next_rule
  53. #define TC_GET_TARGET iptc_get_target
  54. #define TC_BUILTIN iptc_builtin
  55. #define TC_GET_POLICY iptc_get_policy
  56. #define TC_INSERT_ENTRY iptc_insert_entry
  57. #define TC_REPLACE_ENTRY iptc_replace_entry
  58. #define TC_APPEND_ENTRY iptc_append_entry
  59. #define TC_CHECK_ENTRY iptc_check_entry
  60. #define TC_DELETE_ENTRY iptc_delete_entry
  61. #define TC_DELETE_NUM_ENTRY iptc_delete_num_entry
  62. #define TC_FLUSH_ENTRIES iptc_flush_entries
  63. #define TC_ZERO_ENTRIES iptc_zero_entries
  64. #define TC_READ_COUNTER iptc_read_counter
  65. #define TC_ZERO_COUNTER iptc_zero_counter
  66. #define TC_SET_COUNTER iptc_set_counter
  67. #define TC_CREATE_CHAIN iptc_create_chain
  68. #define TC_GET_REFERENCES iptc_get_references
  69. #define TC_DELETE_CHAIN iptc_delete_chain
  70. #define TC_RENAME_CHAIN iptc_rename_chain
  71. #define TC_SET_POLICY iptc_set_policy
  72. #define TC_GET_RAW_SOCKET iptc_get_raw_socket
  73. #define TC_INIT iptc_init
  74. #define TC_FREE iptc_free
  75. #define TC_COMMIT iptc_commit
  76. #define TC_STRERROR iptc_strerror
  77. #define TC_NUM_RULES iptc_num_rules
  78. #define TC_GET_RULE iptc_get_rule
  79. #define TC_OPS iptc_ops
  80. #define TC_AF AF_INET
  81. #define TC_IPPROTO IPPROTO_IP
  82. #define SO_SET_REPLACE IPT_SO_SET_REPLACE
  83. #define SO_SET_ADD_COUNTERS IPT_SO_SET_ADD_COUNTERS
  84. #define SO_GET_INFO IPT_SO_GET_INFO
  85. #define SO_GET_ENTRIES IPT_SO_GET_ENTRIES
  86. #define SO_GET_VERSION IPT_SO_GET_VERSION
  87. #define STANDARD_TARGET XT_STANDARD_TARGET
  88. #define LABEL_RETURN IPTC_LABEL_RETURN
  89. #define LABEL_ACCEPT IPTC_LABEL_ACCEPT
  90. #define LABEL_DROP IPTC_LABEL_DROP
  91. #define LABEL_QUEUE IPTC_LABEL_QUEUE
  92. #define ALIGN XT_ALIGN
  93. #define RETURN XT_RETURN
  94. #include "libiptc.c"
  95. #define IP_PARTS_NATIVE(n) \
  96. (unsigned int)((n)>>24)&0xFF, \
  97. (unsigned int)((n)>>16)&0xFF, \
  98. (unsigned int)((n)>>8)&0xFF, \
  99. (unsigned int)((n)&0xFF)
  100. #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
  101. static int
  102. dump_entry(struct ipt_entry *e, struct xtc_handle *const handle)
  103. {
  104. size_t i;
  105. STRUCT_ENTRY_TARGET *t;
  106. printf("Entry %u (%lu):\n", iptcb_entry2index(handle, e),
  107. iptcb_entry2offset(handle, e));
  108. printf("SRC IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
  109. IP_PARTS(e->ip.src.s_addr),IP_PARTS(e->ip.smsk.s_addr));
  110. printf("DST IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
  111. IP_PARTS(e->ip.dst.s_addr),IP_PARTS(e->ip.dmsk.s_addr));
  112. printf("Interface: `%s'/", e->ip.iniface);
  113. for (i = 0; i < IFNAMSIZ; i++)
  114. printf("%c", e->ip.iniface_mask[i] ? 'X' : '.');
  115. printf("to `%s'/", e->ip.outiface);
  116. for (i = 0; i < IFNAMSIZ; i++)
  117. printf("%c", e->ip.outiface_mask[i] ? 'X' : '.');
  118. printf("\nProtocol: %u\n", e->ip.proto);
  119. printf("Flags: %02X\n", e->ip.flags);
  120. printf("Invflags: %02X\n", e->ip.invflags);
  121. printf("Counters: %llu packets, %llu bytes\n",
  122. (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
  123. printf("Cache: %08X\n", e->nfcache);
  124. IPT_MATCH_ITERATE(e, print_match);
  125. t = GET_TARGET(e);
  126. printf("Target name: `%s' [%u]\n", t->u.user.name, t->u.target_size);
  127. if (strcmp(t->u.user.name, STANDARD_TARGET) == 0) {
  128. const unsigned char *data = t->data;
  129. int pos = *(const int *)data;
  130. if (pos < 0)
  131. printf("verdict=%s\n",
  132. pos == -NF_ACCEPT-1 ? "NF_ACCEPT"
  133. : pos == -NF_DROP-1 ? "NF_DROP"
  134. : pos == -NF_QUEUE-1 ? "NF_QUEUE"
  135. : pos == RETURN ? "RETURN"
  136. : "UNKNOWN");
  137. else
  138. printf("verdict=%u\n", pos);
  139. } else if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0)
  140. printf("error=`%s'\n", t->data);
  141. printf("\n");
  142. return 0;
  143. }
  144. static unsigned char *
  145. is_same(const STRUCT_ENTRY *a, const STRUCT_ENTRY *b, unsigned char *matchmask)
  146. {
  147. unsigned int i;
  148. unsigned char *mptr;
  149. /* Always compare head structures: ignore mask here. */
  150. if (a->ip.src.s_addr != b->ip.src.s_addr
  151. || a->ip.dst.s_addr != b->ip.dst.s_addr
  152. || a->ip.smsk.s_addr != b->ip.smsk.s_addr
  153. || a->ip.dmsk.s_addr != b->ip.dmsk.s_addr
  154. || a->ip.proto != b->ip.proto
  155. || a->ip.flags != b->ip.flags
  156. || a->ip.invflags != b->ip.invflags)
  157. return NULL;
  158. for (i = 0; i < IFNAMSIZ; i++) {
  159. if (a->ip.iniface_mask[i] != b->ip.iniface_mask[i])
  160. return NULL;
  161. if ((a->ip.iniface[i] & a->ip.iniface_mask[i])
  162. != (b->ip.iniface[i] & b->ip.iniface_mask[i]))
  163. return NULL;
  164. if (a->ip.outiface_mask[i] != b->ip.outiface_mask[i])
  165. return NULL;
  166. if ((a->ip.outiface[i] & a->ip.outiface_mask[i])
  167. != (b->ip.outiface[i] & b->ip.outiface_mask[i]))
  168. return NULL;
  169. }
  170. if (a->target_offset != b->target_offset
  171. || a->next_offset != b->next_offset)
  172. return NULL;
  173. mptr = matchmask + sizeof(STRUCT_ENTRY);
  174. if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr))
  175. return NULL;
  176. mptr += XT_ALIGN(sizeof(struct xt_entry_target));
  177. return mptr;
  178. }
  179. #if 0
  180. /***************************** DEBUGGING ********************************/
  181. static inline int
  182. unconditional(const struct ipt_ip *ip)
  183. {
  184. unsigned int i;
  185. for (i = 0; i < sizeof(*ip)/sizeof(uint32_t); i++)
  186. if (((uint32_t *)ip)[i])
  187. return 0;
  188. return 1;
  189. }
  190. static inline int
  191. check_match(const STRUCT_ENTRY_MATCH *m, unsigned int *off)
  192. {
  193. assert(m->u.match_size >= sizeof(STRUCT_ENTRY_MATCH));
  194. assert(ALIGN(m->u.match_size) == m->u.match_size);
  195. (*off) += m->u.match_size;
  196. return 0;
  197. }
  198. static inline int
  199. check_entry(const STRUCT_ENTRY *e, unsigned int *i, unsigned int *off,
  200. unsigned int user_offset, int *was_return,
  201. struct xtc_handle *h)
  202. {
  203. unsigned int toff;
  204. STRUCT_STANDARD_TARGET *t;
  205. assert(e->target_offset >= sizeof(STRUCT_ENTRY));
  206. assert(e->next_offset >= e->target_offset
  207. + sizeof(STRUCT_ENTRY_TARGET));
  208. toff = sizeof(STRUCT_ENTRY);
  209. IPT_MATCH_ITERATE(e, check_match, &toff);
  210. assert(toff == e->target_offset);
  211. t = (STRUCT_STANDARD_TARGET *)
  212. GET_TARGET((STRUCT_ENTRY *)e);
  213. /* next_offset will have to be multiple of entry alignment. */
  214. assert(e->next_offset == ALIGN(e->next_offset));
  215. assert(e->target_offset == ALIGN(e->target_offset));
  216. assert(t->target.u.target_size == ALIGN(t->target.u.target_size));
  217. assert(!TC_IS_CHAIN(t->target.u.user.name, h));
  218. if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0) {
  219. assert(t->target.u.target_size
  220. == ALIGN(sizeof(STRUCT_STANDARD_TARGET)));
  221. assert(t->verdict == -NF_DROP-1
  222. || t->verdict == -NF_ACCEPT-1
  223. || t->verdict == RETURN
  224. || t->verdict < (int)h->entries->size);
  225. if (t->verdict >= 0) {
  226. STRUCT_ENTRY *te = get_entry(h, t->verdict);
  227. int idx;
  228. idx = iptcb_entry2index(h, te);
  229. assert(strcmp(GET_TARGET(te)->u.user.name,
  230. XT_ERROR_TARGET)
  231. != 0);
  232. assert(te != e);
  233. /* Prior node must be error node, or this node. */
  234. assert(t->verdict == iptcb_entry2offset(h, e)+e->next_offset
  235. || strcmp(GET_TARGET(index2entry(h, idx-1))
  236. ->u.user.name, XT_ERROR_TARGET)
  237. == 0);
  238. }
  239. if (t->verdict == RETURN
  240. && unconditional(&e->ip)
  241. && e->target_offset == sizeof(*e))
  242. *was_return = 1;
  243. else
  244. *was_return = 0;
  245. } else if (strcmp(t->target.u.user.name, XT_ERROR_TARGET) == 0) {
  246. assert(t->target.u.target_size
  247. == ALIGN(sizeof(struct ipt_error_target)));
  248. /* If this is in user area, previous must have been return */
  249. if (*off > user_offset)
  250. assert(*was_return);
  251. *was_return = 0;
  252. }
  253. else *was_return = 0;
  254. if (*off == user_offset)
  255. assert(strcmp(t->target.u.user.name, XT_ERROR_TARGET) == 0);
  256. (*off) += e->next_offset;
  257. (*i)++;
  258. return 0;
  259. }
  260. #ifdef IPTC_DEBUG
  261. /* Do every conceivable sanity check on the handle */
  262. static void
  263. do_check(struct xtc_handle *h, unsigned int line)
  264. {
  265. unsigned int i, n;
  266. unsigned int user_offset; /* Offset of first user chain */
  267. int was_return;
  268. assert(h->changed == 0 || h->changed == 1);
  269. if (strcmp(h->info.name, "filter") == 0) {
  270. assert(h->info.valid_hooks
  271. == (1 << NF_IP_LOCAL_IN
  272. | 1 << NF_IP_FORWARD
  273. | 1 << NF_IP_LOCAL_OUT));
  274. /* Hooks should be first three */
  275. assert(h->info.hook_entry[NF_IP_LOCAL_IN] == 0);
  276. n = get_chain_end(h, 0);
  277. n += get_entry(h, n)->next_offset;
  278. assert(h->info.hook_entry[NF_IP_FORWARD] == n);
  279. n = get_chain_end(h, n);
  280. n += get_entry(h, n)->next_offset;
  281. assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
  282. user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
  283. } else if (strcmp(h->info.name, "nat") == 0) {
  284. assert((h->info.valid_hooks
  285. == (1 << NF_IP_PRE_ROUTING
  286. | 1 << NF_IP_POST_ROUTING
  287. | 1 << NF_IP_LOCAL_OUT)) ||
  288. (h->info.valid_hooks
  289. == (1 << NF_IP_PRE_ROUTING
  290. | 1 << NF_IP_LOCAL_IN
  291. | 1 << NF_IP_POST_ROUTING
  292. | 1 << NF_IP_LOCAL_OUT)));
  293. assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
  294. n = get_chain_end(h, 0);
  295. n += get_entry(h, n)->next_offset;
  296. assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
  297. n = get_chain_end(h, n);
  298. n += get_entry(h, n)->next_offset;
  299. assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
  300. user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
  301. if (h->info.valid_hooks & (1 << NF_IP_LOCAL_IN)) {
  302. n = get_chain_end(h, n);
  303. n += get_entry(h, n)->next_offset;
  304. assert(h->info.hook_entry[NF_IP_LOCAL_IN] == n);
  305. user_offset = h->info.hook_entry[NF_IP_LOCAL_IN];
  306. }
  307. } else if (strcmp(h->info.name, "mangle") == 0) {
  308. /* This code is getting ugly because linux < 2.4.18-pre6 had
  309. * two mangle hooks, linux >= 2.4.18-pre6 has five mangle hooks
  310. * */
  311. assert((h->info.valid_hooks
  312. == (1 << NF_IP_PRE_ROUTING
  313. | 1 << NF_IP_LOCAL_OUT)) ||
  314. (h->info.valid_hooks
  315. == (1 << NF_IP_PRE_ROUTING
  316. | 1 << NF_IP_LOCAL_IN
  317. | 1 << NF_IP_FORWARD
  318. | 1 << NF_IP_LOCAL_OUT
  319. | 1 << NF_IP_POST_ROUTING)));
  320. /* Hooks should be first five */
  321. assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
  322. n = get_chain_end(h, 0);
  323. if (h->info.valid_hooks & (1 << NF_IP_LOCAL_IN)) {
  324. n += get_entry(h, n)->next_offset;
  325. assert(h->info.hook_entry[NF_IP_LOCAL_IN] == n);
  326. n = get_chain_end(h, n);
  327. }
  328. if (h->info.valid_hooks & (1 << NF_IP_FORWARD)) {
  329. n += get_entry(h, n)->next_offset;
  330. assert(h->info.hook_entry[NF_IP_FORWARD] == n);
  331. n = get_chain_end(h, n);
  332. }
  333. n += get_entry(h, n)->next_offset;
  334. assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
  335. user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
  336. if (h->info.valid_hooks & (1 << NF_IP_POST_ROUTING)) {
  337. n = get_chain_end(h, n);
  338. n += get_entry(h, n)->next_offset;
  339. assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
  340. user_offset = h->info.hook_entry[NF_IP_POST_ROUTING];
  341. }
  342. } else if (strcmp(h->info.name, "raw") == 0) {
  343. assert(h->info.valid_hooks
  344. == (1 << NF_IP_PRE_ROUTING
  345. | 1 << NF_IP_LOCAL_OUT));
  346. /* Hooks should be first three */
  347. assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
  348. n = get_chain_end(h, n);
  349. n += get_entry(h, n)->next_offset;
  350. assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
  351. user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
  352. } else {
  353. fprintf(stderr, "Unknown table `%s'\n", h->info.name);
  354. abort();
  355. }
  356. /* User chain == end of last builtin + policy entry */
  357. user_offset = get_chain_end(h, user_offset);
  358. user_offset += get_entry(h, user_offset)->next_offset;
  359. /* Overflows should be end of entry chains, and unconditional
  360. policy nodes. */
  361. for (i = 0; i < NUMHOOKS; i++) {
  362. STRUCT_ENTRY *e;
  363. STRUCT_STANDARD_TARGET *t;
  364. if (!(h->info.valid_hooks & (1 << i)))
  365. continue;
  366. assert(h->info.underflow[i]
  367. == get_chain_end(h, h->info.hook_entry[i]));
  368. e = get_entry(h, get_chain_end(h, h->info.hook_entry[i]));
  369. assert(unconditional(&e->ip));
  370. assert(e->target_offset == sizeof(*e));
  371. t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
  372. assert(t->target.u.target_size == ALIGN(sizeof(*t)));
  373. assert(e->next_offset == sizeof(*e) + ALIGN(sizeof(*t)));
  374. assert(strcmp(t->target.u.user.name, STANDARD_TARGET)==0);
  375. assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1);
  376. /* Hooks and underflows must be valid entries */
  377. entry2index(h, get_entry(h, h->info.hook_entry[i]));
  378. entry2index(h, get_entry(h, h->info.underflow[i]));
  379. }
  380. assert(h->info.size
  381. >= h->info.num_entries * (sizeof(STRUCT_ENTRY)
  382. +sizeof(STRUCT_STANDARD_TARGET)));
  383. assert(h->entries.size
  384. >= (h->new_number
  385. * (sizeof(STRUCT_ENTRY)
  386. + sizeof(STRUCT_STANDARD_TARGET))));
  387. assert(strcmp(h->info.name, h->entries.name) == 0);
  388. i = 0; n = 0;
  389. was_return = 0;
  390. /* Check all the entries. */
  391. ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
  392. check_entry, &i, &n, user_offset, &was_return, h);
  393. assert(i == h->new_number);
  394. assert(n == h->entries.size);
  395. /* Final entry must be error node */
  396. assert(strcmp(GET_TARGET(index2entry(h, h->new_number-1))
  397. ->u.user.name,
  398. ERROR_TARGET) == 0);
  399. }
  400. #endif /*IPTC_DEBUG*/
  401. #endif