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 | ||
8cc784ee | 30 | static bool ebt_filter_ip6(const struct sk_buff *skb, |
93f65158 KT |
31 | const struct net_device *in, |
32 | const struct net_device *out, const void *data, | |
33 | unsigned int datalen) | |
34 | { | |
35 | const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data; | |
36 | const struct ipv6hdr *ih6; | |
37 | struct ipv6hdr _ip6h; | |
38 | const struct tcpudphdr *pptr; | |
39 | struct tcpudphdr _ports; | |
40 | struct in6_addr tmp_addr; | |
41 | int i; | |
42 | ||
43 | ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); | |
44 | if (ih6 == NULL) | |
8cc784ee | 45 | return false; |
93f65158 KT |
46 | if (info->bitmask & EBT_IP6_TCLASS && |
47 | FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS)) | |
8cc784ee | 48 | return false; |
93f65158 KT |
49 | for (i = 0; i < 4; i++) |
50 | tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] & | |
51 | info->smsk.in6_u.u6_addr32[i]; | |
52 | if (info->bitmask & EBT_IP6_SOURCE && | |
53 | FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0), | |
54 | EBT_IP6_SOURCE)) | |
8cc784ee | 55 | return false; |
93f65158 KT |
56 | for (i = 0; i < 4; i++) |
57 | tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] & | |
58 | info->dmsk.in6_u.u6_addr32[i]; | |
59 | if (info->bitmask & EBT_IP6_DEST && | |
60 | FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST)) | |
8cc784ee | 61 | return false; |
93f65158 KT |
62 | if (info->bitmask & EBT_IP6_PROTO) { |
63 | uint8_t nexthdr = ih6->nexthdr; | |
64 | int offset_ph; | |
65 | ||
66 | offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr); | |
67 | if (offset_ph == -1) | |
8cc784ee | 68 | return false; |
93f65158 | 69 | if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO)) |
8cc784ee | 70 | return false; |
93f65158 KT |
71 | if (!(info->bitmask & EBT_IP6_DPORT) && |
72 | !(info->bitmask & EBT_IP6_SPORT)) | |
8cc784ee | 73 | return true; |
93f65158 KT |
74 | pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports), |
75 | &_ports); | |
76 | if (pptr == NULL) | |
8cc784ee | 77 | return false; |
93f65158 KT |
78 | if (info->bitmask & EBT_IP6_DPORT) { |
79 | u32 dst = ntohs(pptr->dst); | |
80 | if (FWINV(dst < info->dport[0] || | |
81 | dst > info->dport[1], EBT_IP6_DPORT)) | |
8cc784ee | 82 | return false; |
93f65158 KT |
83 | } |
84 | if (info->bitmask & EBT_IP6_SPORT) { | |
85 | u32 src = ntohs(pptr->src); | |
86 | if (FWINV(src < info->sport[0] || | |
87 | src > info->sport[1], EBT_IP6_SPORT)) | |
8cc784ee | 88 | return false; |
93f65158 | 89 | } |
8cc784ee | 90 | return true; |
93f65158 | 91 | } |
8cc784ee | 92 | return true; |
93f65158 KT |
93 | } |
94 | ||
19eda879 | 95 | static bool ebt_ip6_check(const char *tablename, unsigned int hookmask, |
93f65158 KT |
96 | const struct ebt_entry *e, void *data, unsigned int datalen) |
97 | { | |
98 | struct ebt_ip6_info *info = (struct ebt_ip6_info *)data; | |
99 | ||
93f65158 | 100 | if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO) |
19eda879 | 101 | return false; |
93f65158 | 102 | if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK) |
19eda879 | 103 | return false; |
93f65158 KT |
104 | if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) { |
105 | if (info->invflags & EBT_IP6_PROTO) | |
19eda879 | 106 | return false; |
93f65158 KT |
107 | if (info->protocol != IPPROTO_TCP && |
108 | info->protocol != IPPROTO_UDP && | |
109 | info->protocol != IPPROTO_UDPLITE && | |
110 | info->protocol != IPPROTO_SCTP && | |
111 | info->protocol != IPPROTO_DCCP) | |
19eda879 | 112 | return false; |
93f65158 KT |
113 | } |
114 | if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1]) | |
19eda879 | 115 | return false; |
93f65158 | 116 | if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1]) |
19eda879 JE |
117 | return false; |
118 | return true; | |
93f65158 KT |
119 | } |
120 | ||
121 | static struct ebt_match filter_ip6 = | |
122 | { | |
123 | .name = EBT_IP6_MATCH, | |
001a18d3 JE |
124 | .revision = 0, |
125 | .family = NFPROTO_BRIDGE, | |
93f65158 KT |
126 | .match = ebt_filter_ip6, |
127 | .check = ebt_ip6_check, | |
18219d3f | 128 | .matchsize = XT_ALIGN(sizeof(struct ebt_ip6_info)), |
93f65158 KT |
129 | .me = THIS_MODULE, |
130 | }; | |
131 | ||
132 | static int __init ebt_ip6_init(void) | |
133 | { | |
134 | return ebt_register_match(&filter_ip6); | |
135 | } | |
136 | ||
137 | static void __exit ebt_ip6_fini(void) | |
138 | { | |
139 | ebt_unregister_match(&filter_ip6); | |
140 | } | |
141 | ||
142 | module_init(ebt_ip6_init); | |
143 | module_exit(ebt_ip6_fini); | |
144 | MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match"); | |
145 | MODULE_LICENSE("GPL"); |