ip6t_hbh.c revision 5fa2a7601f994bdd034e871b7ea1abd6969fbb6c
1/* Kernel module to match Hop-by-Hop and Destination parameters. */ 2 3/* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10#include <linux/module.h> 11#include <linux/skbuff.h> 12#include <linux/ipv6.h> 13#include <linux/types.h> 14#include <net/checksum.h> 15#include <net/ipv6.h> 16 17#include <asm/byteorder.h> 18 19#include <linux/netfilter_ipv6/ip6_tables.h> 20#include <linux/netfilter_ipv6/ip6t_opts.h> 21 22MODULE_LICENSE("GPL"); 23MODULE_DESCRIPTION("IPv6 opts match"); 24MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); 25MODULE_ALIAS("ip6t_dst"); 26 27#if 0 28#define DEBUGP printk 29#else 30#define DEBUGP(format, args...) 31#endif 32 33/* 34 * (Type & 0xC0) >> 6 35 * 0 -> ignorable 36 * 1 -> must drop the packet 37 * 2 -> send ICMP PARM PROB regardless and drop packet 38 * 3 -> Send ICMP if not a multicast address and drop packet 39 * (Type & 0x20) >> 5 40 * 0 -> invariant 41 * 1 -> can change the routing 42 * (Type & 0x1F) Type 43 * 0 -> Pad1 (only 1 byte!) 44 * 1 -> PadN LENGTH info (total length = length + 2) 45 * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) 46 * 5 -> RTALERT 2 x x 47 */ 48 49static int 50match(const struct sk_buff *skb, 51 const struct net_device *in, 52 const struct net_device *out, 53 const struct xt_match *match, 54 const void *matchinfo, 55 int offset, 56 unsigned int protoff, 57 int *hotdrop) 58{ 59 struct ipv6_opt_hdr _optsh, *oh; 60 const struct ip6t_opts *optinfo = matchinfo; 61 unsigned int temp; 62 unsigned int ptr; 63 unsigned int hdrlen = 0; 64 unsigned int ret = 0; 65 u8 _opttype, *tp = NULL; 66 u8 _optlen, *lp = NULL; 67 unsigned int optlen; 68 69 if (ipv6_find_hdr(skb, &ptr, match->data, NULL) < 0) 70 return 0; 71 72 oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); 73 if (oh == NULL) { 74 *hotdrop = 1; 75 return 0; 76 } 77 78 hdrlen = ipv6_optlen(oh); 79 if (skb->len - ptr < hdrlen) { 80 /* Packet smaller than it's length field */ 81 return 0; 82 } 83 84 DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); 85 86 DEBUGP("len %02X %04X %02X ", 87 optinfo->hdrlen, hdrlen, 88 (!(optinfo->flags & IP6T_OPTS_LEN) || 89 ((optinfo->hdrlen == hdrlen) ^ 90 !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); 91 92 ret = (oh != NULL) && 93 (!(optinfo->flags & IP6T_OPTS_LEN) || 94 ((optinfo->hdrlen == hdrlen) ^ 95 !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); 96 97 ptr += 2; 98 hdrlen -= 2; 99 if (!(optinfo->flags & IP6T_OPTS_OPTS)) { 100 return ret; 101 } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { 102 DEBUGP("Not strict - not implemented"); 103 } else { 104 DEBUGP("Strict "); 105 DEBUGP("#%d ", optinfo->optsnr); 106 for (temp = 0; temp < optinfo->optsnr; temp++) { 107 /* type field exists ? */ 108 if (hdrlen < 1) 109 break; 110 tp = skb_header_pointer(skb, ptr, sizeof(_opttype), 111 &_opttype); 112 if (tp == NULL) 113 break; 114 115 /* Type check */ 116 if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) { 117 DEBUGP("Tbad %02X %02X\n", 118 *tp, 119 (optinfo->opts[temp] & 0xFF00) >> 8); 120 return 0; 121 } else { 122 DEBUGP("Tok "); 123 } 124 /* Length check */ 125 if (*tp) { 126 u16 spec_len; 127 128 /* length field exists ? */ 129 if (hdrlen < 2) 130 break; 131 lp = skb_header_pointer(skb, ptr + 1, 132 sizeof(_optlen), 133 &_optlen); 134 if (lp == NULL) 135 break; 136 spec_len = optinfo->opts[temp] & 0x00FF; 137 138 if (spec_len != 0x00FF && spec_len != *lp) { 139 DEBUGP("Lbad %02X %04X\n", *lp, 140 spec_len); 141 return 0; 142 } 143 DEBUGP("Lok "); 144 optlen = *lp + 2; 145 } else { 146 DEBUGP("Pad1\n"); 147 optlen = 1; 148 } 149 150 /* Step to the next */ 151 DEBUGP("len%04X \n", optlen); 152 153 if ((ptr > skb->len - optlen || hdrlen < optlen) && 154 (temp < optinfo->optsnr - 1)) { 155 DEBUGP("new pointer is too large! \n"); 156 break; 157 } 158 ptr += optlen; 159 hdrlen -= optlen; 160 } 161 if (temp == optinfo->optsnr) 162 return ret; 163 else 164 return 0; 165 } 166 167 return 0; 168} 169 170/* Called when user tries to insert an entry of this type. */ 171static int 172checkentry(const char *tablename, 173 const void *entry, 174 const struct xt_match *match, 175 void *matchinfo, 176 unsigned int hook_mask) 177{ 178 const struct ip6t_opts *optsinfo = matchinfo; 179 180 if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { 181 DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); 182 return 0; 183 } 184 return 1; 185} 186 187static struct xt_match opts_match[] = { 188 { 189 .name = "hbh", 190 .family = AF_INET6, 191 .match = match, 192 .matchsize = sizeof(struct ip6t_opts), 193 .checkentry = checkentry, 194 .me = THIS_MODULE, 195 .data = NEXTHDR_HOP, 196 }, 197 { 198 .name = "dst", 199 .family = AF_INET6, 200 .match = match, 201 .matchsize = sizeof(struct ip6t_opts), 202 .checkentry = checkentry, 203 .me = THIS_MODULE, 204 .data = NEXTHDR_DEST, 205 }, 206}; 207 208static int __init ip6t_hbh_init(void) 209{ 210 return xt_register_matches(opts_match, ARRAY_SIZE(opts_match)); 211} 212 213static void __exit ip6t_hbh_fini(void) 214{ 215 xt_unregister_matches(opts_match, ARRAY_SIZE(opts_match)); 216} 217 218module_init(ip6t_hbh_init); 219module_exit(ip6t_hbh_fini); 220