ip6_tables.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:46k
源码类别:

Linux/Unix编程

开发平台:

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