ip6_tables.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:45k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Packet matching code.
  3.  *
  4.  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
  5.  * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org>
  6.  *
  7.  * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
  8.  *  - increase module usage count as soon as we have rules inside
  9.  *    a table
  10.  */
  11. #include <linux/config.h>
  12. #include <linux/skbuff.h>
  13. #include <linux/kmod.h>
  14. #include <linux/vmalloc.h>
  15. #include <linux/netdevice.h>
  16. #include <linux/module.h>
  17. #include <linux/tcp.h>
  18. #include <linux/udp.h>
  19. #include <linux/icmpv6.h>
  20. #include <net/ip.h>
  21. #include <asm/uaccess.h>
  22. #include <asm/semaphore.h>
  23. #include <linux/proc_fs.h>
  24. #include <linux/netfilter_ipv6/ip6_tables.h>
  25. #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
  26. /*#define DEBUG_IP_FIREWALL*/
  27. /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
  28. /*#define DEBUG_IP_FIREWALL_USER*/
  29. #ifdef DEBUG_IP_FIREWALL
  30. #define dprintf(format, args...)  printk(format , ## args)
  31. #else
  32. #define dprintf(format, args...)
  33. #endif
  34. #ifdef DEBUG_IP_FIREWALL_USER
  35. #define duprintf(format, args...) printk(format , ## args)
  36. #else
  37. #define duprintf(format, args...)
  38. #endif
  39. #ifdef CONFIG_NETFILTER_DEBUG
  40. #define IP_NF_ASSERT(x)
  41. do {
  42. if (!(x))
  43. printk("IP_NF_ASSERT: %s:%s:%un",
  44.        __FUNCTION__, __FILE__, __LINE__);
  45. } while(0)
  46. #else
  47. #define IP_NF_ASSERT(x)
  48. #endif
  49. #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
  50. /* Mutex protects lists (only traversed in user context). */
  51. static DECLARE_MUTEX(ip6t_mutex);
  52. /* Must have mutex */
  53. #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
  54. #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
  55. #include <linux/netfilter_ipv4/lockhelp.h>
  56. #include <linux/netfilter_ipv4/listhelp.h>
  57. #if 0
  58. /* All the better to debug you with... */
  59. #define static
  60. #define inline
  61. #endif
  62. /* Locking is simple: we assume at worst case there will be one packet
  63.    in user context and one from bottom halves (or soft irq if Alexey's
  64.    softnet patch was applied).
  65.    We keep a set of rules for each CPU, so we can avoid write-locking
  66.    them; doing a readlock_bh() stops packets coming through if we're
  67.    in user context.
  68.    To be cache friendly on SMP, we arrange them like so:
  69.    [ n-entries ]
  70.    ... cache-align padding ...
  71.    [ n-entries ]
  72.    Hence the start of any table is given by get_table() below.  */
  73. /* The table itself */
  74. struct ip6t_table_info
  75. {
  76. /* Size per table */
  77. unsigned int size;
  78. /* Number of entries: FIXME. --RR */
  79. unsigned int number;
  80. /* Initial number of entries. Needed for module usage count */
  81. unsigned int initial_entries;
  82. /* Entry points and underflows */
  83. unsigned int hook_entry[NF_IP6_NUMHOOKS];
  84. unsigned int underflow[NF_IP6_NUMHOOKS];
  85. char padding[SMP_ALIGN((NF_IP6_NUMHOOKS*2+2)*sizeof(unsigned int))];
  86. /* ip6t_entry tables: one per CPU */
  87. char entries[0];
  88. };
  89. static LIST_HEAD(ip6t_target);
  90. static LIST_HEAD(ip6t_match);
  91. static LIST_HEAD(ip6t_tables);
  92. #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
  93. #ifdef CONFIG_SMP
  94. #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*cpu_number_map(p))
  95. #else
  96. #define TABLE_OFFSET(t,p) 0
  97. #endif
  98. #if 0
  99. #define down(x) do { printk("DOWN:%u:" #x "n", __LINE__); down(x); } while(0)
  100. #define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%un", __LINE__); __r; })
  101. #define up(x) do { printk("UP:%u:" #x "n", __LINE__); up(x); } while(0)
  102. #endif
  103. static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
  104.       struct in6_addr addr2)
  105. {
  106. int i;
  107. for( i = 0; i < 16; i++){
  108. if((addr1.s6_addr[i] & mask.s6_addr[i]) != 
  109.    (addr2.s6_addr[i] & mask.s6_addr[i]))
  110. return 1;
  111. }
  112. return 0;
  113. }
  114. /* takes in current header and pointer to the header */
  115. /* if another header exists, sets hdrptr to the next header
  116.    and returns the new header value, else returns 0 */
  117. static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t *hdrptr)
  118. {
  119. int i;
  120. u_int8_t hdrlen, nexthdr = 0;
  121. switch(currenthdr){
  122. case IPPROTO_AH:
  123. /* whoever decided to do the length of AUTH for ipv6
  124. in 32bit units unlike other headers should be beaten...
  125. repeatedly...with a large stick...no, an even LARGER
  126. stick...no, you're still not thinking big enough */
  127. nexthdr = *hdrptr;
  128. hdrlen = hdrptr[i] * 4 + 8;
  129. hdrptr = hdrptr + hdrlen;
  130. break;
  131. /*stupid rfc2402 */
  132. case IPPROTO_DSTOPTS:
  133. case IPPROTO_ROUTING:
  134. case IPPROTO_HOPOPTS:
  135. nexthdr = *hdrptr;
  136. hdrlen = hdrptr[1] * 8 + 8;
  137. hdrptr = hdrptr + hdrlen;
  138. break;
  139. case IPPROTO_FRAGMENT:
  140. nexthdr = *hdrptr;
  141. hdrptr = hdrptr + 8;
  142. break;
  143. }
  144. return nexthdr;
  145. }
  146. /* Returns whether matches rule or not. */
  147. static inline int
  148. ip6_packet_match(const struct ipv6hdr *ipv6,
  149.  const char *indev,
  150.  const char *outdev,
  151.  const struct ip6t_ip6 *ip6info,
  152.  int isfrag)
  153. {
  154. size_t i;
  155. unsigned long ret;
  156. #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
  157. if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
  158.   IP6T_INV_SRCIP)
  159.     || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
  160.      IP6T_INV_DSTIP)) {
  161. dprintf("Source or dest mismatch.n");
  162. /*
  163. dprintf("SRC: %u. Mask: %u. Target: %u.%sn", ip->saddr,
  164. ipinfo->smsk.s_addr, ipinfo->src.s_addr,
  165. ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
  166. dprintf("DST: %u. Mask: %u. Target: %u.%sn", ip->daddr,
  167. ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
  168. ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
  169. return 0;
  170. }
  171. /* Look for ifname matches; this should unroll nicely. */
  172. for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
  173. ret |= (((const unsigned long *)indev)[i]
  174. ^ ((const unsigned long *)ip6info->iniface)[i])
  175. & ((const unsigned long *)ip6info->iniface_mask)[i];
  176. }
  177. if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
  178. dprintf("VIA in mismatch (%s vs %s).%sn",
  179. indev, ip6info->iniface,
  180. ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
  181. return 0;
  182. }
  183. for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
  184. ret |= (((const unsigned long *)outdev)[i]
  185. ^ ((const unsigned long *)ip6info->outiface)[i])
  186. & ((const unsigned long *)ip6info->outiface_mask)[i];
  187. }
  188. if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
  189. dprintf("VIA out mismatch (%s vs %s).%sn",
  190. outdev, ip6info->outiface,
  191. ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
  192. return 0;
  193. }
  194. /* ... might want to do something with class and flowlabel here ... */
  195. /* look for the desired protocol header */
  196. if((ip6info->flags & IP6T_F_PROTO)) {
  197. u_int8_t currenthdr = ipv6->nexthdr;
  198. u_int8_t *hdrptr;
  199. hdrptr = (u_int8_t *)(ipv6 + 1);
  200. do {
  201. if (ip6info->proto == currenthdr) {
  202. if(ip6info->invflags & IP6T_INV_PROTO)
  203. return 0;
  204. return 1;
  205. }
  206. currenthdr = ip6_nexthdr(currenthdr, hdrptr);
  207. } while(currenthdr);
  208. if (!(ip6info->invflags & IP6T_INV_PROTO))
  209. return 0;
  210. }
  211. return 1;
  212. }
  213. /* should be ip6 safe */
  214. static inline int 
  215. ip6_checkentry(const struct ip6t_ip6 *ipv6)
  216. {
  217. if (ipv6->flags & ~IP6T_F_MASK) {
  218. duprintf("Unknown flag bits set: %08Xn",
  219.  ipv6->flags & ~IP6T_F_MASK);
  220. return 0;
  221. }
  222. if (ipv6->invflags & ~IP6T_INV_MASK) {
  223. duprintf("Unknown invflag bits set: %08Xn",
  224.  ipv6->invflags & ~IP6T_INV_MASK);
  225. return 0;
  226. }
  227. return 1;
  228. }
  229. static unsigned int
  230. ip6t_error(struct sk_buff **pskb,
  231.   unsigned int hooknum,
  232.   const struct net_device *in,
  233.   const struct net_device *out,
  234.   const void *targinfo,
  235.   void *userinfo)
  236. {
  237. if (net_ratelimit())
  238. printk("ip6_tables: error: `%s'n", (char *)targinfo);
  239. return NF_DROP;
  240. }
  241. static inline
  242. int do_match(struct ip6t_entry_match *m,
  243.      const struct sk_buff *skb,
  244.      const struct net_device *in,
  245.      const struct net_device *out,
  246.      int offset,
  247.      const void *hdr,
  248.      u_int16_t datalen,
  249.      int *hotdrop)
  250. {
  251. /* Stop iteration if it doesn't match */
  252. if (!m->u.kernel.match->match(skb, in, out, m->data,
  253.       offset, hdr, datalen, hotdrop))
  254. return 1;
  255. else
  256. return 0;
  257. }
  258. static inline struct ip6t_entry *
  259. get_entry(void *base, unsigned int offset)
  260. {
  261. return (struct ip6t_entry *)(base + offset);
  262. }
  263. /* Returns one of the generic firewall policies, like NF_ACCEPT. */
  264. unsigned int
  265. ip6t_do_table(struct sk_buff **pskb,
  266.       unsigned int hook,
  267.       const struct net_device *in,
  268.       const struct net_device *out,
  269.       struct ip6t_table *table,
  270.       void *userdata)
  271. {
  272. static const char nulldevname[IFNAMSIZ] = { 0 };
  273. u_int16_t offset = 0;
  274. struct ipv6hdr *ipv6;
  275. void *protohdr;
  276. u_int16_t datalen;
  277. int hotdrop = 0;
  278. /* Initializing verdict to NF_DROP keeps gcc happy. */
  279. unsigned int verdict = NF_DROP;
  280. const char *indev, *outdev;
  281. void *table_base;
  282. struct ip6t_entry *e, *back;
  283. /* Initialization */
  284. ipv6 = (*pskb)->nh.ipv6h;
  285. protohdr = (u_int32_t *)((char *)ipv6 + IPV6_HDR_LEN);
  286. datalen = (*pskb)->len - IPV6_HDR_LEN;
  287. indev = in ? in->name : nulldevname;
  288. outdev = out ? out->name : nulldevname;
  289. /* We handle fragments by dealing with the first fragment as
  290.  * if it was a normal packet.  All other fragments are treated
  291.  * normally, except that they will NEVER match rules that ask
  292.  * things we don't know, ie. tcp syn flag or ports).  If the
  293.  * rule is also a fragment-specific rule, non-fragments won't
  294.  * match it. */
  295. read_lock_bh(&table->lock);
  296. IP_NF_ASSERT(table->valid_hooks & (1 << hook));
  297. table_base = (void *)table->private->entries
  298. + TABLE_OFFSET(table->private, smp_processor_id());
  299. e = get_entry(table_base, table->private->hook_entry[hook]);
  300. #ifdef CONFIG_NETFILTER_DEBUG
  301. /* Check noone else using our table */
  302. if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
  303.     && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
  304. printk("ASSERT: CPU #%u, %s comefrom(%p) = %Xn",
  305.        smp_processor_id(),
  306.        table->name,
  307.        &((struct ip6t_entry *)table_base)->comefrom,
  308.        ((struct ip6t_entry *)table_base)->comefrom);
  309. }
  310. ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
  311. #endif
  312. /* For return from builtin chain */
  313. back = get_entry(table_base, table->private->underflow[hook]);
  314. do {
  315. IP_NF_ASSERT(e);
  316. IP_NF_ASSERT(back);
  317. (*pskb)->nfcache |= e->nfcache;
  318. if (ip6_packet_match(ipv6, indev, outdev, &e->ipv6, offset)) {
  319. struct ip6t_entry_target *t;
  320. if (IP6T_MATCH_ITERATE(e, do_match,
  321.        *pskb, in, out,
  322.        offset, protohdr,
  323.        datalen, &hotdrop) != 0)
  324. goto no_match;
  325. ADD_COUNTER(e->counters, ntohs(ipv6->payload_len) + IPV6_HDR_LEN, 1);
  326. t = ip6t_get_target(e);
  327. IP_NF_ASSERT(t->u.kernel.target);
  328. /* Standard target? */
  329. if (!t->u.kernel.target->target) {
  330. int v;
  331. v = ((struct ip6t_standard_target *)t)->verdict;
  332. if (v < 0) {
  333. /* Pop from stack? */
  334. if (v != IP6T_RETURN) {
  335. verdict = (unsigned)(-v) - 1;
  336. break;
  337. }
  338. e = back;
  339. back = get_entry(table_base,
  340.  back->comefrom);
  341. continue;
  342. }
  343. if (table_base + v
  344.     != (void *)e + e->next_offset) {
  345. /* Save old back ptr in next entry */
  346. struct ip6t_entry *next
  347. = (void *)e + e->next_offset;
  348. next->comefrom
  349. = (void *)back - table_base;
  350. /* set back pointer to next entry */
  351. back = next;
  352. }
  353. e = get_entry(table_base, v);
  354. } else {
  355. /* Targets which reenter must return
  356.                                    abs. verdicts */
  357. #ifdef CONFIG_NETFILTER_DEBUG
  358. ((struct ip6t_entry *)table_base)->comefrom
  359. = 0xeeeeeeec;
  360. #endif
  361. verdict = t->u.kernel.target->target(pskb,
  362.      hook,
  363.      in, out,
  364.      t->data,
  365.      userdata);
  366. #ifdef CONFIG_NETFILTER_DEBUG
  367. if (((struct ip6t_entry *)table_base)->comefrom
  368.     != 0xeeeeeeec
  369.     && verdict == IP6T_CONTINUE) {
  370. printk("Target %s reentered!n",
  371.        t->u.kernel.target->name);
  372. verdict = NF_DROP;
  373. }
  374. ((struct ip6t_entry *)table_base)->comefrom
  375. = 0x57acc001;
  376. #endif
  377. /* Target might have changed stuff. */
  378. ipv6 = (*pskb)->nh.ipv6h;
  379. protohdr = (u_int32_t *)ipv6 + IPV6_HDR_LEN;
  380. datalen = (*pskb)->len - IPV6_HDR_LEN;
  381. if (verdict == IP6T_CONTINUE)
  382. e = (void *)e + e->next_offset;
  383. else
  384. /* Verdict */
  385. break;
  386. }
  387. } else {
  388. no_match:
  389. e = (void *)e + e->next_offset;
  390. }
  391. } while (!hotdrop);
  392. #ifdef CONFIG_NETFILTER_DEBUG
  393. ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
  394. #endif
  395. read_unlock_bh(&table->lock);
  396. #ifdef DEBUG_ALLOW_ALL
  397. return NF_ACCEPT;
  398. #else
  399. if (hotdrop)
  400. return NF_DROP;
  401. else return verdict;
  402. #endif
  403. }
  404. /* If it succeeds, returns element and locks mutex */
  405. static inline void *
  406. find_inlist_lock_noload(struct list_head *head,
  407. const char *name,
  408. int *error,
  409. struct semaphore *mutex)
  410. {
  411. void *ret;
  412. #if 1
  413. duprintf("find_inlist: searching for `%s' in %s.n",
  414.  name, head == &ip6t_target ? "ip6t_target"
  415.  : head == &ip6t_match ? "ip6t_match"
  416.  : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
  417. #endif
  418. *error = down_interruptible(mutex);
  419. if (*error != 0)
  420. return NULL;
  421. ret = list_named_find(head, name);
  422. if (!ret) {
  423. *error = -ENOENT;
  424. up(mutex);
  425. }
  426. return ret;
  427. }
  428. #ifndef CONFIG_KMOD
  429. #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
  430. #else
  431. static void *
  432. find_inlist_lock(struct list_head *head,
  433.  const char *name,
  434.  const char *prefix,
  435.  int *error,
  436.  struct semaphore *mutex)
  437. {
  438. void *ret;
  439. ret = find_inlist_lock_noload(head, name, error, mutex);
  440. if (!ret) {
  441. char modulename[IP6T_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
  442. strcpy(modulename, prefix);
  443. strcat(modulename, name);
  444. duprintf("find_inlist: loading `%s'.n", modulename);
  445. request_module(modulename);
  446. ret = find_inlist_lock_noload(head, name, error, mutex);
  447. }
  448. return ret;
  449. }
  450. #endif
  451. static inline struct ip6t_table *
  452. find_table_lock(const char *name, int *error, struct semaphore *mutex)
  453. {
  454. return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
  455. }
  456. static inline struct ip6t_match *
  457. find_match_lock(const char *name, int *error, struct semaphore *mutex)
  458. {
  459. return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
  460. }
  461. static inline struct ip6t_target *
  462. find_target_lock(const char *name, int *error, struct semaphore *mutex)
  463. {
  464. return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
  465. }
  466. /* All zeroes == unconditional rule. */
  467. static inline int
  468. unconditional(const struct ip6t_ip6 *ipv6)
  469. {
  470. unsigned int i;
  471. for (i = 0; i < sizeof(*ipv6); i++)
  472. if (((char *)ipv6)[i])
  473. break;
  474. return (i == sizeof(*ipv6));
  475. }
  476. /* Figures out from what hook each rule can be called: returns 0 if
  477.    there are loops.  Puts hook bitmask in comefrom. */
  478. static int
  479. mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
  480. {
  481. unsigned int hook;
  482. /* No recursion; use packet counter to save back ptrs (reset
  483.    to 0 as we leave), and comefrom to save source hook bitmask */
  484. for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
  485. unsigned int pos = newinfo->hook_entry[hook];
  486. struct ip6t_entry *e
  487. = (struct ip6t_entry *)(newinfo->entries + pos);
  488. if (!(valid_hooks & (1 << hook)))
  489. continue;
  490. /* Set initial back pointer. */
  491. e->counters.pcnt = pos;
  492. for (;;) {
  493. struct ip6t_standard_target *t
  494. = (void *)ip6t_get_target(e);
  495. if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
  496. printk("iptables: loop hook %u pos %u %08X.n",
  497.        hook, pos, e->comefrom);
  498. return 0;
  499. }
  500. e->comefrom
  501. |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
  502. /* Unconditional return/END. */
  503. if (e->target_offset == sizeof(struct ip6t_entry)
  504.     && (strcmp(t->target.u.user.name,
  505.        IP6T_STANDARD_TARGET) == 0)
  506.     && t->verdict < 0
  507.     && unconditional(&e->ipv6)) {
  508. unsigned int oldpos, size;
  509. /* Return: backtrack through the last
  510.    big jump. */
  511. do {
  512. e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
  513. #ifdef DEBUG_IP_FIREWALL_USER
  514. if (e->comefrom
  515.     & (1 << NF_IP6_NUMHOOKS)) {
  516. duprintf("Back unset "
  517.  "on hook %u "
  518.  "rule %un",
  519.  hook, pos);
  520. }
  521. #endif
  522. oldpos = pos;
  523. pos = e->counters.pcnt;
  524. e->counters.pcnt = 0;
  525. /* We're at the start. */
  526. if (pos == oldpos)
  527. goto next;
  528. e = (struct ip6t_entry *)
  529. (newinfo->entries + pos);
  530. } while (oldpos == pos + e->next_offset);
  531. /* Move along one */
  532. size = e->next_offset;
  533. e = (struct ip6t_entry *)
  534. (newinfo->entries + pos + size);
  535. e->counters.pcnt = pos;
  536. pos += size;
  537. } else {
  538. int newpos = t->verdict;
  539. if (strcmp(t->target.u.user.name,
  540.    IP6T_STANDARD_TARGET) == 0
  541.     && newpos >= 0) {
  542. /* This a jump; chase it. */
  543. duprintf("Jump rule %u -> %un",
  544.  pos, newpos);
  545. } else {
  546. /* ... this is a fallthru */
  547. newpos = pos + e->next_offset;
  548. }
  549. e = (struct ip6t_entry *)
  550. (newinfo->entries + newpos);
  551. e->counters.pcnt = pos;
  552. pos = newpos;
  553. }
  554. }
  555. next:
  556. duprintf("Finished chain %un", hook);
  557. }
  558. return 1;
  559. }
  560. static inline int
  561. cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
  562. {
  563. if (i && (*i)-- == 0)
  564. return 1;
  565. if (m->u.kernel.match->destroy)
  566. m->u.kernel.match->destroy(m->data,
  567.    m->u.match_size - sizeof(*m));
  568. if (m->u.kernel.match->me)
  569. __MOD_DEC_USE_COUNT(m->u.kernel.match->me);
  570. return 0;
  571. }
  572. static inline int
  573. standard_check(const struct ip6t_entry_target *t,
  574.        unsigned int max_offset)
  575. {
  576. struct ip6t_standard_target *targ = (void *)t;
  577. /* Check standard info. */
  578. if (t->u.target_size
  579.     != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
  580. duprintf("standard_check: target size %u != %un",
  581.  t->u.target_size,
  582.  IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
  583. return 0;
  584. }
  585. if (targ->verdict >= 0
  586.     && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
  587. duprintf("ip6t_standard_check: bad verdict (%i)n",
  588.  targ->verdict);
  589. return 0;
  590. }
  591. if (targ->verdict < -NF_MAX_VERDICT - 1) {
  592. duprintf("ip6t_standard_check: bad negative verdict (%i)n",
  593.  targ->verdict);
  594. return 0;
  595. }
  596. return 1;
  597. }
  598. static inline int
  599. check_match(struct ip6t_entry_match *m,
  600.     const char *name,
  601.     const struct ip6t_ip6 *ipv6,
  602.     unsigned int hookmask,
  603.     unsigned int *i)
  604. {
  605. int ret;
  606. struct ip6t_match *match;
  607. match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
  608. if (!match) {
  609.   // duprintf("check_match: `%s' not foundn", m->u.name);
  610. return ret;
  611. }
  612. if (match->me)
  613. __MOD_INC_USE_COUNT(match->me);
  614. m->u.kernel.match = match;
  615. up(&ip6t_mutex);
  616. if (m->u.kernel.match->checkentry
  617.     && !m->u.kernel.match->checkentry(name, ipv6, m->data,
  618.       m->u.match_size - sizeof(*m),
  619.       hookmask)) {
  620. if (m->u.kernel.match->me)
  621. __MOD_DEC_USE_COUNT(m->u.kernel.match->me);
  622. duprintf("ip_tables: check failed for `%s'.n",
  623.  m->u.kernel.match->name);
  624. return -EINVAL;
  625. }
  626. (*i)++;
  627. return 0;
  628. }
  629. static struct ip6t_target ip6t_standard_target;
  630. static inline int
  631. check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
  632.     unsigned int *i)
  633. {
  634. struct ip6t_entry_target *t;
  635. struct ip6t_target *target;
  636. int ret;
  637. unsigned int j;
  638. if (!ip6_checkentry(&e->ipv6)) {
  639. duprintf("ip_tables: ip check failed %p %s.n", e, name);
  640. return -EINVAL;
  641. }
  642. j = 0;
  643. ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
  644. if (ret != 0)
  645. goto cleanup_matches;
  646. t = ip6t_get_target(e);
  647. target = find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
  648. if (!target) {
  649. duprintf("check_entry: `%s' not foundn", t->u.user.name);
  650. goto cleanup_matches;
  651. }
  652. if (target->me)
  653. __MOD_INC_USE_COUNT(target->me);
  654. t->u.kernel.target = target;
  655. up(&ip6t_mutex);
  656. if (t->u.kernel.target == &ip6t_standard_target) {
  657. if (!standard_check(t, size)) {
  658. ret = -EINVAL;
  659. goto cleanup_matches;
  660. }
  661. } else if (t->u.kernel.target->checkentry
  662.    && !t->u.kernel.target->checkentry(name, e, t->data,
  663.       t->u.target_size
  664.       - sizeof(*t),
  665.       e->comefrom)) {
  666. if (t->u.kernel.target->me)
  667. __MOD_DEC_USE_COUNT(t->u.kernel.target->me);
  668. duprintf("ip_tables: check failed for `%s'.n",
  669.  t->u.kernel.target->name);
  670. ret = -EINVAL;
  671. goto cleanup_matches;
  672. }
  673. (*i)++;
  674. return 0;
  675.  cleanup_matches:
  676. IP6T_MATCH_ITERATE(e, cleanup_match, &j);
  677. return ret;
  678. }
  679. static inline int
  680. check_entry_size_and_hooks(struct ip6t_entry *e,
  681.    struct ip6t_table_info *newinfo,
  682.    unsigned char *base,
  683.    unsigned char *limit,
  684.    const unsigned int *hook_entries,
  685.    const unsigned int *underflows,
  686.    unsigned int *i)
  687. {
  688. unsigned int h;
  689. if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
  690.     || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
  691. duprintf("Bad offset %pn", e);
  692. return -EINVAL;
  693. }
  694. if (e->next_offset
  695.     < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
  696. duprintf("checking: element %p size %un",
  697.  e, e->next_offset);
  698. return -EINVAL;
  699. }
  700. /* Check hooks & underflows */
  701. for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
  702. if ((unsigned char *)e - base == hook_entries[h])
  703. newinfo->hook_entry[h] = hook_entries[h];
  704. if ((unsigned char *)e - base == underflows[h])
  705. newinfo->underflow[h] = underflows[h];
  706. }
  707. /* FIXME: underflows must be unconditional, standard verdicts
  708.            < 0 (not IP6T_RETURN). --RR */
  709. /* Clear counters and comefrom */
  710. e->counters = ((struct ip6t_counters) { 0, 0 });
  711. e->comefrom = 0;
  712. (*i)++;
  713. return 0;
  714. }
  715. static inline int
  716. cleanup_entry(struct ip6t_entry *e, unsigned int *i)
  717. {
  718. struct ip6t_entry_target *t;
  719. if (i && (*i)-- == 0)
  720. return 1;
  721. /* Cleanup all matches */
  722. IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
  723. t = ip6t_get_target(e);
  724. if (t->u.kernel.target->destroy)
  725. t->u.kernel.target->destroy(t->data,
  726.     t->u.target_size - sizeof(*t));
  727. if (t->u.kernel.target->me)
  728. __MOD_DEC_USE_COUNT(t->u.kernel.target->me);
  729. return 0;
  730. }
  731. /* Checks and translates the user-supplied table segment (held in
  732.    newinfo) */
  733. static int
  734. translate_table(const char *name,
  735. unsigned int valid_hooks,
  736. struct ip6t_table_info *newinfo,
  737. unsigned int size,
  738. unsigned int number,
  739. const unsigned int *hook_entries,
  740. const unsigned int *underflows)
  741. {
  742. unsigned int i;
  743. int ret;
  744. newinfo->size = size;
  745. newinfo->number = number;
  746. /* Init all hooks to impossible value. */
  747. for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
  748. newinfo->hook_entry[i] = 0xFFFFFFFF;
  749. newinfo->underflow[i] = 0xFFFFFFFF;
  750. }
  751. duprintf("translate_table: size %un", newinfo->size);
  752. i = 0;
  753. /* Walk through entries, checking offsets. */
  754. ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
  755. check_entry_size_and_hooks,
  756. newinfo,
  757. newinfo->entries,
  758. newinfo->entries + size,
  759. hook_entries, underflows, &i);
  760. if (ret != 0)
  761. return ret;
  762. if (i != number) {
  763. duprintf("translate_table: %u not %u entriesn",
  764.  i, number);
  765. return -EINVAL;
  766. }
  767. /* Check hooks all assigned */
  768. for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
  769. /* Only hooks which are valid */
  770. if (!(valid_hooks & (1 << i)))
  771. continue;
  772. if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
  773. duprintf("Invalid hook entry %u %un",
  774.  i, hook_entries[i]);
  775. return -EINVAL;
  776. }
  777. if (newinfo->underflow[i] == 0xFFFFFFFF) {
  778. duprintf("Invalid underflow %u %un",
  779.  i, underflows[i]);
  780. return -EINVAL;
  781. }
  782. }
  783. if (!mark_source_chains(newinfo, valid_hooks))
  784. return -ELOOP;
  785. /* Finally, each sanity check must pass */
  786. i = 0;
  787. ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
  788. check_entry, name, size, &i);
  789. if (ret != 0) {
  790. IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
  791.   cleanup_entry, &i);
  792. return ret;
  793. }
  794. /* And one copy for every other CPU */
  795. for (i = 1; i < smp_num_cpus; i++) {
  796. memcpy(newinfo->entries + SMP_ALIGN(newinfo->size*i),
  797.        newinfo->entries,
  798.        SMP_ALIGN(newinfo->size));
  799. }
  800. return ret;
  801. }
  802. static struct ip6t_table_info *
  803. replace_table(struct ip6t_table *table,
  804.       unsigned int num_counters,
  805.       struct ip6t_table_info *newinfo,
  806.       int *error)
  807. {
  808. struct ip6t_table_info *oldinfo;
  809. #ifdef CONFIG_NETFILTER_DEBUG
  810. {
  811. struct ip6t_entry *table_base;
  812. unsigned int i;
  813. for (i = 0; i < smp_num_cpus; i++) {
  814. table_base =
  815. (void *)newinfo->entries
  816. + TABLE_OFFSET(newinfo, i);
  817. table_base->comefrom = 0xdead57ac;
  818. }
  819. }
  820. #endif
  821. /* Do the substitution. */
  822. write_lock_bh(&table->lock);
  823. /* Check inside lock: is the old number correct? */
  824. if (num_counters != table->private->number) {
  825. duprintf("num_counters != table->private->number (%u/%u)n",
  826.  num_counters, table->private->number);
  827. write_unlock_bh(&table->lock);
  828. *error = -EAGAIN;
  829. return NULL;
  830. }
  831. oldinfo = table->private;
  832. table->private = newinfo;
  833. newinfo->initial_entries = oldinfo->initial_entries;
  834. write_unlock_bh(&table->lock);
  835. return oldinfo;
  836. }
  837. /* Gets counters. */
  838. static inline int
  839. add_entry_to_counter(const struct ip6t_entry *e,
  840.      struct ip6t_counters total[],
  841.      unsigned int *i)
  842. {
  843. ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
  844. (*i)++;
  845. return 0;
  846. }
  847. static void
  848. get_counters(const struct ip6t_table_info *t,
  849.      struct ip6t_counters counters[])
  850. {
  851. unsigned int cpu;
  852. unsigned int i;
  853. for (cpu = 0; cpu < smp_num_cpus; cpu++) {
  854. i = 0;
  855. IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
  856.   t->size,
  857.   add_entry_to_counter,
  858.   counters,
  859.   &i);
  860. }
  861. }
  862. static int
  863. copy_entries_to_user(unsigned int total_size,
  864.      struct ip6t_table *table,
  865.      void *userptr)
  866. {
  867. unsigned int off, num, countersize;
  868. struct ip6t_entry *e;
  869. struct ip6t_counters *counters;
  870. int ret = 0;
  871. /* We need atomic snapshot of counters: rest doesn't change
  872.    (other than comefrom, which userspace doesn't care
  873.    about). */
  874. countersize = sizeof(struct ip6t_counters) * table->private->number;
  875. counters = vmalloc(countersize);
  876. if (counters == NULL)
  877. return -ENOMEM;
  878. /* First, sum counters... */
  879. memset(counters, 0, countersize);
  880. write_lock_bh(&table->lock);
  881. get_counters(table->private, counters);
  882. write_unlock_bh(&table->lock);
  883. /* ... then copy entire thing from CPU 0... */
  884. if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
  885. ret = -EFAULT;
  886. goto free_counters;
  887. }
  888. /* FIXME: use iterator macros --RR */
  889. /* ... then go back and fix counters and names */
  890. for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
  891. unsigned int i;
  892. struct ip6t_entry_match *m;
  893. struct ip6t_entry_target *t;
  894. e = (struct ip6t_entry *)(table->private->entries + off);
  895. if (copy_to_user(userptr + off
  896.  + offsetof(struct ip6t_entry, counters),
  897.  &counters[num],
  898.  sizeof(counters[num])) != 0) {
  899. ret = -EFAULT;
  900. goto free_counters;
  901. }
  902. for (i = sizeof(struct ip6t_entry);
  903.      i < e->target_offset;
  904.      i += m->u.match_size) {
  905. m = (void *)e + i;
  906. if (copy_to_user(userptr + off + i
  907.  + offsetof(struct ip6t_entry_match,
  908.     u.user.name),
  909.  m->u.kernel.match->name,
  910.  strlen(m->u.kernel.match->name)+1)
  911.     != 0) {
  912. ret = -EFAULT;
  913. goto free_counters;
  914. }
  915. }
  916. t = ip6t_get_target(e);
  917. if (copy_to_user(userptr + off + e->target_offset
  918.  + offsetof(struct ip6t_entry_target,
  919.     u.user.name),
  920.  t->u.kernel.target->name,
  921.  strlen(t->u.kernel.target->name)+1) != 0) {
  922. ret = -EFAULT;
  923. goto free_counters;
  924. }
  925. }
  926.  free_counters:
  927. vfree(counters);
  928. return ret;
  929. }
  930. static int
  931. get_entries(const struct ip6t_get_entries *entries,
  932.     struct ip6t_get_entries *uptr)
  933. {
  934. int ret;
  935. struct ip6t_table *t;
  936. t = find_table_lock(entries->name, &ret, &ip6t_mutex);
  937. if (t) {
  938. duprintf("t->private->number = %un",
  939.  t->private->number);
  940. if (entries->size == t->private->size)
  941. ret = copy_entries_to_user(t->private->size,
  942.    t, uptr->entrytable);
  943. else {
  944. duprintf("get_entries: I've got %u not %u!n",
  945.  t->private->size,
  946.  entries->size);
  947. ret = -EINVAL;
  948. }
  949. up(&ip6t_mutex);
  950. } else
  951. duprintf("get_entries: Can't find %s!n",
  952.  entries->name);
  953. return ret;
  954. }
  955. static int
  956. do_replace(void *user, unsigned int len)
  957. {
  958. int ret;
  959. struct ip6t_replace tmp;
  960. struct ip6t_table *t;
  961. struct ip6t_table_info *newinfo, *oldinfo;
  962. struct ip6t_counters *counters;
  963. if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
  964. return -EFAULT;
  965. /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
  966. if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
  967. return -ENOMEM;
  968. newinfo = vmalloc(sizeof(struct ip6t_table_info)
  969.   + SMP_ALIGN(tmp.size) * smp_num_cpus);
  970. if (!newinfo)
  971. return -ENOMEM;
  972. if (copy_from_user(newinfo->entries, user + sizeof(tmp),
  973.    tmp.size) != 0) {
  974. ret = -EFAULT;
  975. goto free_newinfo;
  976. }
  977. counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
  978. if (!counters) {
  979. ret = -ENOMEM;
  980. goto free_newinfo;
  981. }
  982. memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
  983. ret = translate_table(tmp.name, tmp.valid_hooks,
  984.       newinfo, tmp.size, tmp.num_entries,
  985.       tmp.hook_entry, tmp.underflow);
  986. if (ret != 0)
  987. goto free_newinfo_counters;
  988. duprintf("ip_tables: Translated tablen");
  989. t = find_table_lock(tmp.name, &ret, &ip6t_mutex);
  990. if (!t)
  991. goto free_newinfo_counters_untrans;
  992. /* You lied! */
  993. if (tmp.valid_hooks != t->valid_hooks) {
  994. duprintf("Valid hook crap: %08X vs %08Xn",
  995.  tmp.valid_hooks, t->valid_hooks);
  996. ret = -EINVAL;
  997. goto free_newinfo_counters_untrans_unlock;
  998. }
  999. oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
  1000. if (!oldinfo)
  1001. goto free_newinfo_counters_untrans_unlock;
  1002. /* Update module usage count based on number of rules */
  1003. duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%un",
  1004. oldinfo->number, oldinfo->initial_entries, newinfo->number);
  1005. if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
  1006.       (newinfo->number > oldinfo->initial_entries))
  1007. __MOD_INC_USE_COUNT(t->me);
  1008. else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
  1009.    (newinfo->number <= oldinfo->initial_entries))
  1010. __MOD_DEC_USE_COUNT(t->me);
  1011. /* Get the old counters. */
  1012. get_counters(oldinfo, counters);
  1013. /* Decrease module usage counts and free resource */
  1014. IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
  1015. vfree(oldinfo);
  1016. /* Silent error: too late now. */
  1017. copy_to_user(tmp.counters, counters,
  1018.      sizeof(struct ip6t_counters) * tmp.num_counters);
  1019. vfree(counters);
  1020. up(&ip6t_mutex);
  1021. return 0;
  1022.  free_newinfo_counters_untrans_unlock:
  1023. up(&ip6t_mutex);
  1024.  free_newinfo_counters_untrans:
  1025. IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
  1026.  free_newinfo_counters:
  1027. vfree(counters);
  1028.  free_newinfo:
  1029. vfree(newinfo);
  1030. return ret;
  1031. }
  1032. /* We're lazy, and add to the first CPU; overflow works its fey magic
  1033.  * and everything is OK. */
  1034. static inline int
  1035. add_counter_to_entry(struct ip6t_entry *e,
  1036.      const struct ip6t_counters addme[],
  1037.      unsigned int *i)
  1038. {
  1039. #if 0
  1040. duprintf("add_counter: Entry %u %lu/%lu + %lu/%lun",
  1041.  *i,
  1042.  (long unsigned int)e->counters.pcnt,
  1043.  (long unsigned int)e->counters.bcnt,
  1044.  (long unsigned int)addme[*i].pcnt,
  1045.  (long unsigned int)addme[*i].bcnt);
  1046. #endif
  1047. ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
  1048. (*i)++;
  1049. return 0;
  1050. }
  1051. static int
  1052. do_add_counters(void *user, unsigned int len)
  1053. {
  1054. unsigned int i;
  1055. struct ip6t_counters_info tmp, *paddc;
  1056. struct ip6t_table *t;
  1057. int ret;
  1058. if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
  1059. return -EFAULT;
  1060. if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
  1061. return -EINVAL;
  1062. paddc = vmalloc(len);
  1063. if (!paddc)
  1064. return -ENOMEM;
  1065. if (copy_from_user(paddc, user, len) != 0) {
  1066. ret = -EFAULT;
  1067. goto free;
  1068. }
  1069. t = find_table_lock(tmp.name, &ret, &ip6t_mutex);
  1070. if (!t)
  1071. goto free;
  1072. write_lock_bh(&t->lock);
  1073. if (t->private->number != paddc->num_counters) {
  1074. ret = -EINVAL;
  1075. goto unlock_up_free;
  1076. }
  1077. i = 0;
  1078. IP6T_ENTRY_ITERATE(t->private->entries,
  1079.   t->private->size,
  1080.   add_counter_to_entry,
  1081.   paddc->counters,
  1082.   &i);
  1083.  unlock_up_free:
  1084. write_unlock_bh(&t->lock);
  1085. up(&ip6t_mutex);
  1086.  free:
  1087. vfree(paddc);
  1088. return ret;
  1089. }
  1090. static int
  1091. do_ip6t_set_ctl(struct sock *sk, int cmd, void *user, unsigned int len)
  1092. {
  1093. int ret;
  1094. if (!capable(CAP_NET_ADMIN))
  1095. return -EPERM;
  1096. switch (cmd) {
  1097. case IP6T_SO_SET_REPLACE:
  1098. ret = do_replace(user, len);
  1099. break;
  1100. case IP6T_SO_SET_ADD_COUNTERS:
  1101. ret = do_add_counters(user, len);
  1102. break;
  1103. default:
  1104. duprintf("do_ip6t_set_ctl:  unknown request %in", cmd);
  1105. ret = -EINVAL;
  1106. }
  1107. return ret;
  1108. }
  1109. static int
  1110. do_ip6t_get_ctl(struct sock *sk, int cmd, void *user, int *len)
  1111. {
  1112. int ret;
  1113. if (!capable(CAP_NET_ADMIN))
  1114. return -EPERM;
  1115. switch (cmd) {
  1116. case IP6T_SO_GET_INFO: {
  1117. char name[IP6T_TABLE_MAXNAMELEN];
  1118. struct ip6t_table *t;
  1119. if (*len != sizeof(struct ip6t_getinfo)) {
  1120. duprintf("length %u != %un", *len,
  1121.  sizeof(struct ip6t_getinfo));
  1122. ret = -EINVAL;
  1123. break;
  1124. }
  1125. if (copy_from_user(name, user, sizeof(name)) != 0) {
  1126. ret = -EFAULT;
  1127. break;
  1128. }
  1129. name[IP6T_TABLE_MAXNAMELEN-1] = '';
  1130. t = find_table_lock(name, &ret, &ip6t_mutex);
  1131. if (t) {
  1132. struct ip6t_getinfo info;
  1133. info.valid_hooks = t->valid_hooks;
  1134. memcpy(info.hook_entry, t->private->hook_entry,
  1135.        sizeof(info.hook_entry));
  1136. memcpy(info.underflow, t->private->underflow,
  1137.        sizeof(info.underflow));
  1138. info.num_entries = t->private->number;
  1139. info.size = t->private->size;
  1140. strcpy(info.name, name);
  1141. if (copy_to_user(user, &info, *len) != 0)
  1142. ret = -EFAULT;
  1143. else
  1144. ret = 0;
  1145. up(&ip6t_mutex);
  1146. }
  1147. }
  1148. break;
  1149. case IP6T_SO_GET_ENTRIES: {
  1150. struct ip6t_get_entries get;
  1151. if (*len < sizeof(get)) {
  1152. duprintf("get_entries: %u < %un", *len, sizeof(get));
  1153. ret = -EINVAL;
  1154. } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
  1155. ret = -EFAULT;
  1156. } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
  1157. duprintf("get_entries: %u != %un", *len,
  1158.  sizeof(struct ip6t_get_entries) + get.size);
  1159. ret = -EINVAL;
  1160. } else
  1161. ret = get_entries(&get, user);
  1162. break;
  1163. }
  1164. default:
  1165. duprintf("do_ip6t_get_ctl: unknown request %in", cmd);
  1166. ret = -EINVAL;
  1167. }
  1168. return ret;
  1169. }
  1170. /* Registration hooks for targets. */
  1171. int
  1172. ip6t_register_target(struct ip6t_target *target)
  1173. {
  1174. int ret;
  1175. MOD_INC_USE_COUNT;
  1176. ret = down_interruptible(&ip6t_mutex);
  1177. if (ret != 0) {
  1178. MOD_DEC_USE_COUNT;
  1179. return ret;
  1180. }
  1181. if (!list_named_insert(&ip6t_target, target)) {
  1182. duprintf("ip6t_register_target: `%s' already in list!n",
  1183.  target->name);
  1184. ret = -EINVAL;
  1185. MOD_DEC_USE_COUNT;
  1186. }
  1187. up(&ip6t_mutex);
  1188. return ret;
  1189. }
  1190. void
  1191. ip6t_unregister_target(struct ip6t_target *target)
  1192. {
  1193. down(&ip6t_mutex);
  1194. LIST_DELETE(&ip6t_target, target);
  1195. up(&ip6t_mutex);
  1196. MOD_DEC_USE_COUNT;
  1197. }
  1198. int
  1199. ip6t_register_match(struct ip6t_match *match)
  1200. {
  1201. int ret;
  1202. MOD_INC_USE_COUNT;
  1203. ret = down_interruptible(&ip6t_mutex);
  1204. if (ret != 0) {
  1205. MOD_DEC_USE_COUNT;
  1206. return ret;
  1207. }
  1208. if (!list_named_insert(&ip6t_match, match)) {
  1209. duprintf("ip6t_register_match: `%s' already in list!n",
  1210.  match->name);
  1211. MOD_DEC_USE_COUNT;
  1212. ret = -EINVAL;
  1213. }
  1214. up(&ip6t_mutex);
  1215. return ret;
  1216. }
  1217. void
  1218. ip6t_unregister_match(struct ip6t_match *match)
  1219. {
  1220. down(&ip6t_mutex);
  1221. LIST_DELETE(&ip6t_match, match);
  1222. up(&ip6t_mutex);
  1223. MOD_DEC_USE_COUNT;
  1224. }
  1225. int ip6t_register_table(struct ip6t_table *table)
  1226. {
  1227. int ret;
  1228. struct ip6t_table_info *newinfo;
  1229. static struct ip6t_table_info bootstrap
  1230. = { 0, 0, 0, { 0 }, { 0 }, { }, { } };
  1231. MOD_INC_USE_COUNT;
  1232. newinfo = vmalloc(sizeof(struct ip6t_table_info)
  1233.   + SMP_ALIGN(table->table->size) * smp_num_cpus);
  1234. if (!newinfo) {
  1235. ret = -ENOMEM;
  1236. MOD_DEC_USE_COUNT;
  1237. return ret;
  1238. }
  1239. memcpy(newinfo->entries, table->table->entries, table->table->size);
  1240. ret = translate_table(table->name, table->valid_hooks,
  1241.       newinfo, table->table->size,
  1242.       table->table->num_entries,
  1243.       table->table->hook_entry,
  1244.       table->table->underflow);
  1245. if (ret != 0) {
  1246. vfree(newinfo);
  1247. MOD_DEC_USE_COUNT;
  1248. return ret;
  1249. }
  1250. ret = down_interruptible(&ip6t_mutex);
  1251. if (ret != 0) {
  1252. vfree(newinfo);
  1253. MOD_DEC_USE_COUNT;
  1254. return ret;
  1255. }
  1256. /* Don't autoload: we'd eat our tail... */
  1257. if (list_named_find(&ip6t_tables, table->name)) {
  1258. ret = -EEXIST;
  1259. goto free_unlock;
  1260. }
  1261. /* Simplifies replace_table code. */
  1262. table->private = &bootstrap;
  1263. if (!replace_table(table, 0, newinfo, &ret))
  1264. goto free_unlock;
  1265. duprintf("table->private->number = %un",
  1266.  table->private->number);
  1267. table->lock = RW_LOCK_UNLOCKED;
  1268. list_prepend(&ip6t_tables, table);
  1269.  unlock:
  1270. up(&ip6t_mutex);
  1271. return ret;
  1272.  free_unlock:
  1273. vfree(newinfo);
  1274. MOD_DEC_USE_COUNT;
  1275. goto unlock;
  1276. }
  1277. void ip6t_unregister_table(struct ip6t_table *table)
  1278. {
  1279. down(&ip6t_mutex);
  1280. LIST_DELETE(&ip6t_tables, table);
  1281. up(&ip6t_mutex);
  1282. /* Decrease module usage counts and free resources */
  1283. IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
  1284.   cleanup_entry, NULL);
  1285. vfree(table->private);
  1286. MOD_DEC_USE_COUNT;
  1287. }
  1288. /* Returns 1 if the port is matched by the range, 0 otherwise */
  1289. static inline int
  1290. port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
  1291. {
  1292. int ret;
  1293. ret = (port >= min && port <= max) ^ invert;
  1294. return ret;
  1295. }
  1296. static int
  1297. tcp_find_option(u_int8_t option,
  1298. const struct tcphdr *tcp,
  1299. u_int16_t datalen,
  1300. int invert,
  1301. int *hotdrop)
  1302. {
  1303. unsigned int i = sizeof(struct tcphdr);
  1304. const u_int8_t *opt = (u_int8_t *)tcp;
  1305. duprintf("tcp_match: finding optionn");
  1306. /* If we don't have the whole header, drop packet. */
  1307. if (tcp->doff * 4 > datalen) {
  1308. *hotdrop = 1;
  1309. return 0;
  1310. }
  1311. while (i < tcp->doff * 4) {
  1312. if (opt[i] == option) return !invert;
  1313. if (opt[i] < 2) i++;
  1314. else i += opt[i+1]?:1;
  1315. }
  1316. return invert;
  1317. }
  1318. static int
  1319. tcp_match(const struct sk_buff *skb,
  1320.   const struct net_device *in,
  1321.   const struct net_device *out,
  1322.   const void *matchinfo,
  1323.   int offset,
  1324.   const void *hdr,
  1325.   u_int16_t datalen,
  1326.   int *hotdrop)
  1327. {
  1328. const struct tcphdr *tcp = hdr;
  1329. const struct ip6t_tcp *tcpinfo = matchinfo;
  1330. /* To quote Alan:
  1331.    Don't allow a fragment of TCP 8 bytes in. Nobody normal
  1332.    causes this. Its a cracker trying to break in by doing a
  1333.    flag overwrite to pass the direction checks.
  1334. */
  1335. if (offset == 1) {
  1336. duprintf("Dropping evil TCP offset=1 frag.n");
  1337. *hotdrop = 1;
  1338. return 0;
  1339. } else if (offset == 0 && datalen < sizeof(struct tcphdr)) {
  1340. /* We've been asked to examine this packet, and we
  1341.    can't.  Hence, no choice but to drop. */
  1342. duprintf("Dropping evil TCP offset=0 tinygram.n");
  1343. *hotdrop = 1;
  1344. return 0;
  1345. }
  1346. /* FIXME: Try tcp doff >> packet len against various stacks --RR */
  1347. #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
  1348. /* Must not be a fragment. */
  1349. return !offset
  1350. && port_match(tcpinfo->spts[0], tcpinfo->spts[1],
  1351.       ntohs(tcp->source),
  1352.       !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT))
  1353. && port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
  1354.       ntohs(tcp->dest),
  1355.       !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT))
  1356. && FWINVTCP((((unsigned char *)tcp)[13]
  1357.      & tcpinfo->flg_mask)
  1358.     == tcpinfo->flg_cmp,
  1359.     IP6T_TCP_INV_FLAGS)
  1360. && (!tcpinfo->option
  1361.     || tcp_find_option(tcpinfo->option, tcp, datalen,
  1362.        tcpinfo->invflags
  1363.        & IP6T_TCP_INV_OPTION,
  1364.        hotdrop));
  1365. }
  1366. /* Called when user tries to insert an entry of this type. */
  1367. static int
  1368. tcp_checkentry(const char *tablename,
  1369.        const struct ip6t_ip6 *ipv6,
  1370.        void *matchinfo,
  1371.        unsigned int matchsize,
  1372.        unsigned int hook_mask)
  1373. {
  1374. const struct ip6t_tcp *tcpinfo = matchinfo;
  1375. /* Must specify proto == TCP, and no unknown invflags */
  1376. return ipv6->proto == IPPROTO_TCP
  1377. && !(ipv6->invflags & IP6T_INV_PROTO)
  1378. && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
  1379. && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
  1380. }
  1381. static int
  1382. udp_match(const struct sk_buff *skb,
  1383.   const struct net_device *in,
  1384.   const struct net_device *out,
  1385.   const void *matchinfo,
  1386.   int offset,
  1387.   const void *hdr,
  1388.   u_int16_t datalen,
  1389.   int *hotdrop)
  1390. {
  1391. const struct udphdr *udp = hdr;
  1392. const struct ip6t_udp *udpinfo = matchinfo;
  1393. if (offset == 0 && datalen < sizeof(struct udphdr)) {
  1394. /* We've been asked to examine this packet, and we
  1395.    can't.  Hence, no choice but to drop. */
  1396. duprintf("Dropping evil UDP tinygram.n");
  1397. *hotdrop = 1;
  1398. return 0;
  1399. }
  1400. /* Must not be a fragment. */
  1401. return !offset
  1402. && port_match(udpinfo->spts[0], udpinfo->spts[1],
  1403.       ntohs(udp->source),
  1404.       !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
  1405. && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
  1406.       ntohs(udp->dest),
  1407.       !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
  1408. }
  1409. /* Called when user tries to insert an entry of this type. */
  1410. static int
  1411. udp_checkentry(const char *tablename,
  1412.        const struct ip6t_ip6 *ipv6,
  1413.        void *matchinfo,
  1414.        unsigned int matchinfosize,
  1415.        unsigned int hook_mask)
  1416. {
  1417. const struct ip6t_udp *udpinfo = matchinfo;
  1418. /* Must specify proto == UDP, and no unknown invflags */
  1419. if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
  1420. duprintf("ip6t_udp: Protocol %u != %un", ipv6->proto,
  1421.  IPPROTO_UDP);
  1422. return 0;
  1423. }
  1424. if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
  1425. duprintf("ip6t_udp: matchsize %u != %un",
  1426.  matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
  1427. return 0;
  1428. }
  1429. if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
  1430. duprintf("ip6t_udp: unknown flags %Xn",
  1431.  udpinfo->invflags);
  1432. return 0;
  1433. }
  1434. return 1;
  1435. }
  1436. /* Returns 1 if the type and code is matched by the range, 0 otherwise */
  1437. static inline int
  1438. icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
  1439.      u_int8_t type, u_int8_t code,
  1440.      int invert)
  1441. {
  1442. return (type == test_type && code >= min_code && code <= max_code)
  1443. ^ invert;
  1444. }
  1445. static int
  1446. icmp6_match(const struct sk_buff *skb,
  1447.    const struct net_device *in,
  1448.    const struct net_device *out,
  1449.    const void *matchinfo,
  1450.    int offset,
  1451.    const void *hdr,
  1452.    u_int16_t datalen,
  1453.    int *hotdrop)
  1454. {
  1455. const struct icmp6hdr *icmp = hdr;
  1456. const struct ip6t_icmp *icmpinfo = matchinfo;
  1457. if (offset == 0 && datalen < 2) {
  1458. /* We've been asked to examine this packet, and we
  1459.    can't.  Hence, no choice but to drop. */
  1460. duprintf("Dropping evil ICMP tinygram.n");
  1461. *hotdrop = 1;
  1462. return 0;
  1463. }
  1464. /* Must not be a fragment. */
  1465. return !offset
  1466. && icmp6_type_code_match(icmpinfo->type,
  1467. icmpinfo->code[0],
  1468. icmpinfo->code[1],
  1469. icmp->icmp6_type, icmp->icmp6_code,
  1470. !!(icmpinfo->invflags&IP6T_ICMP_INV));
  1471. }
  1472. /* Called when user tries to insert an entry of this type. */
  1473. static int
  1474. icmp6_checkentry(const char *tablename,
  1475.    const struct ip6t_ip6 *ipv6,
  1476.    void *matchinfo,
  1477.    unsigned int matchsize,
  1478.    unsigned int hook_mask)
  1479. {
  1480. const struct ip6t_icmp *icmpinfo = matchinfo;
  1481. /* Must specify proto == ICMP, and no unknown invflags */
  1482. return ipv6->proto == IPPROTO_ICMPV6
  1483. && !(ipv6->invflags & IP6T_INV_PROTO)
  1484. && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
  1485. && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
  1486. }
  1487. /* The built-in targets: standard (NULL) and error. */
  1488. static struct ip6t_target ip6t_standard_target
  1489. = { { NULL, NULL }, IP6T_STANDARD_TARGET, NULL, NULL, NULL };
  1490. static struct ip6t_target ip6t_error_target
  1491. = { { NULL, NULL }, IP6T_ERROR_TARGET, ip6t_error, NULL, NULL };
  1492. static struct nf_sockopt_ops ip6t_sockopts
  1493. = { { NULL, NULL }, PF_INET6, IP6T_BASE_CTL, IP6T_SO_SET_MAX+1, do_ip6t_set_ctl,
  1494.     IP6T_BASE_CTL, IP6T_SO_GET_MAX+1, do_ip6t_get_ctl, 0, NULL  };
  1495. static struct ip6t_match tcp_matchstruct
  1496. = { { NULL, NULL }, "tcp", &tcp_match, &tcp_checkentry, NULL };
  1497. static struct ip6t_match udp_matchstruct
  1498. = { { NULL, NULL }, "udp", &udp_match, &udp_checkentry, NULL };
  1499. static struct ip6t_match icmp6_matchstruct
  1500. = { { NULL, NULL }, "icmp6", &icmp6_match, &icmp6_checkentry, NULL };
  1501. #ifdef CONFIG_PROC_FS
  1502. static inline int print_name(const struct ip6t_table *t,
  1503.      off_t start_offset, char *buffer, int length,
  1504.      off_t *pos, unsigned int *count)
  1505. {
  1506. if ((*count)++ >= start_offset) {
  1507. unsigned int namelen;
  1508. namelen = sprintf(buffer + *pos, "%sn", t->name);
  1509. if (*pos + namelen > length) {
  1510. /* Stop iterating */
  1511. return 1;
  1512. }
  1513. *pos += namelen;
  1514. }
  1515. return 0;
  1516. }
  1517. static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
  1518. {
  1519. off_t pos = 0;
  1520. unsigned int count = 0;
  1521. if (down_interruptible(&ip6t_mutex) != 0)
  1522. return 0;
  1523. LIST_FIND(&ip6t_tables, print_name, struct ip6t_table *,
  1524.   offset, buffer, length, &pos, &count);
  1525. up(&ip6t_mutex);
  1526. /* `start' hack - see fs/proc/generic.c line ~105 */
  1527. *start=(char *)((unsigned long)count-offset);
  1528. return pos;
  1529. }
  1530. #endif /*CONFIG_PROC_FS*/
  1531. static int __init init(void)
  1532. {
  1533. int ret;
  1534. /* Noone else will be downing sem now, so we won't sleep */
  1535. down(&ip6t_mutex);
  1536. list_append(&ip6t_target, &ip6t_standard_target);
  1537. list_append(&ip6t_target, &ip6t_error_target);
  1538. list_append(&ip6t_match, &tcp_matchstruct);
  1539. list_append(&ip6t_match, &udp_matchstruct);
  1540. list_append(&ip6t_match, &icmp6_matchstruct);
  1541. up(&ip6t_mutex);
  1542. /* Register setsockopt */
  1543. ret = nf_register_sockopt(&ip6t_sockopts);
  1544. if (ret < 0) {
  1545. duprintf("Unable to register sockopts.n");
  1546. return ret;
  1547. }
  1548. #ifdef CONFIG_PROC_FS
  1549. if (!proc_net_create("ip6_tables_names", 0, ip6t_get_tables)) {
  1550. nf_unregister_sockopt(&ip6t_sockopts);
  1551. return -ENOMEM;
  1552. }
  1553. #endif
  1554. printk("ip6_tables: (C) 2000-2002 Netfilter core teamn");
  1555. return 0;
  1556. }
  1557. static void __exit fini(void)
  1558. {
  1559. nf_unregister_sockopt(&ip6t_sockopts);
  1560. #ifdef CONFIG_PROC_FS
  1561. proc_net_remove("ip6_tables_names");
  1562. #endif
  1563. }
  1564. EXPORT_SYMBOL(ip6t_register_table);
  1565. EXPORT_SYMBOL(ip6t_unregister_table);
  1566. EXPORT_SYMBOL(ip6t_do_table);
  1567. EXPORT_SYMBOL(ip6t_register_match);
  1568. EXPORT_SYMBOL(ip6t_unregister_match);
  1569. EXPORT_SYMBOL(ip6t_register_target);
  1570. EXPORT_SYMBOL(ip6t_unregister_target);
  1571. module_init(init);
  1572. module_exit(fini);
  1573. MODULE_LICENSE("GPL");