1 /* Kernel module to match ROUTING parameters. */
2 #include <linux/module.h>
3 #include <linux/skbuff.h>
4 #include <linux/ipv6.h>
5 #include <linux/types.h>
6 #include <net/checksum.h>
9 #include <asm/byteorder.h>
11 #include <linux/netfilter_ipv6/ip6_tables.h>
12 #include <linux/netfilter_ipv6/ip6t_rt.h>
15 MODULE_LICENSE("GPL");
16 MODULE_DESCRIPTION("IPv6 RT match");
17 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
22 #define DEBUGP(format, args...)
25 /* Returns 1 if the id is matched by the range, 0 otherwise */
27 segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
30 DEBUGP("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
32 r=(id >= min && id <= max) ^ invert;
33 DEBUGP(" result %s\n",r? "PASS" : "FAILED");
38 match(const struct sk_buff *skb,
39 const struct net_device *in,
40 const struct net_device *out,
41 const void *matchinfo,
47 struct ipv6_rt_hdr *route = NULL;
48 const struct ip6t_rt *rtinfo = matchinfo;
53 unsigned int hdrlen = 0;
56 /* type of the 1st exthdr */
57 nexthdr = skb->nh.ipv6h->nexthdr;
58 /* pointer to the 1st exthdr */
59 ptr = sizeof(struct ipv6hdr);
60 /* available length */
64 while (ip6t_ext_hdr(nexthdr)) {
65 struct ipv6_opt_hdr *hdr;
67 DEBUGP("ipv6_rt header iteration \n");
69 /* Is there enough space for the next ext header? */
70 if (len < (int)sizeof(struct ipv6_opt_hdr))
72 /* No more exthdr -> evaluate */
73 if (nexthdr == NEXTHDR_NONE) {
77 if (nexthdr == NEXTHDR_ESP) {
81 hdr=(struct ipv6_opt_hdr *)(skb->data+ptr);
83 /* Calculate the header length */
84 if (nexthdr == NEXTHDR_FRAGMENT) {
86 } else if (nexthdr == NEXTHDR_AUTH)
87 hdrlen = (hdr->hdrlen+2)<<2;
89 hdrlen = ipv6_optlen(hdr);
91 /* ROUTING -> evaluate */
92 if (nexthdr == NEXTHDR_ROUTING) {
101 case NEXTHDR_ROUTING:
102 case NEXTHDR_FRAGMENT:
107 DEBUGP("ipv6_rt match: unknown nextheader %u\n",nexthdr);
112 nexthdr = hdr->nexthdr;
115 if ( ptr > skb->len ) {
116 DEBUGP("ipv6_rt: new pointer is too large! \n");
121 /* ROUTING header not found */
122 if ( temp != MASK_ROUTING ) return 0;
124 if (len < (int)sizeof(struct ipv6_rt_hdr)){
130 /* Pcket smaller than its length field */
134 route = (struct ipv6_rt_hdr *) (skb->data + ptr);
136 DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
137 DEBUGP("TYPE %04X ", route->type);
138 DEBUGP("SGS_LEFT %u %02X\n", route->segments_left, route->segments_left);
140 DEBUGP("IPv6 RT segsleft %02X ",
141 (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
142 route->segments_left,
143 !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
144 DEBUGP("type %02X %02X %02X ",
145 rtinfo->rt_type, route->type,
146 (!(rtinfo->flags & IP6T_RT_TYP) ||
147 ((rtinfo->rt_type == route->type) ^
148 !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
149 DEBUGP("len %02X %04X %02X ",
150 rtinfo->hdrlen, hdrlen,
151 (!(rtinfo->flags & IP6T_RT_LEN) ||
152 ((rtinfo->hdrlen == hdrlen) ^
153 !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
154 DEBUGP("res %02X %02X %02X ",
155 (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap,
156 !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)));
158 ret = (route != NULL)
160 (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
161 route->segments_left,
162 !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
164 (!(rtinfo->flags & IP6T_RT_LEN) ||
165 ((rtinfo->hdrlen == hdrlen) ^
166 !!(rtinfo->invflags & IP6T_RT_INV_LEN)))
168 (!(rtinfo->flags & IP6T_RT_TYP) ||
169 ((rtinfo->rt_type == route->type) ^
170 !!(rtinfo->invflags & IP6T_RT_INV_TYP)))
172 !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap));
174 DEBUGP("#%d ",rtinfo->addrnr);
175 temp = len = ptr = 0;
176 if ( !(rtinfo->flags & IP6T_RT_FST) ){
178 } else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
179 DEBUGP("Not strict ");
180 if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
181 DEBUGP("There isn't enough space\n");
184 DEBUGP("#%d ",rtinfo->addrnr);
186 for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){
188 while ((u8)(((struct rt0_hdr *)route)->
189 addr[temp].s6_addr[len]) ==
190 (u8)(rtinfo->addrs[ptr].s6_addr[len])){
192 (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
193 (u8)(rtinfo->addrs[ptr].s6_addr[len]));
195 if ( len == 16 ) break;
198 DEBUGP("ptr=%d temp=%d;\n",ptr,temp);
202 (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
203 (u8)(rtinfo->addrs[ptr].s6_addr[len]));
204 DEBUGP("!ptr=%d temp=%d;\n",ptr,temp);
206 if (ptr==rtinfo->addrnr) break;
208 DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr);
209 if ( (len == 16) && (ptr == rtinfo->addrnr))
215 if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
216 DEBUGP("There isn't enough space\n");
219 DEBUGP("#%d ",rtinfo->addrnr);
220 for(temp=0; temp<rtinfo->addrnr; temp++){
222 while ((u8)(((struct rt0_hdr *)route)->
223 addr[temp].s6_addr[len]) ==
224 (u8)(rtinfo->addrs[temp].s6_addr[len])){
226 (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
227 (u8)(rtinfo->addrs[temp].s6_addr[len]));
229 if ( len == 16 ) break;
233 (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
234 (u8)(rtinfo->addrs[temp].s6_addr[len]));
235 DEBUGP("!len=%d temp=%d;\n",len,temp);
239 DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr);
240 if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
249 /* Called when user tries to insert an entry of this type. */
251 checkentry(const char *tablename,
252 const struct ip6t_ip6 *ip,
254 unsigned int matchinfosize,
255 unsigned int hook_mask)
257 const struct ip6t_rt *rtinfo = matchinfo;
259 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) {
260 DEBUGP("ip6t_rt: matchsize %u != %u\n",
261 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt)));
264 if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
265 DEBUGP("ip6t_rt: unknown flags %X\n",
269 if ( (rtinfo->flags & (IP6T_RT_RES|IP6T_RT_FST_MASK)) &&
270 (!(rtinfo->flags & IP6T_RT_TYP) ||
271 (rtinfo->rt_type != 0) ||
272 (rtinfo->invflags & IP6T_RT_INV_TYP)) ) {
273 DEBUGP("`--rt-type 0' required before `--rt-0-*'");
280 static struct ip6t_match rt_match
281 = { { NULL, NULL }, "rt", &match, &checkentry, NULL, THIS_MODULE };
283 static int __init init(void)
285 return ip6t_register_match(&rt_match);
288 static void __exit cleanup(void)
290 ip6t_unregister_match(&rt_match);
294 module_exit(cleanup);