root/net/netfilter/nft_chain_route.c

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

DEFINITIONS

This source file includes following definitions.
  1. nf_route_table_hook4
  2. nf_route_table_hook6
  3. nf_route_table_inet
  4. nft_chain_route_init
  5. nft_chain_route_fini

   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
  16 static 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, skb);
  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, skb, RTN_UNSPEC);
  46                         if (err < 0)
  47                                 ret = NF_DROP_ERR(err);
  48                 }
  49         }
  50         return ret;
  51 }
  52 
  53 static 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
  65 static 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, skb);
  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, skb);
  96                 if (err < 0)
  97                         ret = NF_DROP_ERR(err);
  98         }
  99 
 100         return ret;
 101 }
 102 
 103 static 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
 115 static 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 
 134 static 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 
 145 void __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 
 158 void __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 }

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