1 /* 2 * Copyright (c) 2014 Pablo Neira Ayuso <pablo@netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/init.h> 11 #include <linux/module.h> 12 #include <linux/netlink.h> 13 #include <linux/netfilter.h> 14 #include <linux/netfilter/nf_tables.h> 15 #include <net/netfilter/nf_tables.h> 16 #include <net/netfilter/nft_reject.h> 17 #include <net/netfilter/ipv4/nf_reject.h> 18 #include <net/netfilter/ipv6/nf_reject.h> 19 #include <linux/ip.h> 20 #include <net/ip.h> 21 #include <net/ip6_checksum.h> 22 #include <linux/netfilter_bridge.h> 23 #include <linux/netfilter_ipv6.h> 24 #include "../br_private.h" 25 26 static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb, 27 struct sk_buff *nskb) 28 { 29 struct ethhdr *eth; 30 31 eth = skb_push(nskb, ETH_HLEN); 32 skb_reset_mac_header(nskb); 33 ether_addr_copy(eth->h_source, eth_hdr(oldskb)->h_dest); 34 ether_addr_copy(eth->h_dest, eth_hdr(oldskb)->h_source); 35 eth->h_proto = eth_hdr(oldskb)->h_proto; 36 skb_pull(nskb, ETH_HLEN); 37 } 38 39 static int nft_bridge_iphdr_validate(struct sk_buff *skb) 40 { 41 struct iphdr *iph; 42 u32 len; 43 44 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 45 return 0; 46 47 iph = ip_hdr(skb); 48 if (iph->ihl < 5 || iph->version != 4) 49 return 0; 50 51 len = ntohs(iph->tot_len); 52 if (skb->len < len) 53 return 0; 54 else if (len < (iph->ihl*4)) 55 return 0; 56 57 if (!pskb_may_pull(skb, iph->ihl*4)) 58 return 0; 59 60 return 1; 61 } 62 63 /* We cannot use oldskb->dev, it can be either bridge device (NF_BRIDGE INPUT) 64 * or the bridge port (NF_BRIDGE PREROUTING). 65 */ 66 static void nft_reject_br_send_v4_tcp_reset(struct net *net, 67 struct sk_buff *oldskb, 68 const struct net_device *dev, 69 int hook) 70 { 71 struct sk_buff *nskb; 72 struct iphdr *niph; 73 const struct tcphdr *oth; 74 struct tcphdr _oth; 75 76 if (!nft_bridge_iphdr_validate(oldskb)) 77 return; 78 79 oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook); 80 if (!oth) 81 return; 82 83 nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + 84 LL_MAX_HEADER, GFP_ATOMIC); 85 if (!nskb) 86 return; 87 88 skb_reserve(nskb, LL_MAX_HEADER); 89 niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP, 90 net->ipv4.sysctl_ip_default_ttl); 91 nf_reject_ip_tcphdr_put(nskb, oldskb, oth); 92 niph->ttl = net->ipv4.sysctl_ip_default_ttl; 93 niph->tot_len = htons(nskb->len); 94 ip_send_check(niph); 95 96 nft_reject_br_push_etherhdr(oldskb, nskb); 97 98 br_forward(br_port_get_rcu(dev), nskb, false, true); 99 } 100 101 static void nft_reject_br_send_v4_unreach(struct net *net, 102 struct sk_buff *oldskb, 103 const struct net_device *dev, 104 int hook, u8 code) 105 { 106 struct sk_buff *nskb; 107 struct iphdr *niph; 108 struct icmphdr *icmph; 109 unsigned int len; 110 __wsum csum; 111 u8 proto; 112 113 if (!nft_bridge_iphdr_validate(oldskb)) 114 return; 115 116 /* IP header checks: fragment. */ 117 if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) 118 return; 119 120 /* RFC says return as much as we can without exceeding 576 bytes. */ 121 len = min_t(unsigned int, 536, oldskb->len); 122 123 if (!pskb_may_pull(oldskb, len)) 124 return; 125 126 if (pskb_trim_rcsum(oldskb, ntohs(ip_hdr(oldskb)->tot_len))) 127 return; 128 129 if (ip_hdr(oldskb)->protocol == IPPROTO_TCP || 130 ip_hdr(oldskb)->protocol == IPPROTO_UDP) 131 proto = ip_hdr(oldskb)->protocol; 132 else 133 proto = 0; 134 135 if (!skb_csum_unnecessary(oldskb) && 136 nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), proto)) 137 return; 138 139 nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmphdr) + 140 LL_MAX_HEADER + len, GFP_ATOMIC); 141 if (!nskb) 142 return; 143 144 skb_reserve(nskb, LL_MAX_HEADER); 145 niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP, 146 net->ipv4.sysctl_ip_default_ttl); 147 148 skb_reset_transport_header(nskb); 149 icmph = skb_put_zero(nskb, sizeof(struct icmphdr)); 150 icmph->type = ICMP_DEST_UNREACH; 151 icmph->code = code; 152 153 skb_put_data(nskb, skb_network_header(oldskb), len); 154 155 csum = csum_partial((void *)icmph, len + sizeof(struct icmphdr), 0); 156 icmph->checksum = csum_fold(csum); 157 158 niph->tot_len = htons(nskb->len); 159 ip_send_check(niph); 160 161 nft_reject_br_push_etherhdr(oldskb, nskb); 162 163 br_forward(br_port_get_rcu(dev), nskb, false, true); 164 } 165 166 static int nft_bridge_ip6hdr_validate(struct sk_buff *skb) 167 { 168 struct ipv6hdr *hdr; 169 u32 pkt_len; 170 171 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 172 return 0; 173 174 hdr = ipv6_hdr(skb); 175 if (hdr->version != 6) 176 return 0; 177 178 pkt_len = ntohs(hdr->payload_len); 179 if (pkt_len + sizeof(struct ipv6hdr) > skb->len) 180 return 0; 181 182 return 1; 183 } 184 185 static void nft_reject_br_send_v6_tcp_reset(struct net *net, 186 struct sk_buff *oldskb, 187 const struct net_device *dev, 188 int hook) 189 { 190 struct sk_buff *nskb; 191 const struct tcphdr *oth; 192 struct tcphdr _oth; 193 unsigned int otcplen; 194 struct ipv6hdr *nip6h; 195 196 if (!nft_bridge_ip6hdr_validate(oldskb)) 197 return; 198 199 oth = nf_reject_ip6_tcphdr_get(oldskb, &_oth, &otcplen, hook); 200 if (!oth) 201 return; 202 203 nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 204 LL_MAX_HEADER, GFP_ATOMIC); 205 if (!nskb) 206 return; 207 208 skb_reserve(nskb, LL_MAX_HEADER); 209 nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP, 210 net->ipv6.devconf_all->hop_limit); 211 nf_reject_ip6_tcphdr_put(nskb, oldskb, oth, otcplen); 212 nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr)); 213 214 nft_reject_br_push_etherhdr(oldskb, nskb); 215 216 br_forward(br_port_get_rcu(dev), nskb, false, true); 217 } 218 219 static bool reject6_br_csum_ok(struct sk_buff *skb, int hook) 220 { 221 const struct ipv6hdr *ip6h = ipv6_hdr(skb); 222 int thoff; 223 __be16 fo; 224 u8 proto = ip6h->nexthdr; 225 226 if (skb_csum_unnecessary(skb)) 227 return true; 228 229 if (ip6h->payload_len && 230 pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h))) 231 return false; 232 233 thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); 234 if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) 235 return false; 236 237 return nf_ip6_checksum(skb, hook, thoff, proto) == 0; 238 } 239 240 static void nft_reject_br_send_v6_unreach(struct net *net, 241 struct sk_buff *oldskb, 242 const struct net_device *dev, 243 int hook, u8 code) 244 { 245 struct sk_buff *nskb; 246 struct ipv6hdr *nip6h; 247 struct icmp6hdr *icmp6h; 248 unsigned int len; 249 250 if (!nft_bridge_ip6hdr_validate(oldskb)) 251 return; 252 253 /* Include "As much of invoking packet as possible without the ICMPv6 254 * packet exceeding the minimum IPv6 MTU" in the ICMP payload. 255 */ 256 len = min_t(unsigned int, 1220, oldskb->len); 257 258 if (!pskb_may_pull(oldskb, len)) 259 return; 260 261 if (!reject6_br_csum_ok(oldskb, hook)) 262 return; 263 264 nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) + 265 LL_MAX_HEADER + len, GFP_ATOMIC); 266 if (!nskb) 267 return; 268 269 skb_reserve(nskb, LL_MAX_HEADER); 270 nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_ICMPV6, 271 net->ipv6.devconf_all->hop_limit); 272 273 skb_reset_transport_header(nskb); 274 icmp6h = skb_put_zero(nskb, sizeof(struct icmp6hdr)); 275 icmp6h->icmp6_type = ICMPV6_DEST_UNREACH; 276 icmp6h->icmp6_code = code; 277 278 skb_put_data(nskb, skb_network_header(oldskb), len); 279 nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr)); 280 281 icmp6h->icmp6_cksum = 282 csum_ipv6_magic(&nip6h->saddr, &nip6h->daddr, 283 nskb->len - sizeof(struct ipv6hdr), 284 IPPROTO_ICMPV6, 285 csum_partial(icmp6h, 286 nskb->len - sizeof(struct ipv6hdr), 287 0)); 288 289 nft_reject_br_push_etherhdr(oldskb, nskb); 290 291 br_forward(br_port_get_rcu(dev), nskb, false, true); 292 } 293 294 static void nft_reject_bridge_eval(const struct nft_expr *expr, 295 struct nft_regs *regs, 296 const struct nft_pktinfo *pkt) 297 { 298 struct nft_reject *priv = nft_expr_priv(expr); 299 const unsigned char *dest = eth_hdr(pkt->skb)->h_dest; 300 301 if (is_broadcast_ether_addr(dest) || 302 is_multicast_ether_addr(dest)) 303 goto out; 304 305 switch (eth_hdr(pkt->skb)->h_proto) { 306 case htons(ETH_P_IP): 307 switch (priv->type) { 308 case NFT_REJECT_ICMP_UNREACH: 309 nft_reject_br_send_v4_unreach(nft_net(pkt), pkt->skb, 310 nft_in(pkt), 311 nft_hook(pkt), 312 priv->icmp_code); 313 break; 314 case NFT_REJECT_TCP_RST: 315 nft_reject_br_send_v4_tcp_reset(nft_net(pkt), pkt->skb, 316 nft_in(pkt), 317 nft_hook(pkt)); 318 break; 319 case NFT_REJECT_ICMPX_UNREACH: 320 nft_reject_br_send_v4_unreach(nft_net(pkt), pkt->skb, 321 nft_in(pkt), 322 nft_hook(pkt), 323 nft_reject_icmp_code(priv->icmp_code)); 324 break; 325 } 326 break; 327 case htons(ETH_P_IPV6): 328 switch (priv->type) { 329 case NFT_REJECT_ICMP_UNREACH: 330 nft_reject_br_send_v6_unreach(nft_net(pkt), pkt->skb, 331 nft_in(pkt), 332 nft_hook(pkt), 333 priv->icmp_code); 334 break; 335 case NFT_REJECT_TCP_RST: 336 nft_reject_br_send_v6_tcp_reset(nft_net(pkt), pkt->skb, 337 nft_in(pkt), 338 nft_hook(pkt)); 339 break; 340 case NFT_REJECT_ICMPX_UNREACH: 341 nft_reject_br_send_v6_unreach(nft_net(pkt), pkt->skb, 342 nft_in(pkt), 343 nft_hook(pkt), 344 nft_reject_icmpv6_code(priv->icmp_code)); 345 break; 346 } 347 break; 348 default: 349 /* No explicit way to reject this protocol, drop it. */ 350 break; 351 } 352 out: 353 regs->verdict.code = NF_DROP; 354 } 355 356 static int nft_reject_bridge_validate(const struct nft_ctx *ctx, 357 const struct nft_expr *expr, 358 const struct nft_data **data) 359 { 360 return nft_chain_validate_hooks(ctx->chain, (1 << NF_BR_PRE_ROUTING) | 361 (1 << NF_BR_LOCAL_IN)); 362 } 363 364 static int nft_reject_bridge_init(const struct nft_ctx *ctx, 365 const struct nft_expr *expr, 366 const struct nlattr * const tb[]) 367 { 368 struct nft_reject *priv = nft_expr_priv(expr); 369 int icmp_code; 370 371 if (tb[NFTA_REJECT_TYPE] == NULL) 372 return -EINVAL; 373 374 priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE])); 375 switch (priv->type) { 376 case NFT_REJECT_ICMP_UNREACH: 377 case NFT_REJECT_ICMPX_UNREACH: 378 if (tb[NFTA_REJECT_ICMP_CODE] == NULL) 379 return -EINVAL; 380 381 icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]); 382 if (priv->type == NFT_REJECT_ICMPX_UNREACH && 383 icmp_code > NFT_REJECT_ICMPX_MAX) 384 return -EINVAL; 385 386 priv->icmp_code = icmp_code; 387 break; 388 case NFT_REJECT_TCP_RST: 389 break; 390 default: 391 return -EINVAL; 392 } 393 return 0; 394 } 395 396 static int nft_reject_bridge_dump(struct sk_buff *skb, 397 const struct nft_expr *expr) 398 { 399 const struct nft_reject *priv = nft_expr_priv(expr); 400 401 if (nla_put_be32(skb, NFTA_REJECT_TYPE, htonl(priv->type))) 402 goto nla_put_failure; 403 404 switch (priv->type) { 405 case NFT_REJECT_ICMP_UNREACH: 406 case NFT_REJECT_ICMPX_UNREACH: 407 if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code)) 408 goto nla_put_failure; 409 break; 410 default: 411 break; 412 } 413 414 return 0; 415 416 nla_put_failure: 417 return -1; 418 } 419 420 static struct nft_expr_type nft_reject_bridge_type; 421 static const struct nft_expr_ops nft_reject_bridge_ops = { 422 .type = &nft_reject_bridge_type, 423 .size = NFT_EXPR_SIZE(sizeof(struct nft_reject)), 424 .eval = nft_reject_bridge_eval, 425 .init = nft_reject_bridge_init, 426 .dump = nft_reject_bridge_dump, 427 .validate = nft_reject_bridge_validate, 428 }; 429 430 static struct nft_expr_type nft_reject_bridge_type __read_mostly = { 431 .family = NFPROTO_BRIDGE, 432 .name = "reject", 433 .ops = &nft_reject_bridge_ops, 434 .policy = nft_reject_policy, 435 .maxattr = NFTA_REJECT_MAX, 436 .owner = THIS_MODULE, 437 }; 438 439 static int __init nft_reject_bridge_module_init(void) 440 { 441 return nft_register_expr(&nft_reject_bridge_type); 442 } 443 444 static void __exit nft_reject_bridge_module_exit(void) 445 { 446 nft_unregister_expr(&nft_reject_bridge_type); 447 } 448 449 module_init(nft_reject_bridge_module_init); 450 module_exit(nft_reject_bridge_module_exit); 451 452 MODULE_LICENSE("GPL"); 453 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 454 MODULE_ALIAS_NFT_AF_EXPR(AF_BRIDGE, "reject"); 455
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.