196e32272SJan Engelhardt /* 2b8f00ba2SJan Engelhardt * xt_connmark - Netfilter module to operate on connection marks 32e4e6a17SHarald Welte * 42e4e6a17SHarald Welte * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> 52e4e6a17SHarald Welte * by Henrik Nordstrom <hno@marasystems.com> 696e32272SJan Engelhardt * Copyright © CC Computer Consultants GmbH, 2007 - 2008 7408ffaa4SJan Engelhardt * Jan Engelhardt <jengelh@medozas.de> 82e4e6a17SHarald Welte * 92e4e6a17SHarald Welte * This program is free software; you can redistribute it and/or modify 102e4e6a17SHarald Welte * it under the terms of the GNU General Public License as published by 112e4e6a17SHarald Welte * the Free Software Foundation; either version 2 of the License, or 122e4e6a17SHarald Welte * (at your option) any later version. 132e4e6a17SHarald Welte * 142e4e6a17SHarald Welte * This program is distributed in the hope that it will be useful, 152e4e6a17SHarald Welte * but WITHOUT ANY WARRANTY; without even the implied warranty of 162e4e6a17SHarald Welte * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 172e4e6a17SHarald Welte * GNU General Public License for more details. 182e4e6a17SHarald Welte * 192e4e6a17SHarald Welte * You should have received a copy of the GNU General Public License 20e664eabdSJeff Kirsher * along with this program; if not, see <http://www.gnu.org/licenses/>. 212e4e6a17SHarald Welte */ 222e4e6a17SHarald Welte 232e4e6a17SHarald Welte #include <linux/module.h> 242e4e6a17SHarald Welte #include <linux/skbuff.h> 25587aa641SPatrick McHardy #include <net/netfilter/nf_conntrack.h> 26b8f00ba2SJan Engelhardt #include <net/netfilter/nf_conntrack_ecache.h> 27587aa641SPatrick McHardy #include <linux/netfilter/x_tables.h> 28587aa641SPatrick McHardy #include <linux/netfilter/xt_connmark.h> 292e4e6a17SHarald Welte 303a4fa0a2SRobert P. J. Day MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>"); 31b8f00ba2SJan Engelhardt MODULE_DESCRIPTION("Xtables: connection mark operations"); 322e4e6a17SHarald Welte MODULE_LICENSE("GPL"); 33b8f00ba2SJan Engelhardt MODULE_ALIAS("ipt_CONNMARK"); 34b8f00ba2SJan Engelhardt MODULE_ALIAS("ip6t_CONNMARK"); 352e4e6a17SHarald Welte MODULE_ALIAS("ipt_connmark"); 3673aaf935SJan Engelhardt MODULE_ALIAS("ip6t_connmark"); 372e4e6a17SHarald Welte 38b8f00ba2SJan Engelhardt static unsigned int 39472a73e0SJack Ma connmark_tg_shift(struct sk_buff *skb, 40472a73e0SJack Ma const struct xt_connmark_tginfo1 *info, 41472a73e0SJack Ma u8 shift_bits, u8 shift_dir) 42b8f00ba2SJan Engelhardt { 43b8f00ba2SJan Engelhardt enum ip_conntrack_info ctinfo; 44b8f00ba2SJan Engelhardt struct nf_conn *ct; 45b8f00ba2SJan Engelhardt u_int32_t newmark; 46b8f00ba2SJan Engelhardt 47b8f00ba2SJan Engelhardt ct = nf_ct_get(skb, &ctinfo); 48ab8bc7edSFlorian Westphal if (ct == NULL) 49b8f00ba2SJan Engelhardt return XT_CONTINUE; 50b8f00ba2SJan Engelhardt 51b8f00ba2SJan Engelhardt switch (info->mode) { 52b8f00ba2SJan Engelhardt case XT_CONNMARK_SET: 53b8f00ba2SJan Engelhardt newmark = (ct->mark & ~info->ctmask) ^ info->ctmark; 54472a73e0SJack Ma if (shift_dir == D_SHIFT_RIGHT) 55472a73e0SJack Ma newmark >>= shift_bits; 56472a73e0SJack Ma else 57472a73e0SJack Ma newmark <<= shift_bits; 58b8f00ba2SJan Engelhardt if (ct->mark != newmark) { 59b8f00ba2SJan Engelhardt ct->mark = newmark; 60b8f00ba2SJan Engelhardt nf_conntrack_event_cache(IPCT_MARK, ct); 61b8f00ba2SJan Engelhardt } 62b8f00ba2SJan Engelhardt break; 63b8f00ba2SJan Engelhardt case XT_CONNMARK_SAVE: 64b8f00ba2SJan Engelhardt newmark = (ct->mark & ~info->ctmask) ^ 65b8f00ba2SJan Engelhardt (skb->mark & info->nfmask); 66472a73e0SJack Ma if (shift_dir == D_SHIFT_RIGHT) 67472a73e0SJack Ma newmark >>= shift_bits; 68472a73e0SJack Ma else 69472a73e0SJack Ma newmark <<= shift_bits; 70b8f00ba2SJan Engelhardt if (ct->mark != newmark) { 71b8f00ba2SJan Engelhardt ct->mark = newmark; 72b8f00ba2SJan Engelhardt nf_conntrack_event_cache(IPCT_MARK, ct); 73b8f00ba2SJan Engelhardt } 74b8f00ba2SJan Engelhardt break; 75b8f00ba2SJan Engelhardt case XT_CONNMARK_RESTORE: 76b8f00ba2SJan Engelhardt newmark = (skb->mark & ~info->nfmask) ^ 77b8f00ba2SJan Engelhardt (ct->mark & info->ctmask); 78472a73e0SJack Ma if (shift_dir == D_SHIFT_RIGHT) 79472a73e0SJack Ma newmark >>= shift_bits; 80472a73e0SJack Ma else 81472a73e0SJack Ma newmark <<= shift_bits; 82b8f00ba2SJan Engelhardt skb->mark = newmark; 83b8f00ba2SJan Engelhardt break; 84b8f00ba2SJan Engelhardt } 85b8f00ba2SJan Engelhardt return XT_CONTINUE; 86b8f00ba2SJan Engelhardt } 87b8f00ba2SJan Engelhardt 88472a73e0SJack Ma static unsigned int 89472a73e0SJack Ma connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) 90472a73e0SJack Ma { 91472a73e0SJack Ma const struct xt_connmark_tginfo1 *info = par->targinfo; 92472a73e0SJack Ma 93472a73e0SJack Ma return connmark_tg_shift(skb, info, 0, 0); 94472a73e0SJack Ma } 95472a73e0SJack Ma 96472a73e0SJack Ma static unsigned int 97472a73e0SJack Ma connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) 98472a73e0SJack Ma { 99472a73e0SJack Ma const struct xt_connmark_tginfo2 *info = par->targinfo; 100472a73e0SJack Ma 101472a73e0SJack Ma return connmark_tg_shift(skb, (const struct xt_connmark_tginfo1 *)info, 102472a73e0SJack Ma info->shift_bits, info->shift_dir); 103472a73e0SJack Ma } 104472a73e0SJack Ma 105135367b8SJan Engelhardt static int connmark_tg_check(const struct xt_tgchk_param *par) 106b8f00ba2SJan Engelhardt { 1074a5a5c73SJan Engelhardt int ret; 1084a5a5c73SJan Engelhardt 109ecb2421bSFlorian Westphal ret = nf_ct_netns_get(par->net, par->family); 110f95c74e3SJan Engelhardt if (ret < 0) 111b2606644SFlorian Westphal pr_info_ratelimited("cannot load conntrack support for proto=%u\n", 1128bee4badSJan Engelhardt par->family); 1134a5a5c73SJan Engelhardt return ret; 114b8f00ba2SJan Engelhardt } 115b8f00ba2SJan Engelhardt 116b8f00ba2SJan Engelhardt static void connmark_tg_destroy(const struct xt_tgdtor_param *par) 117b8f00ba2SJan Engelhardt { 118ecb2421bSFlorian Westphal nf_ct_netns_put(par->net, par->family); 119b8f00ba2SJan Engelhardt } 120b8f00ba2SJan Engelhardt 1211d93a9cbSJan Engelhardt static bool 12262fc8051SJan Engelhardt connmark_mt(const struct sk_buff *skb, struct xt_action_param *par) 1232e4e6a17SHarald Welte { 124f7108a20SJan Engelhardt const struct xt_connmark_mtinfo1 *info = par->matchinfo; 12596e32272SJan Engelhardt enum ip_conntrack_info ctinfo; 12696e32272SJan Engelhardt const struct nf_conn *ct; 12796e32272SJan Engelhardt 12896e32272SJan Engelhardt ct = nf_ct_get(skb, &ctinfo); 129ab8bc7edSFlorian Westphal if (ct == NULL) 13096e32272SJan Engelhardt return false; 13196e32272SJan Engelhardt 13296e32272SJan Engelhardt return ((ct->mark & info->mask) == info->mark) ^ info->invert; 13396e32272SJan Engelhardt } 13496e32272SJan Engelhardt 135b0f38452SJan Engelhardt static int connmark_mt_check(const struct xt_mtchk_param *par) 13696e32272SJan Engelhardt { 1374a5a5c73SJan Engelhardt int ret; 1384a5a5c73SJan Engelhardt 139ecb2421bSFlorian Westphal ret = nf_ct_netns_get(par->net, par->family); 140f95c74e3SJan Engelhardt if (ret < 0) 141b2606644SFlorian Westphal pr_info_ratelimited("cannot load conntrack support for proto=%u\n", 1428bee4badSJan Engelhardt par->family); 1434a5a5c73SJan Engelhardt return ret; 14496e32272SJan Engelhardt } 14596e32272SJan Engelhardt 1466be3d859SJan Engelhardt static void connmark_mt_destroy(const struct xt_mtdtor_param *par) 147b9f78f9fSPablo Neira Ayuso { 148ecb2421bSFlorian Westphal nf_ct_netns_put(par->net, par->family); 149b9f78f9fSPablo Neira Ayuso } 150b9f78f9fSPablo Neira Ayuso 151472a73e0SJack Ma static struct xt_target connmark_tg_reg[] __read_mostly = { 152472a73e0SJack Ma { 153b8f00ba2SJan Engelhardt .name = "CONNMARK", 154b8f00ba2SJan Engelhardt .revision = 1, 155b8f00ba2SJan Engelhardt .family = NFPROTO_UNSPEC, 156b8f00ba2SJan Engelhardt .checkentry = connmark_tg_check, 157b8f00ba2SJan Engelhardt .target = connmark_tg, 158b8f00ba2SJan Engelhardt .targetsize = sizeof(struct xt_connmark_tginfo1), 159b8f00ba2SJan Engelhardt .destroy = connmark_tg_destroy, 160b8f00ba2SJan Engelhardt .me = THIS_MODULE, 161472a73e0SJack Ma }, 162472a73e0SJack Ma { 163472a73e0SJack Ma .name = "CONNMARK", 164472a73e0SJack Ma .revision = 2, 165472a73e0SJack Ma .family = NFPROTO_UNSPEC, 166472a73e0SJack Ma .checkentry = connmark_tg_check, 167472a73e0SJack Ma .target = connmark_tg_v2, 168472a73e0SJack Ma .targetsize = sizeof(struct xt_connmark_tginfo2), 169472a73e0SJack Ma .destroy = connmark_tg_destroy, 170472a73e0SJack Ma .me = THIS_MODULE, 171472a73e0SJack Ma } 172b8f00ba2SJan Engelhardt }; 173b8f00ba2SJan Engelhardt 17484899a2bSJan Engelhardt static struct xt_match connmark_mt_reg __read_mostly = { 17596e32272SJan Engelhardt .name = "connmark", 17696e32272SJan Engelhardt .revision = 1, 17792f3b2b1SJan Engelhardt .family = NFPROTO_UNSPEC, 17896e32272SJan Engelhardt .checkentry = connmark_mt_check, 17996e32272SJan Engelhardt .match = connmark_mt, 18096e32272SJan Engelhardt .matchsize = sizeof(struct xt_connmark_mtinfo1), 18196e32272SJan Engelhardt .destroy = connmark_mt_destroy, 18296e32272SJan Engelhardt .me = THIS_MODULE, 1835d04bff0SPatrick McHardy }; 1842e4e6a17SHarald Welte 185d3c5ee6dSJan Engelhardt static int __init connmark_mt_init(void) 1862e4e6a17SHarald Welte { 187b8f00ba2SJan Engelhardt int ret; 188b8f00ba2SJan Engelhardt 189472a73e0SJack Ma ret = xt_register_targets(connmark_tg_reg, 190472a73e0SJack Ma ARRAY_SIZE(connmark_tg_reg)); 191b8f00ba2SJan Engelhardt if (ret < 0) 192b8f00ba2SJan Engelhardt return ret; 193b8f00ba2SJan Engelhardt ret = xt_register_match(&connmark_mt_reg); 194b8f00ba2SJan Engelhardt if (ret < 0) { 195472a73e0SJack Ma xt_unregister_targets(connmark_tg_reg, 196472a73e0SJack Ma ARRAY_SIZE(connmark_tg_reg)); 197b8f00ba2SJan Engelhardt return ret; 198b8f00ba2SJan Engelhardt } 199b8f00ba2SJan Engelhardt return 0; 2002e4e6a17SHarald Welte } 2012e4e6a17SHarald Welte 202d3c5ee6dSJan Engelhardt static void __exit connmark_mt_exit(void) 2032e4e6a17SHarald Welte { 20484899a2bSJan Engelhardt xt_unregister_match(&connmark_mt_reg); 205472a73e0SJack Ma xt_unregister_target(connmark_tg_reg); 2062e4e6a17SHarald Welte } 2072e4e6a17SHarald Welte 208d3c5ee6dSJan Engelhardt module_init(connmark_mt_init); 209d3c5ee6dSJan Engelhardt module_exit(connmark_mt_exit); 210