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.25-rc1 261 lines 7.4 kB view raw
1/* 2 * xt_CONNMARK - Netfilter module to modify the connection mark values 3 * 4 * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> 5 * by Henrik Nordstrom <hno@marasystems.com> 6 * Copyright © CC Computer Consultants GmbH, 2007 - 2008 7 * Jan Engelhardt <jengelh@computergmbh.de> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23#include <linux/module.h> 24#include <linux/skbuff.h> 25#include <linux/ip.h> 26#include <net/checksum.h> 27 28MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>"); 29MODULE_DESCRIPTION("Xtables: connection mark modification"); 30MODULE_LICENSE("GPL"); 31MODULE_ALIAS("ipt_CONNMARK"); 32MODULE_ALIAS("ip6t_CONNMARK"); 33 34#include <linux/netfilter/x_tables.h> 35#include <linux/netfilter/xt_CONNMARK.h> 36#include <net/netfilter/nf_conntrack_ecache.h> 37 38static unsigned int 39connmark_tg_v0(struct sk_buff *skb, const struct net_device *in, 40 const struct net_device *out, unsigned int hooknum, 41 const struct xt_target *target, const void *targinfo) 42{ 43 const struct xt_connmark_target_info *markinfo = targinfo; 44 struct nf_conn *ct; 45 enum ip_conntrack_info ctinfo; 46 u_int32_t diff; 47 u_int32_t mark; 48 u_int32_t newmark; 49 50 ct = nf_ct_get(skb, &ctinfo); 51 if (ct) { 52 switch(markinfo->mode) { 53 case XT_CONNMARK_SET: 54 newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; 55 if (newmark != ct->mark) { 56 ct->mark = newmark; 57 nf_conntrack_event_cache(IPCT_MARK, skb); 58 } 59 break; 60 case XT_CONNMARK_SAVE: 61 newmark = (ct->mark & ~markinfo->mask) | 62 (skb->mark & markinfo->mask); 63 if (ct->mark != newmark) { 64 ct->mark = newmark; 65 nf_conntrack_event_cache(IPCT_MARK, skb); 66 } 67 break; 68 case XT_CONNMARK_RESTORE: 69 mark = skb->mark; 70 diff = (ct->mark ^ mark) & markinfo->mask; 71 skb->mark = mark ^ diff; 72 break; 73 } 74 } 75 76 return XT_CONTINUE; 77} 78 79static unsigned int 80connmark_tg(struct sk_buff *skb, const struct net_device *in, 81 const struct net_device *out, unsigned int hooknum, 82 const struct xt_target *target, const void *targinfo) 83{ 84 const struct xt_connmark_tginfo1 *info = targinfo; 85 enum ip_conntrack_info ctinfo; 86 struct nf_conn *ct; 87 u_int32_t newmark; 88 89 ct = nf_ct_get(skb, &ctinfo); 90 if (ct == NULL) 91 return XT_CONTINUE; 92 93 switch (info->mode) { 94 case XT_CONNMARK_SET: 95 newmark = (ct->mark & ~info->ctmask) ^ info->ctmark; 96 if (ct->mark != newmark) { 97 ct->mark = newmark; 98 nf_conntrack_event_cache(IPCT_MARK, skb); 99 } 100 break; 101 case XT_CONNMARK_SAVE: 102 newmark = (ct->mark & ~info->ctmask) ^ 103 (skb->mark & info->nfmask); 104 if (ct->mark != newmark) { 105 ct->mark = newmark; 106 nf_conntrack_event_cache(IPCT_MARK, skb); 107 } 108 break; 109 case XT_CONNMARK_RESTORE: 110 newmark = (skb->mark & ~info->nfmask) ^ 111 (ct->mark & info->ctmask); 112 skb->mark = newmark; 113 break; 114 } 115 116 return XT_CONTINUE; 117} 118 119static bool 120connmark_tg_check_v0(const char *tablename, const void *entry, 121 const struct xt_target *target, void *targinfo, 122 unsigned int hook_mask) 123{ 124 const struct xt_connmark_target_info *matchinfo = targinfo; 125 126 if (matchinfo->mode == XT_CONNMARK_RESTORE) { 127 if (strcmp(tablename, "mangle") != 0) { 128 printk(KERN_WARNING "CONNMARK: restore can only be " 129 "called from \"mangle\" table, not \"%s\"\n", 130 tablename); 131 return false; 132 } 133 } 134 if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) { 135 printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n"); 136 return false; 137 } 138 if (nf_ct_l3proto_try_module_get(target->family) < 0) { 139 printk(KERN_WARNING "can't load conntrack support for " 140 "proto=%u\n", target->family); 141 return false; 142 } 143 return true; 144} 145 146static bool 147connmark_tg_check(const char *tablename, const void *entry, 148 const struct xt_target *target, void *targinfo, 149 unsigned int hook_mask) 150{ 151 if (nf_ct_l3proto_try_module_get(target->family) < 0) { 152 printk(KERN_WARNING "cannot load conntrack support for " 153 "proto=%u\n", target->family); 154 return false; 155 } 156 return true; 157} 158 159static void 160connmark_tg_destroy(const struct xt_target *target, void *targinfo) 161{ 162 nf_ct_l3proto_module_put(target->family); 163} 164 165#ifdef CONFIG_COMPAT 166struct compat_xt_connmark_target_info { 167 compat_ulong_t mark, mask; 168 u_int8_t mode; 169 u_int8_t __pad1; 170 u_int16_t __pad2; 171}; 172 173static void connmark_tg_compat_from_user_v0(void *dst, void *src) 174{ 175 const struct compat_xt_connmark_target_info *cm = src; 176 struct xt_connmark_target_info m = { 177 .mark = cm->mark, 178 .mask = cm->mask, 179 .mode = cm->mode, 180 }; 181 memcpy(dst, &m, sizeof(m)); 182} 183 184static int connmark_tg_compat_to_user_v0(void __user *dst, void *src) 185{ 186 const struct xt_connmark_target_info *m = src; 187 struct compat_xt_connmark_target_info cm = { 188 .mark = m->mark, 189 .mask = m->mask, 190 .mode = m->mode, 191 }; 192 return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; 193} 194#endif /* CONFIG_COMPAT */ 195 196static struct xt_target connmark_tg_reg[] __read_mostly = { 197 { 198 .name = "CONNMARK", 199 .revision = 0, 200 .family = AF_INET, 201 .checkentry = connmark_tg_check_v0, 202 .destroy = connmark_tg_destroy, 203 .target = connmark_tg_v0, 204 .targetsize = sizeof(struct xt_connmark_target_info), 205#ifdef CONFIG_COMPAT 206 .compatsize = sizeof(struct compat_xt_connmark_target_info), 207 .compat_from_user = connmark_tg_compat_from_user_v0, 208 .compat_to_user = connmark_tg_compat_to_user_v0, 209#endif 210 .me = THIS_MODULE 211 }, 212 { 213 .name = "CONNMARK", 214 .revision = 0, 215 .family = AF_INET6, 216 .checkentry = connmark_tg_check_v0, 217 .destroy = connmark_tg_destroy, 218 .target = connmark_tg_v0, 219 .targetsize = sizeof(struct xt_connmark_target_info), 220#ifdef CONFIG_COMPAT 221 .compatsize = sizeof(struct compat_xt_connmark_target_info), 222 .compat_from_user = connmark_tg_compat_from_user_v0, 223 .compat_to_user = connmark_tg_compat_to_user_v0, 224#endif 225 .me = THIS_MODULE 226 }, 227 { 228 .name = "CONNMARK", 229 .revision = 1, 230 .family = AF_INET, 231 .checkentry = connmark_tg_check, 232 .target = connmark_tg, 233 .targetsize = sizeof(struct xt_connmark_tginfo1), 234 .destroy = connmark_tg_destroy, 235 .me = THIS_MODULE, 236 }, 237 { 238 .name = "CONNMARK", 239 .revision = 1, 240 .family = AF_INET6, 241 .checkentry = connmark_tg_check, 242 .target = connmark_tg, 243 .targetsize = sizeof(struct xt_connmark_tginfo1), 244 .destroy = connmark_tg_destroy, 245 .me = THIS_MODULE, 246 }, 247}; 248 249static int __init connmark_tg_init(void) 250{ 251 return xt_register_targets(connmark_tg_reg, 252 ARRAY_SIZE(connmark_tg_reg)); 253} 254 255static void __exit connmark_tg_exit(void) 256{ 257 xt_unregister_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg)); 258} 259 260module_init(connmark_tg_init); 261module_exit(connmark_tg_exit);