Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  xt_connmark - Netfilter module to operate on connection marks
0004  *
0005  *  Copyright (C) 2002,2004 MARA Systems AB <https://www.marasystems.com>
0006  *  by Henrik Nordstrom <hno@marasystems.com>
0007  *  Copyright © CC Computer Consultants GmbH, 2007 - 2008
0008  *  Jan Engelhardt <jengelh@medozas.de>
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/skbuff.h>
0013 #include <net/netfilter/nf_conntrack.h>
0014 #include <net/netfilter/nf_conntrack_ecache.h>
0015 #include <linux/netfilter/x_tables.h>
0016 #include <linux/netfilter/xt_connmark.h>
0017 
0018 MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>");
0019 MODULE_DESCRIPTION("Xtables: connection mark operations");
0020 MODULE_LICENSE("GPL");
0021 MODULE_ALIAS("ipt_CONNMARK");
0022 MODULE_ALIAS("ip6t_CONNMARK");
0023 MODULE_ALIAS("ipt_connmark");
0024 MODULE_ALIAS("ip6t_connmark");
0025 
0026 static unsigned int
0027 connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
0028 {
0029     enum ip_conntrack_info ctinfo;
0030     u_int32_t new_targetmark;
0031     struct nf_conn *ct;
0032     u_int32_t newmark;
0033 
0034     ct = nf_ct_get(skb, &ctinfo);
0035     if (ct == NULL)
0036         return XT_CONTINUE;
0037 
0038     switch (info->mode) {
0039     case XT_CONNMARK_SET:
0040         newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
0041         if (info->shift_dir == D_SHIFT_RIGHT)
0042             newmark >>= info->shift_bits;
0043         else
0044             newmark <<= info->shift_bits;
0045 
0046         if (ct->mark != newmark) {
0047             ct->mark = newmark;
0048             nf_conntrack_event_cache(IPCT_MARK, ct);
0049         }
0050         break;
0051     case XT_CONNMARK_SAVE:
0052         new_targetmark = (skb->mark & info->nfmask);
0053         if (info->shift_dir == D_SHIFT_RIGHT)
0054             new_targetmark >>= info->shift_bits;
0055         else
0056             new_targetmark <<= info->shift_bits;
0057 
0058         newmark = (ct->mark & ~info->ctmask) ^
0059               new_targetmark;
0060         if (ct->mark != newmark) {
0061             ct->mark = newmark;
0062             nf_conntrack_event_cache(IPCT_MARK, ct);
0063         }
0064         break;
0065     case XT_CONNMARK_RESTORE:
0066         new_targetmark = (ct->mark & info->ctmask);
0067         if (info->shift_dir == D_SHIFT_RIGHT)
0068             new_targetmark >>= info->shift_bits;
0069         else
0070             new_targetmark <<= info->shift_bits;
0071 
0072         newmark = (skb->mark & ~info->nfmask) ^
0073               new_targetmark;
0074         skb->mark = newmark;
0075         break;
0076     }
0077     return XT_CONTINUE;
0078 }
0079 
0080 static unsigned int
0081 connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
0082 {
0083     const struct xt_connmark_tginfo1 *info = par->targinfo;
0084     const struct xt_connmark_tginfo2 info2 = {
0085         .ctmark = info->ctmark,
0086         .ctmask = info->ctmask,
0087         .nfmask = info->nfmask,
0088         .mode   = info->mode,
0089     };
0090 
0091     return connmark_tg_shift(skb, &info2);
0092 }
0093 
0094 static unsigned int
0095 connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
0096 {
0097     const struct xt_connmark_tginfo2 *info = par->targinfo;
0098 
0099     return connmark_tg_shift(skb, info);
0100 }
0101 
0102 static int connmark_tg_check(const struct xt_tgchk_param *par)
0103 {
0104     int ret;
0105 
0106     ret = nf_ct_netns_get(par->net, par->family);
0107     if (ret < 0)
0108         pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
0109                     par->family);
0110     return ret;
0111 }
0112 
0113 static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
0114 {
0115     nf_ct_netns_put(par->net, par->family);
0116 }
0117 
0118 static bool
0119 connmark_mt(const struct sk_buff *skb, struct xt_action_param *par)
0120 {
0121     const struct xt_connmark_mtinfo1 *info = par->matchinfo;
0122     enum ip_conntrack_info ctinfo;
0123     const struct nf_conn *ct;
0124 
0125     ct = nf_ct_get(skb, &ctinfo);
0126     if (ct == NULL)
0127         return false;
0128 
0129     return ((ct->mark & info->mask) == info->mark) ^ info->invert;
0130 }
0131 
0132 static int connmark_mt_check(const struct xt_mtchk_param *par)
0133 {
0134     int ret;
0135 
0136     ret = nf_ct_netns_get(par->net, par->family);
0137     if (ret < 0)
0138         pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
0139                     par->family);
0140     return ret;
0141 }
0142 
0143 static void connmark_mt_destroy(const struct xt_mtdtor_param *par)
0144 {
0145     nf_ct_netns_put(par->net, par->family);
0146 }
0147 
0148 static struct xt_target connmark_tg_reg[] __read_mostly = {
0149     {
0150         .name           = "CONNMARK",
0151         .revision       = 1,
0152         .family         = NFPROTO_UNSPEC,
0153         .checkentry     = connmark_tg_check,
0154         .target         = connmark_tg,
0155         .targetsize     = sizeof(struct xt_connmark_tginfo1),
0156         .destroy        = connmark_tg_destroy,
0157         .me             = THIS_MODULE,
0158     },
0159     {
0160         .name           = "CONNMARK",
0161         .revision       = 2,
0162         .family         = NFPROTO_UNSPEC,
0163         .checkentry     = connmark_tg_check,
0164         .target         = connmark_tg_v2,
0165         .targetsize     = sizeof(struct xt_connmark_tginfo2),
0166         .destroy        = connmark_tg_destroy,
0167         .me             = THIS_MODULE,
0168     }
0169 };
0170 
0171 static struct xt_match connmark_mt_reg __read_mostly = {
0172     .name           = "connmark",
0173     .revision       = 1,
0174     .family         = NFPROTO_UNSPEC,
0175     .checkentry     = connmark_mt_check,
0176     .match          = connmark_mt,
0177     .matchsize      = sizeof(struct xt_connmark_mtinfo1),
0178     .destroy        = connmark_mt_destroy,
0179     .me             = THIS_MODULE,
0180 };
0181 
0182 static int __init connmark_mt_init(void)
0183 {
0184     int ret;
0185 
0186     ret = xt_register_targets(connmark_tg_reg,
0187                   ARRAY_SIZE(connmark_tg_reg));
0188     if (ret < 0)
0189         return ret;
0190     ret = xt_register_match(&connmark_mt_reg);
0191     if (ret < 0) {
0192         xt_unregister_targets(connmark_tg_reg,
0193                       ARRAY_SIZE(connmark_tg_reg));
0194         return ret;
0195     }
0196     return 0;
0197 }
0198 
0199 static void __exit connmark_mt_exit(void)
0200 {
0201     xt_unregister_match(&connmark_mt_reg);
0202     xt_unregister_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg));
0203 }
0204 
0205 module_init(connmark_mt_init);
0206 module_exit(connmark_mt_exit);