File Index
Files and directories
Sign in
FILE

nft_chain_route.c

File preview with syntax highlighting.

linux-6.19.14/net/netfilter/nft_chain_route.c C
  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}
~/ Read-only file preview.