Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ebt_ip6.c
Go to the documentation of this file.
1 /*
2  * ebt_ip6
3  *
4  * Authors:
5  * Manohar Castelino <[email protected]>
6  * Kuo-Lang Tseng <[email protected]>
7  * Jan Engelhardt <[email protected]>
8  *
9  * Summary:
10  * This is just a modification of the IPv4 code written by
11  * Bart De Schuymer <[email protected]>
12  * with the changes required to support IPv6
13  *
14  * Jan, 2008
15  */
16 #include <linux/ipv6.h>
17 #include <net/ipv6.h>
18 #include <linux/in.h>
19 #include <linux/module.h>
20 #include <net/dsfield.h>
21 #include <linux/netfilter/x_tables.h>
22 #include <linux/netfilter_bridge/ebtables.h>
24 
25 union pkthdr {
26  struct {
29  } tcpudphdr;
30  struct {
33  } icmphdr;
34 };
35 
36 static bool
37 ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par)
38 {
39  const struct ebt_ip6_info *info = par->matchinfo;
40  const struct ipv6hdr *ih6;
41  struct ipv6hdr _ip6h;
42  const union pkthdr *pptr;
43  union pkthdr _pkthdr;
44 
45  ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
46  if (ih6 == NULL)
47  return false;
48  if (info->bitmask & EBT_IP6_TCLASS &&
49  FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS))
50  return false;
51  if (FWINV(ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk,
52  &info->saddr), EBT_IP6_SOURCE) ||
53  FWINV(ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk,
54  &info->daddr), EBT_IP6_DEST))
55  return false;
56  if (info->bitmask & EBT_IP6_PROTO) {
57  uint8_t nexthdr = ih6->nexthdr;
58  __be16 frag_off;
59  int offset_ph;
60 
61  offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off);
62  if (offset_ph == -1)
63  return false;
64  if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO))
65  return false;
66  if (!(info->bitmask & ( EBT_IP6_DPORT |
68  return true;
69 
70  /* min icmpv6 headersize is 4, so sizeof(_pkthdr) is ok. */
71  pptr = skb_header_pointer(skb, offset_ph, sizeof(_pkthdr),
72  &_pkthdr);
73  if (pptr == NULL)
74  return false;
75  if (info->bitmask & EBT_IP6_DPORT) {
76  u16 dst = ntohs(pptr->tcpudphdr.dst);
77  if (FWINV(dst < info->dport[0] ||
78  dst > info->dport[1], EBT_IP6_DPORT))
79  return false;
80  }
81  if (info->bitmask & EBT_IP6_SPORT) {
82  u16 src = ntohs(pptr->tcpudphdr.src);
83  if (FWINV(src < info->sport[0] ||
84  src > info->sport[1], EBT_IP6_SPORT))
85  return false;
86  }
87  if ((info->bitmask & EBT_IP6_ICMP6) &&
88  FWINV(pptr->icmphdr.type < info->icmpv6_type[0] ||
89  pptr->icmphdr.type > info->icmpv6_type[1] ||
90  pptr->icmphdr.code < info->icmpv6_code[0] ||
91  pptr->icmphdr.code > info->icmpv6_code[1],
93  return false;
94  }
95  return true;
96 }
97 
98 static int ebt_ip6_mt_check(const struct xt_mtchk_param *par)
99 {
100  const struct ebt_entry *e = par->entryinfo;
101  struct ebt_ip6_info *info = par->matchinfo;
102 
103  if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
104  return -EINVAL;
105  if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
106  return -EINVAL;
107  if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
108  if (info->invflags & EBT_IP6_PROTO)
109  return -EINVAL;
110  if (info->protocol != IPPROTO_TCP &&
111  info->protocol != IPPROTO_UDP &&
112  info->protocol != IPPROTO_UDPLITE &&
113  info->protocol != IPPROTO_SCTP &&
114  info->protocol != IPPROTO_DCCP)
115  return -EINVAL;
116  }
117  if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
118  return -EINVAL;
119  if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
120  return -EINVAL;
121  if (info->bitmask & EBT_IP6_ICMP6) {
122  if ((info->invflags & EBT_IP6_PROTO) ||
123  info->protocol != IPPROTO_ICMPV6)
124  return -EINVAL;
125  if (info->icmpv6_type[0] > info->icmpv6_type[1] ||
126  info->icmpv6_code[0] > info->icmpv6_code[1])
127  return -EINVAL;
128  }
129  return 0;
130 }
131 
132 static struct xt_match ebt_ip6_mt_reg __read_mostly = {
133  .name = "ip6",
134  .revision = 0,
135  .family = NFPROTO_BRIDGE,
136  .match = ebt_ip6_mt,
137  .checkentry = ebt_ip6_mt_check,
138  .matchsize = sizeof(struct ebt_ip6_info),
139  .me = THIS_MODULE,
140 };
141 
142 static int __init ebt_ip6_init(void)
143 {
144  return xt_register_match(&ebt_ip6_mt_reg);
145 }
146 
147 static void __exit ebt_ip6_fini(void)
148 {
149  xt_unregister_match(&ebt_ip6_mt_reg);
150 }
151 
152 module_init(ebt_ip6_init);
153 module_exit(ebt_ip6_fini);
154 MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match");
155 MODULE_AUTHOR("Kuo-Lang Tseng <[email protected]>");
156 MODULE_LICENSE("GPL");