cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nft_chain_route.c (4065B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3#include <linux/skbuff.h>
      4#include <linux/netfilter.h>
      5#include <linux/netfilter_ipv4.h>
      6#include <linux/netfilter_ipv6.h>
      7#include <linux/netfilter/nfnetlink.h>
      8#include <linux/netfilter/nf_tables.h>
      9#include <net/netfilter/nf_tables.h>
     10#include <net/netfilter/nf_tables_ipv4.h>
     11#include <net/netfilter/nf_tables_ipv6.h>
     12#include <net/route.h>
     13#include <net/ip.h>
     14
     15#ifdef CONFIG_NF_TABLES_IPV4
     16static unsigned int nf_route_table_hook4(void *priv,
     17					 struct sk_buff *skb,
     18					 const struct nf_hook_state *state)
     19{
     20	const struct iphdr *iph;
     21	struct nft_pktinfo pkt;
     22	__be32 saddr, daddr;
     23	unsigned int ret;
     24	u32 mark;
     25	int err;
     26	u8 tos;
     27
     28	nft_set_pktinfo(&pkt, skb, state);
     29	nft_set_pktinfo_ipv4(&pkt);
     30
     31	mark = skb->mark;
     32	iph = ip_hdr(skb);
     33	saddr = iph->saddr;
     34	daddr = iph->daddr;
     35	tos = iph->tos;
     36
     37	ret = nft_do_chain(&pkt, priv);
     38	if (ret == NF_ACCEPT) {
     39		iph = ip_hdr(skb);
     40
     41		if (iph->saddr != saddr ||
     42		    iph->daddr != daddr ||
     43		    skb->mark != mark ||
     44		    iph->tos != tos) {
     45			err = ip_route_me_harder(state->net, state->sk, skb, RTN_UNSPEC);
     46			if (err < 0)
     47				ret = NF_DROP_ERR(err);
     48		}
     49	}
     50	return ret;
     51}
     52
     53static const struct nft_chain_type nft_chain_route_ipv4 = {
     54	.name		= "route",
     55	.type		= NFT_CHAIN_T_ROUTE,
     56	.family		= NFPROTO_IPV4,
     57	.hook_mask	= (1 << NF_INET_LOCAL_OUT),
     58	.hooks		= {
     59		[NF_INET_LOCAL_OUT]	= nf_route_table_hook4,
     60	},
     61};
     62#endif
     63
     64#ifdef CONFIG_NF_TABLES_IPV6
     65static unsigned int nf_route_table_hook6(void *priv,
     66					 struct sk_buff *skb,
     67					 const struct nf_hook_state *state)
     68{
     69	struct in6_addr saddr, daddr;
     70	struct nft_pktinfo pkt;
     71	u32 mark, flowlabel;
     72	unsigned int ret;
     73	u8 hop_limit;
     74	int err;
     75
     76	nft_set_pktinfo(&pkt, skb, state);
     77	nft_set_pktinfo_ipv6(&pkt);
     78
     79	/* save source/dest address, mark, hoplimit, flowlabel, priority */
     80	memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
     81	memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr));
     82	mark = skb->mark;
     83	hop_limit = ipv6_hdr(skb)->hop_limit;
     84
     85	/* flowlabel and prio (includes version, which shouldn't change either)*/
     86	flowlabel = *((u32 *)ipv6_hdr(skb));
     87
     88	ret = nft_do_chain(&pkt, priv);
     89	if (ret == NF_ACCEPT &&
     90	    (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
     91	     memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
     92	     skb->mark != mark ||
     93	     ipv6_hdr(skb)->hop_limit != hop_limit ||
     94	     flowlabel != *((u32 *)ipv6_hdr(skb)))) {
     95		err = nf_ip6_route_me_harder(state->net, state->sk, skb);
     96		if (err < 0)
     97			ret = NF_DROP_ERR(err);
     98	}
     99
    100	return ret;
    101}
    102
    103static const struct nft_chain_type nft_chain_route_ipv6 = {
    104	.name		= "route",
    105	.type		= NFT_CHAIN_T_ROUTE,
    106	.family		= NFPROTO_IPV6,
    107	.hook_mask	= (1 << NF_INET_LOCAL_OUT),
    108	.hooks		= {
    109		[NF_INET_LOCAL_OUT]	= nf_route_table_hook6,
    110	},
    111};
    112#endif
    113
    114#ifdef CONFIG_NF_TABLES_INET
    115static unsigned int nf_route_table_inet(void *priv,
    116					struct sk_buff *skb,
    117					const struct nf_hook_state *state)
    118{
    119	struct nft_pktinfo pkt;
    120
    121	switch (state->pf) {
    122	case NFPROTO_IPV4:
    123		return nf_route_table_hook4(priv, skb, state);
    124	case NFPROTO_IPV6:
    125		return nf_route_table_hook6(priv, skb, state);
    126	default:
    127		nft_set_pktinfo(&pkt, skb, state);
    128		break;
    129	}
    130
    131	return nft_do_chain(&pkt, priv);
    132}
    133
    134static const struct nft_chain_type nft_chain_route_inet = {
    135	.name		= "route",
    136	.type		= NFT_CHAIN_T_ROUTE,
    137	.family		= NFPROTO_INET,
    138	.hook_mask	= (1 << NF_INET_LOCAL_OUT),
    139	.hooks		= {
    140		[NF_INET_LOCAL_OUT]	= nf_route_table_inet,
    141	},
    142};
    143#endif
    144
    145void __init nft_chain_route_init(void)
    146{
    147#ifdef CONFIG_NF_TABLES_IPV6
    148	nft_register_chain_type(&nft_chain_route_ipv6);
    149#endif
    150#ifdef CONFIG_NF_TABLES_IPV4
    151	nft_register_chain_type(&nft_chain_route_ipv4);
    152#endif
    153#ifdef CONFIG_NF_TABLES_INET
    154	nft_register_chain_type(&nft_chain_route_inet);
    155#endif
    156}
    157
    158void __exit nft_chain_route_fini(void)
    159{
    160#ifdef CONFIG_NF_TABLES_IPV6
    161	nft_unregister_chain_type(&nft_chain_route_ipv6);
    162#endif
    163#ifdef CONFIG_NF_TABLES_IPV4
    164	nft_unregister_chain_type(&nft_chain_route_ipv4);
    165#endif
    166#ifdef CONFIG_NF_TABLES_INET
    167	nft_unregister_chain_type(&nft_chain_route_inet);
    168#endif
    169}