1/* Kernel module to match FRAG 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 <linux/netfilter/x_tables.h> 18#include <linux/netfilter_ipv6/ip6_tables.h> 19#include <linux/netfilter_ipv6/ip6t_frag.h> 20 21MODULE_LICENSE("GPL"); 22MODULE_DESCRIPTION("IPv6 FRAG match"); 23MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); 24 25#define DEBUGP(format, args...) 26 27/* Returns 1 if the id is matched by the range, 0 otherwise */ 28static inline int 29id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert) 30{ 31 int r = 0; 32 DEBUGP("frag id_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ', 33 min, id, max); 34 r = (id >= min && id <= max) ^ invert; 35 DEBUGP(" result %s\n", r ? "PASS" : "FAILED"); 36 return r; 37} 38 39static int 40match(const struct sk_buff *skb, 41 const struct net_device *in, 42 const struct net_device *out, 43 const struct xt_match *match, 44 const void *matchinfo, 45 int offset, 46 unsigned int protoff, 47 int *hotdrop) 48{ 49 struct frag_hdr _frag, *fh; 50 const struct ip6t_frag *fraginfo = matchinfo; 51 unsigned int ptr; 52 int err; 53 54 err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL); 55 if (err < 0) { 56 if (err != -ENOENT) 57 *hotdrop = 1; 58 return 0; 59 } 60 61 fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); 62 if (fh == NULL) { 63 *hotdrop = 1; 64 return 0; 65 } 66 67 DEBUGP("INFO %04X ", fh->frag_off); 68 DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); 69 DEBUGP("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6); 70 DEBUGP("MF %04X ", fh->frag_off & htons(IP6_MF)); 71 DEBUGP("ID %u %08X\n", ntohl(fh->identification), 72 ntohl(fh->identification)); 73 74 DEBUGP("IPv6 FRAG id %02X ", 75 (id_match(fraginfo->ids[0], fraginfo->ids[1], 76 ntohl(fh->identification), 77 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))); 78 DEBUGP("res %02X %02X%04X %02X ", 79 (fraginfo->flags & IP6T_FRAG_RES), fh->reserved, 80 ntohs(fh->frag_off) & 0x6, 81 !((fraginfo->flags & IP6T_FRAG_RES) 82 && (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); 83 DEBUGP("first %02X %02X %02X ", 84 (fraginfo->flags & IP6T_FRAG_FST), 85 ntohs(fh->frag_off) & ~0x7, 86 !((fraginfo->flags & IP6T_FRAG_FST) 87 && (ntohs(fh->frag_off) & ~0x7))); 88 DEBUGP("mf %02X %02X %02X ", 89 (fraginfo->flags & IP6T_FRAG_MF), 90 ntohs(fh->frag_off) & IP6_MF, 91 !((fraginfo->flags & IP6T_FRAG_MF) 92 && !((ntohs(fh->frag_off) & IP6_MF)))); 93 DEBUGP("last %02X %02X %02X\n", 94 (fraginfo->flags & IP6T_FRAG_NMF), 95 ntohs(fh->frag_off) & IP6_MF, 96 !((fraginfo->flags & IP6T_FRAG_NMF) 97 && (ntohs(fh->frag_off) & IP6_MF))); 98 99 return (fh != NULL) 100 && 101 (id_match(fraginfo->ids[0], fraginfo->ids[1], 102 ntohl(fh->identification), 103 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))) 104 && 105 !((fraginfo->flags & IP6T_FRAG_RES) 106 && (fh->reserved || (ntohs(fh->frag_off) & 0x6))) 107 && 108 !((fraginfo->flags & IP6T_FRAG_FST) 109 && (ntohs(fh->frag_off) & ~0x7)) 110 && 111 !((fraginfo->flags & IP6T_FRAG_MF) 112 && !(ntohs(fh->frag_off) & IP6_MF)) 113 && 114 !((fraginfo->flags & IP6T_FRAG_NMF) 115 && (ntohs(fh->frag_off) & IP6_MF)); 116} 117 118/* Called when user tries to insert an entry of this type. */ 119static int 120checkentry(const char *tablename, 121 const void *ip, 122 const struct xt_match *match, 123 void *matchinfo, 124 unsigned int hook_mask) 125{ 126 const struct ip6t_frag *fraginfo = matchinfo; 127 128 if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { 129 DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags); 130 return 0; 131 } 132 return 1; 133} 134 135static struct xt_match frag_match = { 136 .name = "frag", 137 .family = AF_INET6, 138 .match = match, 139 .matchsize = sizeof(struct ip6t_frag), 140 .checkentry = checkentry, 141 .me = THIS_MODULE, 142}; 143 144static int __init ip6t_frag_init(void) 145{ 146 return xt_register_match(&frag_match); 147} 148 149static void __exit ip6t_frag_fini(void) 150{ 151 xt_unregister_match(&frag_match); 152} 153 154module_init(ip6t_frag_init); 155module_exit(ip6t_frag_fini); 156