1 #include <linux/init.h> 2 #include <linux/kernel.h> 3 #include <linux/netdevice.h> 4 #include <net/net_namespace.h> 5 #include <net/netfilter/nf_tables.h> 6 #include <linux/netfilter_ipv4.h> 7 #include <linux/netfilter_ipv6.h> 8 #include <linux/netfilter_bridge.h> 9 #include <linux/netfilter_arp.h> 10 #include <net/netfilter/nf_tables_ipv4.h> 11 #include <net/netfilter/nf_tables_ipv6.h> 12 13 #ifdef CONFIG_NF_TABLES_IPV4 14 static unsigned int nft_do_chain_ipv4(void *priv, 15 struct sk_buff *skb, 16 const struct nf_hook_state *state) 17 { 18 struct nft_pktinfo pkt; 19 20 nft_set_pktinfo(&pkt, skb, state); 21 nft_set_pktinfo_ipv4(&pkt, skb); 22 23 return nft_do_chain(&pkt, priv); 24 } 25 26 static const struct nft_chain_type nft_chain_filter_ipv4 = { 27 .name = "filter", 28 .type = NFT_CHAIN_T_DEFAULT, 29 .family = NFPROTO_IPV4, 30 .hook_mask = (1 << NF_INET_LOCAL_IN) | 31 (1 << NF_INET_LOCAL_OUT) | 32 (1 << NF_INET_FORWARD) | 33 (1 << NF_INET_PRE_ROUTING) | 34 (1 << NF_INET_POST_ROUTING), 35 .hooks = { 36 [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, 37 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv4, 38 [NF_INET_FORWARD] = nft_do_chain_ipv4, 39 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4, 40 [NF_INET_POST_ROUTING] = nft_do_chain_ipv4, 41 }, 42 }; 43 44 static void nft_chain_filter_ipv4_init(void) 45 { 46 nft_register_chain_type(&nft_chain_filter_ipv4); 47 } 48 static void nft_chain_filter_ipv4_fini(void) 49 { 50 nft_unregister_chain_type(&nft_chain_filter_ipv4); 51 } 52 53 #else 54 static inline void nft_chain_filter_ipv4_init(void) {} 55 static inline void nft_chain_filter_ipv4_fini(void) {} 56 #endif /* CONFIG_NF_TABLES_IPV4 */ 57 58 #ifdef CONFIG_NF_TABLES_ARP 59 static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb, 60 const struct nf_hook_state *state) 61 { 62 struct nft_pktinfo pkt; 63 64 nft_set_pktinfo(&pkt, skb, state); 65 nft_set_pktinfo_unspec(&pkt, skb); 66 67 return nft_do_chain(&pkt, priv); 68 } 69 70 static const struct nft_chain_type nft_chain_filter_arp = { 71 .name = "filter", 72 .type = NFT_CHAIN_T_DEFAULT, 73 .family = NFPROTO_ARP, 74 .owner = THIS_MODULE, 75 .hook_mask = (1 << NF_ARP_IN) | 76 (1 << NF_ARP_OUT), 77 .hooks = { 78 [NF_ARP_IN] = nft_do_chain_arp, 79 [NF_ARP_OUT] = nft_do_chain_arp, 80 }, 81 }; 82 83 static void nft_chain_filter_arp_init(void) 84 { 85 nft_register_chain_type(&nft_chain_filter_arp); 86 } 87 88 static void nft_chain_filter_arp_fini(void) 89 { 90 nft_unregister_chain_type(&nft_chain_filter_arp); 91 } 92 #else 93 static inline void nft_chain_filter_arp_init(void) {} 94 static inline void nft_chain_filter_arp_fini(void) {} 95 #endif /* CONFIG_NF_TABLES_ARP */ 96 97 #ifdef CONFIG_NF_TABLES_IPV6 98 static unsigned int nft_do_chain_ipv6(void *priv, 99 struct sk_buff *skb, 100 const struct nf_hook_state *state) 101 { 102 struct nft_pktinfo pkt; 103 104 nft_set_pktinfo(&pkt, skb, state); 105 nft_set_pktinfo_ipv6(&pkt, skb); 106 107 return nft_do_chain(&pkt, priv); 108 } 109 110 static const struct nft_chain_type nft_chain_filter_ipv6 = { 111 .name = "filter", 112 .type = NFT_CHAIN_T_DEFAULT, 113 .family = NFPROTO_IPV6, 114 .hook_mask = (1 << NF_INET_LOCAL_IN) | 115 (1 << NF_INET_LOCAL_OUT) | 116 (1 << NF_INET_FORWARD) | 117 (1 << NF_INET_PRE_ROUTING) | 118 (1 << NF_INET_POST_ROUTING), 119 .hooks = { 120 [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, 121 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv6, 122 [NF_INET_FORWARD] = nft_do_chain_ipv6, 123 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, 124 [NF_INET_POST_ROUTING] = nft_do_chain_ipv6, 125 }, 126 }; 127 128 static void nft_chain_filter_ipv6_init(void) 129 { 130 nft_register_chain_type(&nft_chain_filter_ipv6); 131 } 132 133 static void nft_chain_filter_ipv6_fini(void) 134 { 135 nft_unregister_chain_type(&nft_chain_filter_ipv6); 136 } 137 #else 138 static inline void nft_chain_filter_ipv6_init(void) {} 139 static inline void nft_chain_filter_ipv6_fini(void) {} 140 #endif /* CONFIG_NF_TABLES_IPV6 */ 141 142 #ifdef CONFIG_NF_TABLES_INET 143 static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb, 144 const struct nf_hook_state *state) 145 { 146 struct nft_pktinfo pkt; 147 148 nft_set_pktinfo(&pkt, skb, state); 149 150 switch (state->pf) { 151 case NFPROTO_IPV4: 152 nft_set_pktinfo_ipv4(&pkt, skb); 153 break; 154 case NFPROTO_IPV6: 155 nft_set_pktinfo_ipv6(&pkt, skb); 156 break; 157 default: 158 break; 159 } 160 161 return nft_do_chain(&pkt, priv); 162 } 163 164 static const struct nft_chain_type nft_chain_filter_inet = { 165 .name = "filter", 166 .type = NFT_CHAIN_T_DEFAULT, 167 .family = NFPROTO_INET, 168 .hook_mask = (1 << NF_INET_LOCAL_IN) | 169 (1 << NF_INET_LOCAL_OUT) | 170 (1 << NF_INET_FORWARD) | 171 (1 << NF_INET_PRE_ROUTING) | 172 (1 << NF_INET_POST_ROUTING), 173 .hooks = { 174 [NF_INET_LOCAL_IN] = nft_do_chain_inet, 175 [NF_INET_LOCAL_OUT] = nft_do_chain_inet, 176 [NF_INET_FORWARD] = nft_do_chain_inet, 177 [NF_INET_PRE_ROUTING] = nft_do_chain_inet, 178 [NF_INET_POST_ROUTING] = nft_do_chain_inet, 179 }, 180 }; 181 182 static void nft_chain_filter_inet_init(void) 183 { 184 nft_register_chain_type(&nft_chain_filter_inet); 185 } 186 187 static void nft_chain_filter_inet_fini(void) 188 { 189 nft_unregister_chain_type(&nft_chain_filter_inet); 190 } 191 #else 192 static inline void nft_chain_filter_inet_init(void) {} 193 static inline void nft_chain_filter_inet_fini(void) {} 194 #endif /* CONFIG_NF_TABLES_IPV6 */ 195 196 #ifdef CONFIG_NF_TABLES_BRIDGE 197 static unsigned int 198 nft_do_chain_bridge(void *priv, 199 struct sk_buff *skb, 200 const struct nf_hook_state *state) 201 { 202 struct nft_pktinfo pkt; 203 204 nft_set_pktinfo(&pkt, skb, state); 205 206 switch (eth_hdr(skb)->h_proto) { 207 case htons(ETH_P_IP): 208 nft_set_pktinfo_ipv4_validate(&pkt, skb); 209 break; 210 case htons(ETH_P_IPV6): 211 nft_set_pktinfo_ipv6_validate(&pkt, skb); 212 break; 213 default: 214 nft_set_pktinfo_unspec(&pkt, skb); 215 break; 216 } 217 218 return nft_do_chain(&pkt, priv); 219 } 220 221 static const struct nft_chain_type nft_chain_filter_bridge = { 222 .name = "filter", 223 .type = NFT_CHAIN_T_DEFAULT, 224 .family = NFPROTO_BRIDGE, 225 .hook_mask = (1 << NF_BR_PRE_ROUTING) | 226 (1 << NF_BR_LOCAL_IN) | 227 (1 << NF_BR_FORWARD) | 228 (1 << NF_BR_LOCAL_OUT) | 229 (1 << NF_BR_POST_ROUTING), 230 .hooks = { 231 [NF_BR_PRE_ROUTING] = nft_do_chain_bridge, 232 [NF_BR_LOCAL_IN] = nft_do_chain_bridge, 233 [NF_BR_FORWARD] = nft_do_chain_bridge, 234 [NF_BR_LOCAL_OUT] = nft_do_chain_bridge, 235 [NF_BR_POST_ROUTING] = nft_do_chain_bridge, 236 }, 237 }; 238 239 static void nft_chain_filter_bridge_init(void) 240 { 241 nft_register_chain_type(&nft_chain_filter_bridge); 242 } 243 244 static void nft_chain_filter_bridge_fini(void) 245 { 246 nft_unregister_chain_type(&nft_chain_filter_bridge); 247 } 248 #else 249 static inline void nft_chain_filter_bridge_init(void) {} 250 static inline void nft_chain_filter_bridge_fini(void) {} 251 #endif /* CONFIG_NF_TABLES_BRIDGE */ 252 253 #ifdef CONFIG_NF_TABLES_NETDEV 254 static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb, 255 const struct nf_hook_state *state) 256 { 257 struct nft_pktinfo pkt; 258 259 nft_set_pktinfo(&pkt, skb, state); 260 261 switch (skb->protocol) { 262 case htons(ETH_P_IP): 263 nft_set_pktinfo_ipv4_validate(&pkt, skb); 264 break; 265 case htons(ETH_P_IPV6): 266 nft_set_pktinfo_ipv6_validate(&pkt, skb); 267 break; 268 default: 269 nft_set_pktinfo_unspec(&pkt, skb); 270 break; 271 } 272 273 return nft_do_chain(&pkt, priv); 274 } 275 276 static const struct nft_chain_type nft_chain_filter_netdev = { 277 .name = "filter", 278 .type = NFT_CHAIN_T_DEFAULT, 279 .family = NFPROTO_NETDEV, 280 .hook_mask = (1 << NF_NETDEV_INGRESS), 281 .hooks = { 282 [NF_NETDEV_INGRESS] = nft_do_chain_netdev, 283 }, 284 }; 285 286 static void nft_netdev_event(unsigned long event, struct net_device *dev, 287 struct nft_ctx *ctx) 288 { 289 struct nft_base_chain *basechain = nft_base_chain(ctx->chain); 290 291 switch (event) { 292 case NETDEV_UNREGISTER: 293 if (strcmp(basechain->dev_name, dev->name) != 0) 294 return; 295 296 __nft_release_basechain(ctx); 297 break; 298 case NETDEV_CHANGENAME: 299 if (dev->ifindex != basechain->ops.dev->ifindex) 300 return; 301 302 strncpy(basechain->dev_name, dev->name, IFNAMSIZ); 303 break; 304 } 305 } 306 307 static int nf_tables_netdev_event(struct notifier_block *this, 308 unsigned long event, void *ptr) 309 { 310 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 311 struct nft_table *table; 312 struct nft_chain *chain, *nr; 313 struct nft_ctx ctx = { 314 .net = dev_net(dev), 315 }; 316 317 if (event != NETDEV_UNREGISTER && 318 event != NETDEV_CHANGENAME) 319 return NOTIFY_DONE; 320 321 ctx.net = maybe_get_net(ctx.net); 322 if (!ctx.net) 323 return NOTIFY_DONE; 324 325 nfnl_lock(NFNL_SUBSYS_NFTABLES); 326 list_for_each_entry(table, &ctx.net->nft.tables, list) { 327 if (table->family != NFPROTO_NETDEV) 328 continue; 329 330 ctx.family = table->family; 331 ctx.table = table; 332 list_for_each_entry_safe(chain, nr, &table->chains, list) { 333 if (!nft_is_base_chain(chain)) 334 continue; 335 336 ctx.chain = chain; 337 nft_netdev_event(event, dev, &ctx); 338 } 339 } 340 nfnl_unlock(NFNL_SUBSYS_NFTABLES); 341 put_net(ctx.net); 342 343 return NOTIFY_DONE; 344 } 345 346 static struct notifier_block nf_tables_netdev_notifier = { 347 .notifier_call = nf_tables_netdev_event, 348 }; 349 350 static int nft_chain_filter_netdev_init(void) 351 { 352 int err; 353 354 nft_register_chain_type(&nft_chain_filter_netdev); 355 356 err = register_netdevice_notifier(&nf_tables_netdev_notifier); 357 if (err) 358 goto err_register_netdevice_notifier; 359 360 return 0; 361 362 err_register_netdevice_notifier: 363 nft_unregister_chain_type(&nft_chain_filter_netdev); 364 365 return err; 366 } 367 368 static void nft_chain_filter_netdev_fini(void) 369 { 370 nft_unregister_chain_type(&nft_chain_filter_netdev); 371 unregister_netdevice_notifier(&nf_tables_netdev_notifier); 372 } 373 #else 374 static inline int nft_chain_filter_netdev_init(void) { return 0; } 375 static inline void nft_chain_filter_netdev_fini(void) {} 376 #endif /* CONFIG_NF_TABLES_NETDEV */ 377 378 int __init nft_chain_filter_init(void) 379 { 380 int err; 381 382 err = nft_chain_filter_netdev_init(); 383 if (err < 0) 384 return err; 385 386 nft_chain_filter_ipv4_init(); 387 nft_chain_filter_ipv6_init(); 388 nft_chain_filter_arp_init(); 389 nft_chain_filter_inet_init(); 390 nft_chain_filter_bridge_init(); 391 392 return 0; 393 } 394 395 void __exit nft_chain_filter_fini(void) 396 { 397 nft_chain_filter_bridge_fini(); 398 nft_chain_filter_inet_fini(); 399 nft_chain_filter_arp_fini(); 400 nft_chain_filter_ipv6_fini(); 401 nft_chain_filter_ipv4_fini(); 402 nft_chain_filter_netdev_fini(); 403 } 404