Commit | Line | Data |
---|---|---|
93f65158 KT |
1 | /* |
2 | * ebt_ip6 | |
3 | * | |
4 | * Authors: | |
5 | * Manohar Castelino <manohar.r.castelino@intel.com> | |
6 | * Kuo-Lang Tseng <kuo-lang.tseng@intel.com> | |
7 | * Jan Engelhardt <jengelh@computergmbh.de> | |
8 | * | |
9 | * Summary: | |
10 | * This is just a modification of the IPv4 code written by | |
11 | * Bart De Schuymer <bdschuym@pandora.be> | |
12 | * with the changes required to support IPv6 | |
13 | * | |
14 | * Jan, 2008 | |
15 | */ | |
93f65158 KT |
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> | |
18219d3f JE |
21 | #include <linux/netfilter/x_tables.h> |
22 | #include <linux/netfilter_bridge/ebtables.h> | |
23 | #include <linux/netfilter_bridge/ebt_ip6.h> | |
93f65158 KT |
24 | |
25 | struct tcpudphdr { | |
26 | __be16 src; | |
27 | __be16 dst; | |
28 | }; | |
29 | ||
2d06d4a5 | 30 | static bool |
f7108a20 | 31 | ebt_ip6_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
93f65158 | 32 | { |
f7108a20 | 33 | const struct ebt_ip6_info *info = par->matchinfo; |
93f65158 KT |
34 | const struct ipv6hdr *ih6; |
35 | struct ipv6hdr _ip6h; | |
36 | const struct tcpudphdr *pptr; | |
37 | struct tcpudphdr _ports; | |
38 | struct in6_addr tmp_addr; | |
39 | int i; | |
40 | ||
41 | ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); | |
42 | if (ih6 == NULL) | |
8cc784ee | 43 | return false; |
93f65158 KT |
44 | if (info->bitmask & EBT_IP6_TCLASS && |
45 | FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS)) | |
8cc784ee | 46 | return false; |
93f65158 KT |
47 | for (i = 0; i < 4; i++) |
48 | tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] & | |
49 | info->smsk.in6_u.u6_addr32[i]; | |
50 | if (info->bitmask & EBT_IP6_SOURCE && | |
51 | FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0), | |
52 | EBT_IP6_SOURCE)) | |
8cc784ee | 53 | return false; |
93f65158 KT |
54 | for (i = 0; i < 4; i++) |
55 | tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] & | |
56 | info->dmsk.in6_u.u6_addr32[i]; | |
57 | if (info->bitmask & EBT_IP6_DEST && | |
58 | FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST)) | |
8cc784ee | 59 | return false; |
93f65158 KT |
60 | if (info->bitmask & EBT_IP6_PROTO) { |
61 | uint8_t nexthdr = ih6->nexthdr; | |
62 | int offset_ph; | |
63 | ||
64 | offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr); | |
65 | if (offset_ph == -1) | |
8cc784ee | 66 | return false; |
93f65158 | 67 | if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO)) |
8cc784ee | 68 | return false; |
93f65158 KT |
69 | if (!(info->bitmask & EBT_IP6_DPORT) && |
70 | !(info->bitmask & EBT_IP6_SPORT)) | |
8cc784ee | 71 | return true; |
93f65158 KT |
72 | pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports), |
73 | &_ports); | |
74 | if (pptr == NULL) | |
8cc784ee | 75 | return false; |
93f65158 KT |
76 | if (info->bitmask & EBT_IP6_DPORT) { |
77 | u32 dst = ntohs(pptr->dst); | |
78 | if (FWINV(dst < info->dport[0] || | |
79 | dst > info->dport[1], EBT_IP6_DPORT)) | |
8cc784ee | 80 | return false; |
93f65158 KT |
81 | } |
82 | if (info->bitmask & EBT_IP6_SPORT) { | |
83 | u32 src = ntohs(pptr->src); | |
84 | if (FWINV(src < info->sport[0] || | |
85 | src > info->sport[1], EBT_IP6_SPORT)) | |
8cc784ee | 86 | return false; |
93f65158 | 87 | } |
8cc784ee | 88 | return true; |
93f65158 | 89 | } |
8cc784ee | 90 | return true; |
93f65158 KT |
91 | } |
92 | ||
9b4fce7a | 93 | static bool ebt_ip6_mt_check(const struct xt_mtchk_param *par) |
93f65158 | 94 | { |
9b4fce7a JE |
95 | const struct ebt_entry *e = par->entryinfo; |
96 | struct ebt_ip6_info *info = par->matchinfo; | |
93f65158 | 97 | |
93f65158 | 98 | if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO) |
19eda879 | 99 | return false; |
93f65158 | 100 | if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK) |
19eda879 | 101 | return false; |
93f65158 KT |
102 | if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) { |
103 | if (info->invflags & EBT_IP6_PROTO) | |
19eda879 | 104 | return false; |
93f65158 KT |
105 | if (info->protocol != IPPROTO_TCP && |
106 | info->protocol != IPPROTO_UDP && | |
107 | info->protocol != IPPROTO_UDPLITE && | |
108 | info->protocol != IPPROTO_SCTP && | |
109 | info->protocol != IPPROTO_DCCP) | |
19eda879 | 110 | return false; |
93f65158 KT |
111 | } |
112 | if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1]) | |
19eda879 | 113 | return false; |
93f65158 | 114 | if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1]) |
19eda879 JE |
115 | return false; |
116 | return true; | |
93f65158 KT |
117 | } |
118 | ||
043ef46c JE |
119 | static struct xt_match ebt_ip6_mt_reg __read_mostly = { |
120 | .name = "ip6", | |
001a18d3 JE |
121 | .revision = 0, |
122 | .family = NFPROTO_BRIDGE, | |
2d06d4a5 JE |
123 | .match = ebt_ip6_mt, |
124 | .checkentry = ebt_ip6_mt_check, | |
fc0e3df4 | 125 | .matchsize = sizeof(struct ebt_ip6_info), |
93f65158 KT |
126 | .me = THIS_MODULE, |
127 | }; | |
128 | ||
129 | static int __init ebt_ip6_init(void) | |
130 | { | |
043ef46c | 131 | return xt_register_match(&ebt_ip6_mt_reg); |
93f65158 KT |
132 | } |
133 | ||
134 | static void __exit ebt_ip6_fini(void) | |
135 | { | |
043ef46c | 136 | xt_unregister_match(&ebt_ip6_mt_reg); |
93f65158 KT |
137 | } |
138 | ||
139 | module_init(ebt_ip6_init); | |
140 | module_exit(ebt_ip6_fini); | |
141 | MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match"); | |
142 | MODULE_LICENSE("GPL"); |