~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/bridge/netfilter/nf_tables_bridge.c

Version: ~ [ linux-5.6-rc7 ] ~ [ linux-5.5.11 ] ~ [ linux-5.4.27 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.112 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.174 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.217 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.217 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.82 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
  3  * Copyright (c) 2013 Pablo Neira Ayuso <pablo@netfilter.org>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License version 2 as
  7  * published by the Free Software Foundation.
  8  *
  9  * Development of this code funded by Astaro AG (http://www.astaro.com/)
 10  */
 11 
 12 #include <linux/init.h>
 13 #include <linux/module.h>
 14 #include <linux/netfilter_bridge.h>
 15 #include <net/netfilter/nf_tables.h>
 16 #include <net/netfilter/nf_tables_bridge.h>
 17 #include <linux/ip.h>
 18 #include <linux/ipv6.h>
 19 #include <net/netfilter/nf_tables_ipv4.h>
 20 #include <net/netfilter/nf_tables_ipv6.h>
 21 
 22 int nft_bridge_iphdr_validate(struct sk_buff *skb)
 23 {
 24         struct iphdr *iph;
 25         u32 len;
 26 
 27         if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 28                 return 0;
 29 
 30         iph = ip_hdr(skb);
 31         if (iph->ihl < 5 || iph->version != 4)
 32                 return 0;
 33 
 34         len = ntohs(iph->tot_len);
 35         if (skb->len < len)
 36                 return 0;
 37         else if (len < (iph->ihl*4))
 38                 return 0;
 39 
 40         if (!pskb_may_pull(skb, iph->ihl*4))
 41                 return 0;
 42 
 43         return 1;
 44 }
 45 EXPORT_SYMBOL_GPL(nft_bridge_iphdr_validate);
 46 
 47 int nft_bridge_ip6hdr_validate(struct sk_buff *skb)
 48 {
 49         struct ipv6hdr *hdr;
 50         u32 pkt_len;
 51 
 52         if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 53                 return 0;
 54 
 55         hdr = ipv6_hdr(skb);
 56         if (hdr->version != 6)
 57                 return 0;
 58 
 59         pkt_len = ntohs(hdr->payload_len);
 60         if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
 61                 return 0;
 62 
 63         return 1;
 64 }
 65 EXPORT_SYMBOL_GPL(nft_bridge_ip6hdr_validate);
 66 
 67 static inline void nft_bridge_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
 68                                                struct sk_buff *skb,
 69                                                const struct nf_hook_state *state)
 70 {
 71         if (nft_bridge_iphdr_validate(skb))
 72                 nft_set_pktinfo_ipv4(pkt, skb, state);
 73         else
 74                 nft_set_pktinfo(pkt, skb, state);
 75 }
 76 
 77 static inline void nft_bridge_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
 78                                                struct sk_buff *skb,
 79                                                const struct nf_hook_state *state)
 80 {
 81 #if IS_ENABLED(CONFIG_IPV6)
 82         if (nft_bridge_ip6hdr_validate(skb) &&
 83             nft_set_pktinfo_ipv6(pkt, skb, state) == 0)
 84                 return;
 85 #endif
 86         nft_set_pktinfo(pkt, skb, state);
 87 }
 88 
 89 static unsigned int
 90 nft_do_chain_bridge(void *priv,
 91                     struct sk_buff *skb,
 92                     const struct nf_hook_state *state)
 93 {
 94         struct nft_pktinfo pkt;
 95 
 96         switch (eth_hdr(skb)->h_proto) {
 97         case htons(ETH_P_IP):
 98                 nft_bridge_set_pktinfo_ipv4(&pkt, skb, state);
 99                 break;
100         case htons(ETH_P_IPV6):
101                 nft_bridge_set_pktinfo_ipv6(&pkt, skb, state);
102                 break;
103         default:
104                 nft_set_pktinfo(&pkt, skb, state);
105                 break;
106         }
107 
108         return nft_do_chain(&pkt, priv);
109 }
110 
111 static struct nft_af_info nft_af_bridge __read_mostly = {
112         .family         = NFPROTO_BRIDGE,
113         .nhooks         = NF_BR_NUMHOOKS,
114         .owner          = THIS_MODULE,
115         .nops           = 1,
116         .hooks          = {
117                 [NF_BR_PRE_ROUTING]     = nft_do_chain_bridge,
118                 [NF_BR_LOCAL_IN]        = nft_do_chain_bridge,
119                 [NF_BR_FORWARD]         = nft_do_chain_bridge,
120                 [NF_BR_LOCAL_OUT]       = nft_do_chain_bridge,
121                 [NF_BR_POST_ROUTING]    = nft_do_chain_bridge,
122         },
123 };
124 
125 static int nf_tables_bridge_init_net(struct net *net)
126 {
127         net->nft.bridge = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
128         if (net->nft.bridge == NULL)
129                 return -ENOMEM;
130 
131         memcpy(net->nft.bridge, &nft_af_bridge, sizeof(nft_af_bridge));
132 
133         if (nft_register_afinfo(net, net->nft.bridge) < 0)
134                 goto err;
135 
136         return 0;
137 err:
138         kfree(net->nft.bridge);
139         return -ENOMEM;
140 }
141 
142 static void nf_tables_bridge_exit_net(struct net *net)
143 {
144         nft_unregister_afinfo(net, net->nft.bridge);
145         kfree(net->nft.bridge);
146 }
147 
148 static struct pernet_operations nf_tables_bridge_net_ops = {
149         .init   = nf_tables_bridge_init_net,
150         .exit   = nf_tables_bridge_exit_net,
151 };
152 
153 static const struct nf_chain_type filter_bridge = {
154         .name           = "filter",
155         .type           = NFT_CHAIN_T_DEFAULT,
156         .family         = NFPROTO_BRIDGE,
157         .owner          = THIS_MODULE,
158         .hook_mask      = (1 << NF_BR_PRE_ROUTING) |
159                           (1 << NF_BR_LOCAL_IN) |
160                           (1 << NF_BR_FORWARD) |
161                           (1 << NF_BR_LOCAL_OUT) |
162                           (1 << NF_BR_POST_ROUTING),
163 };
164 
165 static int __init nf_tables_bridge_init(void)
166 {
167         int ret;
168 
169         nft_register_chain_type(&filter_bridge);
170         ret = register_pernet_subsys(&nf_tables_bridge_net_ops);
171         if (ret < 0)
172                 nft_unregister_chain_type(&filter_bridge);
173 
174         return ret;
175 }
176 
177 static void __exit nf_tables_bridge_exit(void)
178 {
179         unregister_pernet_subsys(&nf_tables_bridge_net_ops);
180         nft_unregister_chain_type(&filter_bridge);
181 }
182 
183 module_init(nf_tables_bridge_init);
184 module_exit(nf_tables_bridge_exit);
185 
186 MODULE_LICENSE("GPL");
187 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
188 MODULE_ALIAS_NFT_FAMILY(AF_BRIDGE);
189 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp