0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/netlink.h>
0008 #include <linux/netfilter.h>
0009 #include <linux/netfilter/nf_tables.h>
0010 #include <net/dst.h>
0011 #include <net/ip6_route.h>
0012 #include <net/route.h>
0013 #include <net/netfilter/nf_tables.h>
0014 #include <net/netfilter/nf_tables_core.h>
0015
0016 struct nft_rt {
0017 enum nft_rt_keys key:8;
0018 u8 dreg;
0019 };
0020
0021 static u16 get_tcpmss(const struct nft_pktinfo *pkt, const struct dst_entry *skbdst)
0022 {
0023 u32 minlen = sizeof(struct ipv6hdr), mtu = dst_mtu(skbdst);
0024 const struct sk_buff *skb = pkt->skb;
0025 struct dst_entry *dst = NULL;
0026 struct flowi fl;
0027
0028 memset(&fl, 0, sizeof(fl));
0029
0030 switch (nft_pf(pkt)) {
0031 case NFPROTO_IPV4:
0032 fl.u.ip4.daddr = ip_hdr(skb)->saddr;
0033 minlen = sizeof(struct iphdr) + sizeof(struct tcphdr);
0034 break;
0035 case NFPROTO_IPV6:
0036 fl.u.ip6.daddr = ipv6_hdr(skb)->saddr;
0037 minlen = sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
0038 break;
0039 }
0040
0041 nf_route(nft_net(pkt), &dst, &fl, false, nft_pf(pkt));
0042 if (dst) {
0043 mtu = min(mtu, dst_mtu(dst));
0044 dst_release(dst);
0045 }
0046
0047 if (mtu <= minlen || mtu > 0xffff)
0048 return TCP_MSS_DEFAULT;
0049
0050 return mtu - minlen;
0051 }
0052
0053 void nft_rt_get_eval(const struct nft_expr *expr,
0054 struct nft_regs *regs,
0055 const struct nft_pktinfo *pkt)
0056 {
0057 const struct nft_rt *priv = nft_expr_priv(expr);
0058 const struct sk_buff *skb = pkt->skb;
0059 u32 *dest = ®s->data[priv->dreg];
0060 const struct dst_entry *dst;
0061
0062 dst = skb_dst(skb);
0063 if (!dst)
0064 goto err;
0065
0066 switch (priv->key) {
0067 #ifdef CONFIG_IP_ROUTE_CLASSID
0068 case NFT_RT_CLASSID:
0069 *dest = dst->tclassid;
0070 break;
0071 #endif
0072 case NFT_RT_NEXTHOP4:
0073 if (nft_pf(pkt) != NFPROTO_IPV4)
0074 goto err;
0075
0076 *dest = (__force u32)rt_nexthop((const struct rtable *)dst,
0077 ip_hdr(skb)->daddr);
0078 break;
0079 case NFT_RT_NEXTHOP6:
0080 if (nft_pf(pkt) != NFPROTO_IPV6)
0081 goto err;
0082
0083 memcpy(dest, rt6_nexthop((struct rt6_info *)dst,
0084 &ipv6_hdr(skb)->daddr),
0085 sizeof(struct in6_addr));
0086 break;
0087 case NFT_RT_TCPMSS:
0088 nft_reg_store16(dest, get_tcpmss(pkt, dst));
0089 break;
0090 #ifdef CONFIG_XFRM
0091 case NFT_RT_XFRM:
0092 nft_reg_store8(dest, !!dst->xfrm);
0093 break;
0094 #endif
0095 default:
0096 WARN_ON(1);
0097 goto err;
0098 }
0099 return;
0100
0101 err:
0102 regs->verdict.code = NFT_BREAK;
0103 }
0104
0105 static const struct nla_policy nft_rt_policy[NFTA_RT_MAX + 1] = {
0106 [NFTA_RT_DREG] = { .type = NLA_U32 },
0107 [NFTA_RT_KEY] = { .type = NLA_U32 },
0108 };
0109
0110 static int nft_rt_get_init(const struct nft_ctx *ctx,
0111 const struct nft_expr *expr,
0112 const struct nlattr * const tb[])
0113 {
0114 struct nft_rt *priv = nft_expr_priv(expr);
0115 unsigned int len;
0116
0117 if (tb[NFTA_RT_KEY] == NULL ||
0118 tb[NFTA_RT_DREG] == NULL)
0119 return -EINVAL;
0120
0121 priv->key = ntohl(nla_get_be32(tb[NFTA_RT_KEY]));
0122 switch (priv->key) {
0123 #ifdef CONFIG_IP_ROUTE_CLASSID
0124 case NFT_RT_CLASSID:
0125 #endif
0126 case NFT_RT_NEXTHOP4:
0127 len = sizeof(u32);
0128 break;
0129 case NFT_RT_NEXTHOP6:
0130 len = sizeof(struct in6_addr);
0131 break;
0132 case NFT_RT_TCPMSS:
0133 len = sizeof(u16);
0134 break;
0135 #ifdef CONFIG_XFRM
0136 case NFT_RT_XFRM:
0137 len = sizeof(u8);
0138 break;
0139 #endif
0140 default:
0141 return -EOPNOTSUPP;
0142 }
0143
0144 return nft_parse_register_store(ctx, tb[NFTA_RT_DREG], &priv->dreg,
0145 NULL, NFT_DATA_VALUE, len);
0146 }
0147
0148 static int nft_rt_get_dump(struct sk_buff *skb,
0149 const struct nft_expr *expr)
0150 {
0151 const struct nft_rt *priv = nft_expr_priv(expr);
0152
0153 if (nla_put_be32(skb, NFTA_RT_KEY, htonl(priv->key)))
0154 goto nla_put_failure;
0155 if (nft_dump_register(skb, NFTA_RT_DREG, priv->dreg))
0156 goto nla_put_failure;
0157 return 0;
0158
0159 nla_put_failure:
0160 return -1;
0161 }
0162
0163 static int nft_rt_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
0164 const struct nft_data **data)
0165 {
0166 const struct nft_rt *priv = nft_expr_priv(expr);
0167 unsigned int hooks;
0168
0169 switch (priv->key) {
0170 case NFT_RT_NEXTHOP4:
0171 case NFT_RT_NEXTHOP6:
0172 case NFT_RT_CLASSID:
0173 case NFT_RT_XFRM:
0174 return 0;
0175 case NFT_RT_TCPMSS:
0176 hooks = (1 << NF_INET_FORWARD) |
0177 (1 << NF_INET_LOCAL_OUT) |
0178 (1 << NF_INET_POST_ROUTING);
0179 break;
0180 default:
0181 return -EINVAL;
0182 }
0183
0184 return nft_chain_validate_hooks(ctx->chain, hooks);
0185 }
0186
0187 static const struct nft_expr_ops nft_rt_get_ops = {
0188 .type = &nft_rt_type,
0189 .size = NFT_EXPR_SIZE(sizeof(struct nft_rt)),
0190 .eval = nft_rt_get_eval,
0191 .init = nft_rt_get_init,
0192 .dump = nft_rt_get_dump,
0193 .validate = nft_rt_validate,
0194 .reduce = NFT_REDUCE_READONLY,
0195 };
0196
0197 struct nft_expr_type nft_rt_type __read_mostly = {
0198 .name = "rt",
0199 .ops = &nft_rt_get_ops,
0200 .policy = nft_rt_policy,
0201 .maxattr = NFTA_RT_MAX,
0202 .owner = THIS_MODULE,
0203 };