root/net/netfilter/xt_ipvs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ipvs_mt_addrcmp
  2. ipvs_mt
  3. ipvs_mt_check
  4. ipvs_mt_init
  5. ipvs_mt_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *      xt_ipvs - kernel module to match IPVS connection properties
   4  *
   5  *      Author: Hannes Eder <heder@google.com>
   6  */
   7 
   8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9 
  10 #include <linux/module.h>
  11 #include <linux/moduleparam.h>
  12 #include <linux/spinlock.h>
  13 #include <linux/skbuff.h>
  14 #ifdef CONFIG_IP_VS_IPV6
  15 #include <net/ipv6.h>
  16 #endif
  17 #include <linux/ip_vs.h>
  18 #include <linux/types.h>
  19 #include <linux/netfilter/x_tables.h>
  20 #include <linux/netfilter/xt_ipvs.h>
  21 #include <net/netfilter/nf_conntrack.h>
  22 
  23 #include <net/ip_vs.h>
  24 
  25 MODULE_AUTHOR("Hannes Eder <heder@google.com>");
  26 MODULE_DESCRIPTION("Xtables: match IPVS connection properties");
  27 MODULE_LICENSE("GPL");
  28 MODULE_ALIAS("ipt_ipvs");
  29 MODULE_ALIAS("ip6t_ipvs");
  30 
  31 /* borrowed from xt_conntrack */
  32 static bool ipvs_mt_addrcmp(const union nf_inet_addr *kaddr,
  33                             const union nf_inet_addr *uaddr,
  34                             const union nf_inet_addr *umask,
  35                             unsigned int l3proto)
  36 {
  37         if (l3proto == NFPROTO_IPV4)
  38                 return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
  39 #ifdef CONFIG_IP_VS_IPV6
  40         else if (l3proto == NFPROTO_IPV6)
  41                 return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
  42                        &uaddr->in6) == 0;
  43 #endif
  44         else
  45                 return false;
  46 }
  47 
  48 static bool
  49 ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par)
  50 {
  51         const struct xt_ipvs_mtinfo *data = par->matchinfo;
  52         struct netns_ipvs *ipvs = net_ipvs(xt_net(par));
  53         /* ipvs_mt_check ensures that family is only NFPROTO_IPV[46]. */
  54         const u_int8_t family = xt_family(par);
  55         struct ip_vs_iphdr iph;
  56         struct ip_vs_protocol *pp;
  57         struct ip_vs_conn *cp;
  58         bool match = true;
  59 
  60         if (data->bitmask == XT_IPVS_IPVS_PROPERTY) {
  61                 match = skb->ipvs_property ^
  62                         !!(data->invert & XT_IPVS_IPVS_PROPERTY);
  63                 goto out;
  64         }
  65 
  66         /* other flags than XT_IPVS_IPVS_PROPERTY are set */
  67         if (!skb->ipvs_property) {
  68                 match = false;
  69                 goto out;
  70         }
  71 
  72         ip_vs_fill_iph_skb(family, skb, true, &iph);
  73 
  74         if (data->bitmask & XT_IPVS_PROTO)
  75                 if ((iph.protocol == data->l4proto) ^
  76                     !(data->invert & XT_IPVS_PROTO)) {
  77                         match = false;
  78                         goto out;
  79                 }
  80 
  81         pp = ip_vs_proto_get(iph.protocol);
  82         if (unlikely(!pp)) {
  83                 match = false;
  84                 goto out;
  85         }
  86 
  87         /*
  88          * Check if the packet belongs to an existing entry
  89          */
  90         cp = pp->conn_out_get(ipvs, family, skb, &iph);
  91         if (unlikely(cp == NULL)) {
  92                 match = false;
  93                 goto out;
  94         }
  95 
  96         /*
  97          * We found a connection, i.e. ct != 0, make sure to call
  98          * __ip_vs_conn_put before returning.  In our case jump to out_put_con.
  99          */
 100 
 101         if (data->bitmask & XT_IPVS_VPORT)
 102                 if ((cp->vport == data->vport) ^
 103                     !(data->invert & XT_IPVS_VPORT)) {
 104                         match = false;
 105                         goto out_put_cp;
 106                 }
 107 
 108         if (data->bitmask & XT_IPVS_VPORTCTL)
 109                 if ((cp->control != NULL &&
 110                      cp->control->vport == data->vportctl) ^
 111                     !(data->invert & XT_IPVS_VPORTCTL)) {
 112                         match = false;
 113                         goto out_put_cp;
 114                 }
 115 
 116         if (data->bitmask & XT_IPVS_DIR) {
 117                 enum ip_conntrack_info ctinfo;
 118                 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 119 
 120                 if (ct == NULL) {
 121                         match = false;
 122                         goto out_put_cp;
 123                 }
 124 
 125                 if ((ctinfo >= IP_CT_IS_REPLY) ^
 126                     !!(data->invert & XT_IPVS_DIR)) {
 127                         match = false;
 128                         goto out_put_cp;
 129                 }
 130         }
 131 
 132         if (data->bitmask & XT_IPVS_METHOD)
 133                 if (((cp->flags & IP_VS_CONN_F_FWD_MASK) == data->fwd_method) ^
 134                     !(data->invert & XT_IPVS_METHOD)) {
 135                         match = false;
 136                         goto out_put_cp;
 137                 }
 138 
 139         if (data->bitmask & XT_IPVS_VADDR) {
 140                 if (ipvs_mt_addrcmp(&cp->vaddr, &data->vaddr,
 141                                     &data->vmask, family) ^
 142                     !(data->invert & XT_IPVS_VADDR)) {
 143                         match = false;
 144                         goto out_put_cp;
 145                 }
 146         }
 147 
 148 out_put_cp:
 149         __ip_vs_conn_put(cp);
 150 out:
 151         pr_debug("match=%d\n", match);
 152         return match;
 153 }
 154 
 155 static int ipvs_mt_check(const struct xt_mtchk_param *par)
 156 {
 157         if (par->family != NFPROTO_IPV4
 158 #ifdef CONFIG_IP_VS_IPV6
 159             && par->family != NFPROTO_IPV6
 160 #endif
 161                 ) {
 162                 pr_info_ratelimited("protocol family %u not supported\n",
 163                                     par->family);
 164                 return -EINVAL;
 165         }
 166 
 167         return 0;
 168 }
 169 
 170 static struct xt_match xt_ipvs_mt_reg __read_mostly = {
 171         .name       = "ipvs",
 172         .revision   = 0,
 173         .family     = NFPROTO_UNSPEC,
 174         .match      = ipvs_mt,
 175         .checkentry = ipvs_mt_check,
 176         .matchsize  = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
 177         .me         = THIS_MODULE,
 178 };
 179 
 180 static int __init ipvs_mt_init(void)
 181 {
 182         return xt_register_match(&xt_ipvs_mt_reg);
 183 }
 184 
 185 static void __exit ipvs_mt_exit(void)
 186 {
 187         xt_unregister_match(&xt_ipvs_mt_reg);
 188 }
 189 
 190 module_init(ipvs_mt_init);
 191 module_exit(ipvs_mt_exit);

/* [<][>][^][v][top][bottom][index][help] */