0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009
0010 #include <linux/module.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/skbuff.h>
0014 #ifdef CONFIG_IP_VS_IPV6
0015 #include <net/ipv6.h>
0016 #endif
0017 #include <linux/ip_vs.h>
0018 #include <linux/types.h>
0019 #include <linux/netfilter/x_tables.h>
0020 #include <linux/netfilter/xt_ipvs.h>
0021 #include <net/netfilter/nf_conntrack.h>
0022
0023 #include <net/ip_vs.h>
0024
0025 MODULE_AUTHOR("Hannes Eder <heder@google.com>");
0026 MODULE_DESCRIPTION("Xtables: match IPVS connection properties");
0027 MODULE_LICENSE("GPL");
0028 MODULE_ALIAS("ipt_ipvs");
0029 MODULE_ALIAS("ip6t_ipvs");
0030
0031
0032 static bool ipvs_mt_addrcmp(const union nf_inet_addr *kaddr,
0033 const union nf_inet_addr *uaddr,
0034 const union nf_inet_addr *umask,
0035 unsigned int l3proto)
0036 {
0037 if (l3proto == NFPROTO_IPV4)
0038 return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
0039 #ifdef CONFIG_IP_VS_IPV6
0040 else if (l3proto == NFPROTO_IPV6)
0041 return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
0042 &uaddr->in6) == 0;
0043 #endif
0044 else
0045 return false;
0046 }
0047
0048 static bool
0049 ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par)
0050 {
0051 const struct xt_ipvs_mtinfo *data = par->matchinfo;
0052 struct netns_ipvs *ipvs = net_ipvs(xt_net(par));
0053
0054 const u_int8_t family = xt_family(par);
0055 struct ip_vs_iphdr iph;
0056 struct ip_vs_protocol *pp;
0057 struct ip_vs_conn *cp;
0058 bool match = true;
0059
0060 if (data->bitmask == XT_IPVS_IPVS_PROPERTY) {
0061 match = skb->ipvs_property ^
0062 !!(data->invert & XT_IPVS_IPVS_PROPERTY);
0063 goto out;
0064 }
0065
0066
0067 if (!skb->ipvs_property) {
0068 match = false;
0069 goto out;
0070 }
0071
0072 ip_vs_fill_iph_skb(family, skb, true, &iph);
0073
0074 if (data->bitmask & XT_IPVS_PROTO)
0075 if ((iph.protocol == data->l4proto) ^
0076 !(data->invert & XT_IPVS_PROTO)) {
0077 match = false;
0078 goto out;
0079 }
0080
0081 pp = ip_vs_proto_get(iph.protocol);
0082 if (unlikely(!pp)) {
0083 match = false;
0084 goto out;
0085 }
0086
0087
0088
0089
0090 cp = pp->conn_out_get(ipvs, family, skb, &iph);
0091 if (unlikely(cp == NULL)) {
0092 match = false;
0093 goto out;
0094 }
0095
0096
0097
0098
0099
0100
0101 if (data->bitmask & XT_IPVS_VPORT)
0102 if ((cp->vport == data->vport) ^
0103 !(data->invert & XT_IPVS_VPORT)) {
0104 match = false;
0105 goto out_put_cp;
0106 }
0107
0108 if (data->bitmask & XT_IPVS_VPORTCTL)
0109 if ((cp->control != NULL &&
0110 cp->control->vport == data->vportctl) ^
0111 !(data->invert & XT_IPVS_VPORTCTL)) {
0112 match = false;
0113 goto out_put_cp;
0114 }
0115
0116 if (data->bitmask & XT_IPVS_DIR) {
0117 enum ip_conntrack_info ctinfo;
0118 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
0119
0120 if (ct == NULL) {
0121 match = false;
0122 goto out_put_cp;
0123 }
0124
0125 if ((ctinfo >= IP_CT_IS_REPLY) ^
0126 !!(data->invert & XT_IPVS_DIR)) {
0127 match = false;
0128 goto out_put_cp;
0129 }
0130 }
0131
0132 if (data->bitmask & XT_IPVS_METHOD)
0133 if (((cp->flags & IP_VS_CONN_F_FWD_MASK) == data->fwd_method) ^
0134 !(data->invert & XT_IPVS_METHOD)) {
0135 match = false;
0136 goto out_put_cp;
0137 }
0138
0139 if (data->bitmask & XT_IPVS_VADDR) {
0140 if (ipvs_mt_addrcmp(&cp->vaddr, &data->vaddr,
0141 &data->vmask, family) ^
0142 !(data->invert & XT_IPVS_VADDR)) {
0143 match = false;
0144 goto out_put_cp;
0145 }
0146 }
0147
0148 out_put_cp:
0149 __ip_vs_conn_put(cp);
0150 out:
0151 pr_debug("match=%d\n", match);
0152 return match;
0153 }
0154
0155 static int ipvs_mt_check(const struct xt_mtchk_param *par)
0156 {
0157 if (par->family != NFPROTO_IPV4
0158 #ifdef CONFIG_IP_VS_IPV6
0159 && par->family != NFPROTO_IPV6
0160 #endif
0161 ) {
0162 pr_info_ratelimited("protocol family %u not supported\n",
0163 par->family);
0164 return -EINVAL;
0165 }
0166
0167 return 0;
0168 }
0169
0170 static struct xt_match xt_ipvs_mt_reg __read_mostly = {
0171 .name = "ipvs",
0172 .revision = 0,
0173 .family = NFPROTO_UNSPEC,
0174 .match = ipvs_mt,
0175 .checkentry = ipvs_mt_check,
0176 .matchsize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
0177 .me = THIS_MODULE,
0178 };
0179
0180 static int __init ipvs_mt_init(void)
0181 {
0182 return xt_register_match(&xt_ipvs_mt_reg);
0183 }
0184
0185 static void __exit ipvs_mt_exit(void)
0186 {
0187 xt_unregister_match(&xt_ipvs_mt_reg);
0188 }
0189
0190 module_init(ipvs_mt_init);
0191 module_exit(ipvs_mt_exit);