Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.32-rc1 183 lines 4.5 kB view raw
1/* 2 * iptables module for DCCP protocol header matching 3 * 4 * (C) 2005 by Harald Welte <laforge@netfilter.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11#include <linux/module.h> 12#include <linux/skbuff.h> 13#include <linux/spinlock.h> 14#include <net/ip.h> 15#include <linux/dccp.h> 16 17#include <linux/netfilter/x_tables.h> 18#include <linux/netfilter/xt_dccp.h> 19 20#include <linux/netfilter_ipv4/ip_tables.h> 21#include <linux/netfilter_ipv6/ip6_tables.h> 22 23MODULE_LICENSE("GPL"); 24MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 25MODULE_DESCRIPTION("Xtables: DCCP protocol packet match"); 26MODULE_ALIAS("ipt_dccp"); 27MODULE_ALIAS("ip6t_dccp"); 28 29#define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \ 30 || (!!((invflag) & (option)) ^ (cond))) 31 32static unsigned char *dccp_optbuf; 33static DEFINE_SPINLOCK(dccp_buflock); 34 35static inline bool 36dccp_find_option(u_int8_t option, 37 const struct sk_buff *skb, 38 unsigned int protoff, 39 const struct dccp_hdr *dh, 40 bool *hotdrop) 41{ 42 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ 43 const unsigned char *op; 44 unsigned int optoff = __dccp_hdr_len(dh); 45 unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh); 46 unsigned int i; 47 48 if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) 49 goto invalid; 50 51 if (!optlen) 52 return false; 53 54 spin_lock_bh(&dccp_buflock); 55 op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf); 56 if (op == NULL) { 57 /* If we don't have the whole header, drop packet. */ 58 goto partial; 59 } 60 61 for (i = 0; i < optlen; ) { 62 if (op[i] == option) { 63 spin_unlock_bh(&dccp_buflock); 64 return true; 65 } 66 67 if (op[i] < 2) 68 i++; 69 else 70 i += op[i+1]?:1; 71 } 72 73 spin_unlock_bh(&dccp_buflock); 74 return false; 75 76partial: 77 spin_unlock_bh(&dccp_buflock); 78invalid: 79 *hotdrop = true; 80 return false; 81} 82 83 84static inline bool 85match_types(const struct dccp_hdr *dh, u_int16_t typemask) 86{ 87 return typemask & (1 << dh->dccph_type); 88} 89 90static inline bool 91match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff, 92 const struct dccp_hdr *dh, bool *hotdrop) 93{ 94 return dccp_find_option(option, skb, protoff, dh, hotdrop); 95} 96 97static bool 98dccp_mt(const struct sk_buff *skb, const struct xt_match_param *par) 99{ 100 const struct xt_dccp_info *info = par->matchinfo; 101 const struct dccp_hdr *dh; 102 struct dccp_hdr _dh; 103 104 if (par->fragoff != 0) 105 return false; 106 107 dh = skb_header_pointer(skb, par->thoff, sizeof(_dh), &_dh); 108 if (dh == NULL) { 109 *par->hotdrop = true; 110 return false; 111 } 112 113 return DCCHECK(ntohs(dh->dccph_sport) >= info->spts[0] 114 && ntohs(dh->dccph_sport) <= info->spts[1], 115 XT_DCCP_SRC_PORTS, info->flags, info->invflags) 116 && DCCHECK(ntohs(dh->dccph_dport) >= info->dpts[0] 117 && ntohs(dh->dccph_dport) <= info->dpts[1], 118 XT_DCCP_DEST_PORTS, info->flags, info->invflags) 119 && DCCHECK(match_types(dh, info->typemask), 120 XT_DCCP_TYPE, info->flags, info->invflags) 121 && DCCHECK(match_option(info->option, skb, par->thoff, dh, 122 par->hotdrop), 123 XT_DCCP_OPTION, info->flags, info->invflags); 124} 125 126static bool dccp_mt_check(const struct xt_mtchk_param *par) 127{ 128 const struct xt_dccp_info *info = par->matchinfo; 129 130 return !(info->flags & ~XT_DCCP_VALID_FLAGS) 131 && !(info->invflags & ~XT_DCCP_VALID_FLAGS) 132 && !(info->invflags & ~info->flags); 133} 134 135static struct xt_match dccp_mt_reg[] __read_mostly = { 136 { 137 .name = "dccp", 138 .family = NFPROTO_IPV4, 139 .checkentry = dccp_mt_check, 140 .match = dccp_mt, 141 .matchsize = sizeof(struct xt_dccp_info), 142 .proto = IPPROTO_DCCP, 143 .me = THIS_MODULE, 144 }, 145 { 146 .name = "dccp", 147 .family = NFPROTO_IPV6, 148 .checkentry = dccp_mt_check, 149 .match = dccp_mt, 150 .matchsize = sizeof(struct xt_dccp_info), 151 .proto = IPPROTO_DCCP, 152 .me = THIS_MODULE, 153 }, 154}; 155 156static int __init dccp_mt_init(void) 157{ 158 int ret; 159 160 /* doff is 8 bits, so the maximum option size is (4*256). Don't put 161 * this in BSS since DaveM is worried about locked TLB's for kernel 162 * BSS. */ 163 dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL); 164 if (!dccp_optbuf) 165 return -ENOMEM; 166 ret = xt_register_matches(dccp_mt_reg, ARRAY_SIZE(dccp_mt_reg)); 167 if (ret) 168 goto out_kfree; 169 return ret; 170 171out_kfree: 172 kfree(dccp_optbuf); 173 return ret; 174} 175 176static void __exit dccp_mt_exit(void) 177{ 178 xt_unregister_matches(dccp_mt_reg, ARRAY_SIZE(dccp_mt_reg)); 179 kfree(dccp_optbuf); 180} 181 182module_init(dccp_mt_init); 183module_exit(dccp_mt_exit);