Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  xt_conntrack - Netfilter module to match connection tracking
0004  *  information. (Superset of Rusty's minimalistic state match.)
0005  *
0006  *  (C) 2001  Marc Boucher (marc@mbsi.ca).
0007  *  (C) 2006-2012 Patrick McHardy <kaber@trash.net>
0008  *  Copyright © CC Computer Consultants GmbH, 2007 - 2008
0009  */
0010 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0011 #include <linux/module.h>
0012 #include <linux/skbuff.h>
0013 #include <net/ipv6.h>
0014 #include <linux/netfilter/x_tables.h>
0015 #include <linux/netfilter/xt_conntrack.h>
0016 #include <net/netfilter/nf_conntrack.h>
0017 
0018 MODULE_LICENSE("GPL");
0019 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
0020 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
0021 MODULE_DESCRIPTION("Xtables: connection tracking state match");
0022 MODULE_ALIAS("ipt_conntrack");
0023 MODULE_ALIAS("ip6t_conntrack");
0024 
0025 static bool
0026 conntrack_addrcmp(const union nf_inet_addr *kaddr,
0027                   const union nf_inet_addr *uaddr,
0028                   const union nf_inet_addr *umask, unsigned int l3proto)
0029 {
0030     if (l3proto == NFPROTO_IPV4)
0031         return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
0032     else if (l3proto == NFPROTO_IPV6)
0033         return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
0034                &uaddr->in6) == 0;
0035     else
0036         return false;
0037 }
0038 
0039 static inline bool
0040 conntrack_mt_origsrc(const struct nf_conn *ct,
0041                      const struct xt_conntrack_mtinfo2 *info,
0042              u_int8_t family)
0043 {
0044     return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
0045            &info->origsrc_addr, &info->origsrc_mask, family);
0046 }
0047 
0048 static inline bool
0049 conntrack_mt_origdst(const struct nf_conn *ct,
0050                      const struct xt_conntrack_mtinfo2 *info,
0051              u_int8_t family)
0052 {
0053     return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3,
0054            &info->origdst_addr, &info->origdst_mask, family);
0055 }
0056 
0057 static inline bool
0058 conntrack_mt_replsrc(const struct nf_conn *ct,
0059                      const struct xt_conntrack_mtinfo2 *info,
0060              u_int8_t family)
0061 {
0062     return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3,
0063            &info->replsrc_addr, &info->replsrc_mask, family);
0064 }
0065 
0066 static inline bool
0067 conntrack_mt_repldst(const struct nf_conn *ct,
0068                      const struct xt_conntrack_mtinfo2 *info,
0069              u_int8_t family)
0070 {
0071     return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3,
0072            &info->repldst_addr, &info->repldst_mask, family);
0073 }
0074 
0075 static inline bool
0076 ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
0077                     const struct nf_conn *ct)
0078 {
0079     const struct nf_conntrack_tuple *tuple;
0080 
0081     tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
0082     if ((info->match_flags & XT_CONNTRACK_PROTO) &&
0083         (nf_ct_protonum(ct) == info->l4proto) ^
0084         !(info->invert_flags & XT_CONNTRACK_PROTO))
0085         return false;
0086 
0087     /* Shortcut to match all recognized protocols by using ->src.all. */
0088     if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
0089         (tuple->src.u.all == info->origsrc_port) ^
0090         !(info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT))
0091         return false;
0092 
0093     if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
0094         (tuple->dst.u.all == info->origdst_port) ^
0095         !(info->invert_flags & XT_CONNTRACK_ORIGDST_PORT))
0096         return false;
0097 
0098     tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
0099 
0100     if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
0101         (tuple->src.u.all == info->replsrc_port) ^
0102         !(info->invert_flags & XT_CONNTRACK_REPLSRC_PORT))
0103         return false;
0104 
0105     if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
0106         (tuple->dst.u.all == info->repldst_port) ^
0107         !(info->invert_flags & XT_CONNTRACK_REPLDST_PORT))
0108         return false;
0109 
0110     return true;
0111 }
0112 
0113 static inline bool
0114 port_match(u16 min, u16 max, u16 port, bool invert)
0115 {
0116     return (port >= min && port <= max) ^ invert;
0117 }
0118 
0119 static inline bool
0120 ct_proto_port_check_v3(const struct xt_conntrack_mtinfo3 *info,
0121                const struct nf_conn *ct)
0122 {
0123     const struct nf_conntrack_tuple *tuple;
0124 
0125     tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
0126     if ((info->match_flags & XT_CONNTRACK_PROTO) &&
0127         (nf_ct_protonum(ct) == info->l4proto) ^
0128         !(info->invert_flags & XT_CONNTRACK_PROTO))
0129         return false;
0130 
0131     /* Shortcut to match all recognized protocols by using ->src.all. */
0132     if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
0133         !port_match(info->origsrc_port, info->origsrc_port_high,
0134             ntohs(tuple->src.u.all),
0135             info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT))
0136         return false;
0137 
0138     if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
0139         !port_match(info->origdst_port, info->origdst_port_high,
0140             ntohs(tuple->dst.u.all),
0141             info->invert_flags & XT_CONNTRACK_ORIGDST_PORT))
0142         return false;
0143 
0144     tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
0145 
0146     if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
0147         !port_match(info->replsrc_port, info->replsrc_port_high,
0148             ntohs(tuple->src.u.all),
0149             info->invert_flags & XT_CONNTRACK_REPLSRC_PORT))
0150         return false;
0151 
0152     if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
0153         !port_match(info->repldst_port, info->repldst_port_high,
0154             ntohs(tuple->dst.u.all),
0155             info->invert_flags & XT_CONNTRACK_REPLDST_PORT))
0156         return false;
0157 
0158     return true;
0159 }
0160 
0161 static bool
0162 conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par,
0163              u16 state_mask, u16 status_mask)
0164 {
0165     const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
0166     enum ip_conntrack_info ctinfo;
0167     const struct nf_conn *ct;
0168     unsigned int statebit;
0169 
0170     ct = nf_ct_get(skb, &ctinfo);
0171 
0172     if (ct)
0173         statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
0174     else if (ctinfo == IP_CT_UNTRACKED)
0175         statebit = XT_CONNTRACK_STATE_UNTRACKED;
0176     else
0177         statebit = XT_CONNTRACK_STATE_INVALID;
0178 
0179     if (info->match_flags & XT_CONNTRACK_STATE) {
0180         if (ct != NULL) {
0181             if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
0182                 statebit |= XT_CONNTRACK_STATE_SNAT;
0183             if (test_bit(IPS_DST_NAT_BIT, &ct->status))
0184                 statebit |= XT_CONNTRACK_STATE_DNAT;
0185         }
0186         if (!!(state_mask & statebit) ^
0187             !(info->invert_flags & XT_CONNTRACK_STATE))
0188             return false;
0189     }
0190 
0191     if (ct == NULL)
0192         return info->match_flags & XT_CONNTRACK_STATE;
0193     if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
0194         (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
0195         !(info->invert_flags & XT_CONNTRACK_DIRECTION))
0196         return false;
0197 
0198     if (info->match_flags & XT_CONNTRACK_ORIGSRC)
0199         if (conntrack_mt_origsrc(ct, info, xt_family(par)) ^
0200             !(info->invert_flags & XT_CONNTRACK_ORIGSRC))
0201             return false;
0202 
0203     if (info->match_flags & XT_CONNTRACK_ORIGDST)
0204         if (conntrack_mt_origdst(ct, info, xt_family(par)) ^
0205             !(info->invert_flags & XT_CONNTRACK_ORIGDST))
0206             return false;
0207 
0208     if (info->match_flags & XT_CONNTRACK_REPLSRC)
0209         if (conntrack_mt_replsrc(ct, info, xt_family(par)) ^
0210             !(info->invert_flags & XT_CONNTRACK_REPLSRC))
0211             return false;
0212 
0213     if (info->match_flags & XT_CONNTRACK_REPLDST)
0214         if (conntrack_mt_repldst(ct, info, xt_family(par)) ^
0215             !(info->invert_flags & XT_CONNTRACK_REPLDST))
0216             return false;
0217 
0218     if (par->match->revision != 3) {
0219         if (!ct_proto_port_check(info, ct))
0220             return false;
0221     } else {
0222         if (!ct_proto_port_check_v3(par->matchinfo, ct))
0223             return false;
0224     }
0225 
0226     if ((info->match_flags & XT_CONNTRACK_STATUS) &&
0227         (!!(status_mask & ct->status) ^
0228         !(info->invert_flags & XT_CONNTRACK_STATUS)))
0229         return false;
0230 
0231     if (info->match_flags & XT_CONNTRACK_EXPIRES) {
0232         unsigned long expires = nf_ct_expires(ct) / HZ;
0233 
0234         if ((expires >= info->expires_min &&
0235             expires <= info->expires_max) ^
0236             !(info->invert_flags & XT_CONNTRACK_EXPIRES))
0237             return false;
0238     }
0239     return true;
0240 }
0241 
0242 static bool
0243 conntrack_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
0244 {
0245     const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
0246 
0247     return conntrack_mt(skb, par, info->state_mask, info->status_mask);
0248 }
0249 
0250 static bool
0251 conntrack_mt_v2(const struct sk_buff *skb, struct xt_action_param *par)
0252 {
0253     const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
0254 
0255     return conntrack_mt(skb, par, info->state_mask, info->status_mask);
0256 }
0257 
0258 static bool
0259 conntrack_mt_v3(const struct sk_buff *skb, struct xt_action_param *par)
0260 {
0261     const struct xt_conntrack_mtinfo3 *info = par->matchinfo;
0262 
0263     return conntrack_mt(skb, par, info->state_mask, info->status_mask);
0264 }
0265 
0266 static int conntrack_mt_check(const struct xt_mtchk_param *par)
0267 {
0268     int ret;
0269 
0270     ret = nf_ct_netns_get(par->net, par->family);
0271     if (ret < 0)
0272         pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
0273                     par->family);
0274     return ret;
0275 }
0276 
0277 static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
0278 {
0279     nf_ct_netns_put(par->net, par->family);
0280 }
0281 
0282 static struct xt_match conntrack_mt_reg[] __read_mostly = {
0283     {
0284         .name       = "conntrack",
0285         .revision   = 1,
0286         .family     = NFPROTO_UNSPEC,
0287         .matchsize  = sizeof(struct xt_conntrack_mtinfo1),
0288         .match      = conntrack_mt_v1,
0289         .checkentry = conntrack_mt_check,
0290         .destroy    = conntrack_mt_destroy,
0291         .me         = THIS_MODULE,
0292     },
0293     {
0294         .name       = "conntrack",
0295         .revision   = 2,
0296         .family     = NFPROTO_UNSPEC,
0297         .matchsize  = sizeof(struct xt_conntrack_mtinfo2),
0298         .match      = conntrack_mt_v2,
0299         .checkentry = conntrack_mt_check,
0300         .destroy    = conntrack_mt_destroy,
0301         .me         = THIS_MODULE,
0302     },
0303     {
0304         .name       = "conntrack",
0305         .revision   = 3,
0306         .family     = NFPROTO_UNSPEC,
0307         .matchsize  = sizeof(struct xt_conntrack_mtinfo3),
0308         .match      = conntrack_mt_v3,
0309         .checkentry = conntrack_mt_check,
0310         .destroy    = conntrack_mt_destroy,
0311         .me         = THIS_MODULE,
0312     },
0313 };
0314 
0315 static int __init conntrack_mt_init(void)
0316 {
0317     return xt_register_matches(conntrack_mt_reg,
0318            ARRAY_SIZE(conntrack_mt_reg));
0319 }
0320 
0321 static void __exit conntrack_mt_exit(void)
0322 {
0323     xt_unregister_matches(conntrack_mt_reg, ARRAY_SIZE(conntrack_mt_reg));
0324 }
0325 
0326 module_init(conntrack_mt_init);
0327 module_exit(conntrack_mt_exit);