0001
0002
0003
0004
0005
0006
0007
0008
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);