blob: d6e5ab4632775b5a93f3f624270d8cca392bdb5f [file] [log] [blame]
Jan Engelhardt0dc8c762008-01-14 23:38:34 -08001/*
2 * xt_CONNMARK - Netfilter module to modify the connection mark values
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Jan Engelhardt0dc8c762008-01-14 23:38:34 -08004 * 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>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
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
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +020028MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>");
Jan Engelhardt2ae15b62008-01-14 23:42:28 -080029MODULE_DESCRIPTION("Xtables: connection mark modification");
Linus Torvalds1da177e2005-04-16 15:20:36 -070030MODULE_LICENSE("GPL");
Harald Welte2e4e6a12006-01-12 13:30:04 -080031MODULE_ALIAS("ipt_CONNMARK");
Jan Engelhardt73aaf932007-10-11 14:36:40 -070032MODULE_ALIAS("ip6t_CONNMARK");
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Harald Welte2e4e6a12006-01-12 13:30:04 -080034#include <linux/netfilter/x_tables.h>
35#include <linux/netfilter/xt_CONNMARK.h>
Martin Josefssonf6180122006-11-29 02:35:01 +010036#include <net/netfilter/nf_conntrack_ecache.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
38static unsigned int
Jan Engelhardt7eb35582008-10-08 11:35:19 +020039connmark_tg_v0(struct sk_buff *skb, const struct xt_target_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070040{
Jan Engelhardt7eb35582008-10-08 11:35:19 +020041 const struct xt_connmark_target_info *markinfo = par->targinfo;
Patrick McHardy587aa642007-03-14 16:37:25 -070042 struct nf_conn *ct;
43 enum ip_conntrack_info ctinfo;
Harald Weltebf3a46a2005-08-09 19:22:01 -070044 u_int32_t diff;
Thomas Graf82e91ff2006-11-09 15:19:14 -080045 u_int32_t mark;
Harald Weltebf3a46a2005-08-09 19:22:01 -070046 u_int32_t newmark;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Herbert Xu3db05fe2007-10-15 00:53:15 -070048 ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy587aa642007-03-14 16:37:25 -070049 if (ct) {
Patrick McHardy90528e62006-08-22 00:33:26 -070050 switch(markinfo->mode) {
51 case XT_CONNMARK_SET:
Patrick McHardy587aa642007-03-14 16:37:25 -070052 newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
53 if (newmark != ct->mark) {
54 ct->mark = newmark;
Alexey Dobriyana71996f2008-10-08 11:35:07 +020055 nf_conntrack_event_cache(IPCT_MARK, ct);
Jan Engelhardt2822b0d2007-02-07 15:06:43 -080056 }
Patrick McHardy90528e62006-08-22 00:33:26 -070057 break;
58 case XT_CONNMARK_SAVE:
Patrick McHardy587aa642007-03-14 16:37:25 -070059 newmark = (ct->mark & ~markinfo->mask) |
Herbert Xu3db05fe2007-10-15 00:53:15 -070060 (skb->mark & markinfo->mask);
Patrick McHardy587aa642007-03-14 16:37:25 -070061 if (ct->mark != newmark) {
62 ct->mark = newmark;
Alexey Dobriyana71996f2008-10-08 11:35:07 +020063 nf_conntrack_event_cache(IPCT_MARK, ct);
Patrick McHardy90528e62006-08-22 00:33:26 -070064 }
65 break;
66 case XT_CONNMARK_RESTORE:
Herbert Xu3db05fe2007-10-15 00:53:15 -070067 mark = skb->mark;
Patrick McHardy587aa642007-03-14 16:37:25 -070068 diff = (ct->mark ^ mark) & markinfo->mask;
Herbert Xu3db05fe2007-10-15 00:53:15 -070069 skb->mark = mark ^ diff;
Patrick McHardy90528e62006-08-22 00:33:26 -070070 break;
Pablo Neira Ayuso2521c122006-08-22 00:31:24 -070071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 }
73
Harald Welte2e4e6a12006-01-12 13:30:04 -080074 return XT_CONTINUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075}
76
Jan Engelhardt0dc8c762008-01-14 23:38:34 -080077static unsigned int
Jan Engelhardt7eb35582008-10-08 11:35:19 +020078connmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
Jan Engelhardt0dc8c762008-01-14 23:38:34 -080079{
Jan Engelhardt7eb35582008-10-08 11:35:19 +020080 const struct xt_connmark_tginfo1 *info = par->targinfo;
Jan Engelhardt0dc8c762008-01-14 23:38:34 -080081 enum ip_conntrack_info ctinfo;
82 struct nf_conn *ct;
83 u_int32_t newmark;
84
85 ct = nf_ct_get(skb, &ctinfo);
86 if (ct == NULL)
87 return XT_CONTINUE;
88
89 switch (info->mode) {
90 case XT_CONNMARK_SET:
91 newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
92 if (ct->mark != newmark) {
93 ct->mark = newmark;
Alexey Dobriyana71996f2008-10-08 11:35:07 +020094 nf_conntrack_event_cache(IPCT_MARK, ct);
Jan Engelhardt0dc8c762008-01-14 23:38:34 -080095 }
96 break;
97 case XT_CONNMARK_SAVE:
98 newmark = (ct->mark & ~info->ctmask) ^
99 (skb->mark & info->nfmask);
100 if (ct->mark != newmark) {
101 ct->mark = newmark;
Alexey Dobriyana71996f2008-10-08 11:35:07 +0200102 nf_conntrack_event_cache(IPCT_MARK, ct);
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800103 }
104 break;
105 case XT_CONNMARK_RESTORE:
106 newmark = (skb->mark & ~info->nfmask) ^
107 (ct->mark & info->ctmask);
108 skb->mark = newmark;
109 break;
110 }
111
112 return XT_CONTINUE;
113}
114
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200115static bool connmark_tg_check_v0(const struct xt_tgchk_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200117 const struct xt_connmark_target_info *matchinfo = par->targinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Harald Welte2e4e6a12006-01-12 13:30:04 -0800119 if (matchinfo->mode == XT_CONNMARK_RESTORE) {
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200120 if (strcmp(par->table, "mangle") != 0) {
Patrick McHardy90528e62006-08-22 00:33:26 -0700121 printk(KERN_WARNING "CONNMARK: restore can only be "
122 "called from \"mangle\" table, not \"%s\"\n",
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200123 par->table);
Jan Engelhardte1931b72007-07-07 22:16:26 -0700124 return false;
Patrick McHardy90528e62006-08-22 00:33:26 -0700125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 }
Harald Weltebf3a46a2005-08-09 19:22:01 -0700127 if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) {
128 printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n");
Jan Engelhardte1931b72007-07-07 22:16:26 -0700129 return false;
Harald Weltebf3a46a2005-08-09 19:22:01 -0700130 }
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200131 if (nf_ct_l3proto_try_module_get(par->family) < 0) {
Jan Engelhardt67b4af22007-12-01 00:01:50 +1100132 printk(KERN_WARNING "can't load conntrack support for "
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200133 "proto=%u\n", par->family);
Jan Engelhardt67b4af22007-12-01 00:01:50 +1100134 return false;
135 }
Jan Engelhardte1931b72007-07-07 22:16:26 -0700136 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200139static bool connmark_tg_check(const struct xt_tgchk_param *par)
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800140{
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200141 if (nf_ct_l3proto_try_module_get(par->family) < 0) {
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800142 printk(KERN_WARNING "cannot load conntrack support for "
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200143 "proto=%u\n", par->family);
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800144 return false;
145 }
146 return true;
147}
148
Jan Engelhardta2df1642008-10-08 11:35:19 +0200149static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800150{
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200151 nf_ct_l3proto_module_put(par->family);
Yasuyuki Kozakai11078c32006-12-12 00:29:02 -0800152}
153
Patrick McHardy7ce975b2006-09-20 12:06:40 -0700154#ifdef CONFIG_COMPAT
155struct compat_xt_connmark_target_info {
156 compat_ulong_t mark, mask;
157 u_int8_t mode;
158 u_int8_t __pad1;
159 u_int16_t __pad2;
160};
161
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800162static void connmark_tg_compat_from_user_v0(void *dst, void *src)
Patrick McHardy7ce975b2006-09-20 12:06:40 -0700163{
Jan Engelhardta47362a2007-07-07 22:16:55 -0700164 const struct compat_xt_connmark_target_info *cm = src;
Patrick McHardy7ce975b2006-09-20 12:06:40 -0700165 struct xt_connmark_target_info m = {
166 .mark = cm->mark,
167 .mask = cm->mask,
168 .mode = cm->mode,
169 };
170 memcpy(dst, &m, sizeof(m));
171}
172
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800173static int connmark_tg_compat_to_user_v0(void __user *dst, void *src)
Patrick McHardy7ce975b2006-09-20 12:06:40 -0700174{
Jan Engelhardta47362a2007-07-07 22:16:55 -0700175 const struct xt_connmark_target_info *m = src;
Patrick McHardy7ce975b2006-09-20 12:06:40 -0700176 struct compat_xt_connmark_target_info cm = {
177 .mark = m->mark,
178 .mask = m->mask,
179 .mode = m->mode,
180 };
181 return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
182}
183#endif /* CONFIG_COMPAT */
184
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800185static struct xt_target connmark_tg_reg[] __read_mostly = {
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700186 {
187 .name = "CONNMARK",
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800188 .revision = 0,
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200189 .family = NFPROTO_UNSPEC,
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800190 .checkentry = connmark_tg_check_v0,
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800191 .destroy = connmark_tg_destroy,
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800192 .target = connmark_tg_v0,
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700193 .targetsize = sizeof(struct xt_connmark_target_info),
Patrick McHardy34f4c422007-12-17 21:50:53 -0800194#ifdef CONFIG_COMPAT
195 .compatsize = sizeof(struct compat_xt_connmark_target_info),
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800196 .compat_from_user = connmark_tg_compat_from_user_v0,
197 .compat_to_user = connmark_tg_compat_to_user_v0,
Patrick McHardy34f4c422007-12-17 21:50:53 -0800198#endif
Patrick McHardy4470bbc2006-08-22 00:34:04 -0700199 .me = THIS_MODULE
200 },
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800201 {
202 .name = "CONNMARK",
203 .revision = 1,
Jan Engelhardt92f3b2b2008-10-08 11:35:20 +0200204 .family = NFPROTO_UNSPEC,
Jan Engelhardt0dc8c762008-01-14 23:38:34 -0800205 .checkentry = connmark_tg_check,
206 .target = connmark_tg,
207 .targetsize = sizeof(struct xt_connmark_tginfo1),
208 .destroy = connmark_tg_destroy,
209 .me = THIS_MODULE,
210 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211};
212
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800213static int __init connmark_tg_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214{
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800215 return xt_register_targets(connmark_tg_reg,
216 ARRAY_SIZE(connmark_tg_reg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217}
218
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800219static void __exit connmark_tg_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220{
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800221 xt_unregister_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222}
223
Jan Engelhardtd3c5ee62007-12-04 23:24:03 -0800224module_init(connmark_tg_init);
225module_exit(connmark_tg_exit);