Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_reject: add reject skbuff creation helpers

Adds reject skbuff creation helper functions to ipv4/6 nf_reject
infrastructure. Use these functions for reject verdict in bridge
family.

Can be reused by all different families that support reject and
will not inject the reject packet through ip local out.

Signed-off-by: Jose M. Guisado Gomez <guigom@riseup.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Jose M. Guisado Gomez and committed by
Pablo Neira Ayuso
fa538f7c 37d38ece

+280 -192
+10
include/net/netfilter/ipv4/nf_reject.h
··· 18 18 void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb, 19 19 const struct tcphdr *oth); 20 20 21 + struct sk_buff *nf_reject_skb_v4_unreach(struct net *net, 22 + struct sk_buff *oldskb, 23 + const struct net_device *dev, 24 + int hook, u8 code); 25 + struct sk_buff *nf_reject_skb_v4_tcp_reset(struct net *net, 26 + struct sk_buff *oldskb, 27 + const struct net_device *dev, 28 + int hook); 29 + 30 + 21 31 #endif /* _IPV4_NF_REJECT_H */
+9
include/net/netfilter/ipv6/nf_reject.h
··· 20 20 const struct sk_buff *oldskb, 21 21 const struct tcphdr *oth, unsigned int otcplen); 22 22 23 + struct sk_buff *nf_reject_skb_v6_tcp_reset(struct net *net, 24 + struct sk_buff *oldskb, 25 + const struct net_device *dev, 26 + int hook); 27 + struct sk_buff *nf_reject_skb_v6_unreach(struct net *net, 28 + struct sk_buff *oldskb, 29 + const struct net_device *dev, 30 + int hook, u8 code); 31 + 23 32 #endif /* _IPV6_NF_REJECT_H */
+1 -1
net/bridge/netfilter/Kconfig
··· 17 17 18 18 config NFT_BRIDGE_REJECT 19 19 tristate "Netfilter nf_tables bridge reject support" 20 - depends on NFT_REJECT && NFT_REJECT_IPV4 && NFT_REJECT_IPV6 20 + depends on NFT_REJECT 21 21 help 22 22 Add support to reject packets. 23 23
+4 -191
net/bridge/netfilter/nft_reject_bridge.c
··· 39 39 } 40 40 } 41 41 42 - static int nft_bridge_iphdr_validate(struct sk_buff *skb) 43 - { 44 - struct iphdr *iph; 45 - u32 len; 46 - 47 - if (!pskb_may_pull(skb, sizeof(struct iphdr))) 48 - return 0; 49 - 50 - iph = ip_hdr(skb); 51 - if (iph->ihl < 5 || iph->version != 4) 52 - return 0; 53 - 54 - len = ntohs(iph->tot_len); 55 - if (skb->len < len) 56 - return 0; 57 - else if (len < (iph->ihl*4)) 58 - return 0; 59 - 60 - if (!pskb_may_pull(skb, iph->ihl*4)) 61 - return 0; 62 - 63 - return 1; 64 - } 65 - 66 42 /* We cannot use oldskb->dev, it can be either bridge device (NF_BRIDGE INPUT) 67 43 * or the bridge port (NF_BRIDGE PREROUTING). 68 44 */ ··· 48 72 int hook) 49 73 { 50 74 struct sk_buff *nskb; 51 - struct iphdr *niph; 52 - const struct tcphdr *oth; 53 - struct tcphdr _oth; 54 75 55 - if (!nft_bridge_iphdr_validate(oldskb)) 56 - return; 57 - 58 - oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook); 59 - if (!oth) 60 - return; 61 - 62 - nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + 63 - LL_MAX_HEADER, GFP_ATOMIC); 76 + nskb = nf_reject_skb_v4_tcp_reset(net, oldskb, dev, hook); 64 77 if (!nskb) 65 78 return; 66 - 67 - skb_reserve(nskb, LL_MAX_HEADER); 68 - niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP, 69 - net->ipv4.sysctl_ip_default_ttl); 70 - nf_reject_ip_tcphdr_put(nskb, oldskb, oth); 71 - niph->tot_len = htons(nskb->len); 72 - ip_send_check(niph); 73 79 74 80 nft_reject_br_push_etherhdr(oldskb, nskb); 75 81 ··· 64 106 int hook, u8 code) 65 107 { 66 108 struct sk_buff *nskb; 67 - struct iphdr *niph; 68 - struct icmphdr *icmph; 69 - unsigned int len; 70 - __wsum csum; 71 - u8 proto; 72 109 73 - if (!nft_bridge_iphdr_validate(oldskb)) 74 - return; 75 - 76 - /* IP header checks: fragment. */ 77 - if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) 78 - return; 79 - 80 - /* RFC says return as much as we can without exceeding 576 bytes. */ 81 - len = min_t(unsigned int, 536, oldskb->len); 82 - 83 - if (!pskb_may_pull(oldskb, len)) 84 - return; 85 - 86 - if (pskb_trim_rcsum(oldskb, ntohs(ip_hdr(oldskb)->tot_len))) 87 - return; 88 - 89 - proto = ip_hdr(oldskb)->protocol; 90 - 91 - if (!skb_csum_unnecessary(oldskb) && 92 - nf_reject_verify_csum(proto) && 93 - nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), proto)) 94 - return; 95 - 96 - nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmphdr) + 97 - LL_MAX_HEADER + len, GFP_ATOMIC); 110 + nskb = nf_reject_skb_v4_unreach(net, oldskb, dev, hook, code); 98 111 if (!nskb) 99 112 return; 100 - 101 - skb_reserve(nskb, LL_MAX_HEADER); 102 - niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP, 103 - net->ipv4.sysctl_ip_default_ttl); 104 - 105 - skb_reset_transport_header(nskb); 106 - icmph = skb_put_zero(nskb, sizeof(struct icmphdr)); 107 - icmph->type = ICMP_DEST_UNREACH; 108 - icmph->code = code; 109 - 110 - skb_put_data(nskb, skb_network_header(oldskb), len); 111 - 112 - csum = csum_partial((void *)icmph, len + sizeof(struct icmphdr), 0); 113 - icmph->checksum = csum_fold(csum); 114 - 115 - niph->tot_len = htons(nskb->len); 116 - ip_send_check(niph); 117 113 118 114 nft_reject_br_push_etherhdr(oldskb, nskb); 119 115 120 116 br_forward(br_port_get_rcu(dev), nskb, false, true); 121 - } 122 - 123 - static int nft_bridge_ip6hdr_validate(struct sk_buff *skb) 124 - { 125 - struct ipv6hdr *hdr; 126 - u32 pkt_len; 127 - 128 - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 129 - return 0; 130 - 131 - hdr = ipv6_hdr(skb); 132 - if (hdr->version != 6) 133 - return 0; 134 - 135 - pkt_len = ntohs(hdr->payload_len); 136 - if (pkt_len + sizeof(struct ipv6hdr) > skb->len) 137 - return 0; 138 - 139 - return 1; 140 117 } 141 118 142 119 static void nft_reject_br_send_v6_tcp_reset(struct net *net, ··· 80 187 int hook) 81 188 { 82 189 struct sk_buff *nskb; 83 - const struct tcphdr *oth; 84 - struct tcphdr _oth; 85 - unsigned int otcplen; 86 - struct ipv6hdr *nip6h; 87 190 88 - if (!nft_bridge_ip6hdr_validate(oldskb)) 89 - return; 90 - 91 - oth = nf_reject_ip6_tcphdr_get(oldskb, &_oth, &otcplen, hook); 92 - if (!oth) 93 - return; 94 - 95 - nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 96 - LL_MAX_HEADER, GFP_ATOMIC); 191 + nskb = nf_reject_skb_v6_tcp_reset(net, oldskb, dev, hook); 97 192 if (!nskb) 98 193 return; 99 - 100 - skb_reserve(nskb, LL_MAX_HEADER); 101 - nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP, 102 - net->ipv6.devconf_all->hop_limit); 103 - nf_reject_ip6_tcphdr_put(nskb, oldskb, oth, otcplen); 104 - nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr)); 105 194 106 195 nft_reject_br_push_etherhdr(oldskb, nskb); 107 196 108 197 br_forward(br_port_get_rcu(dev), nskb, false, true); 109 198 } 110 199 111 - static bool reject6_br_csum_ok(struct sk_buff *skb, int hook) 112 - { 113 - const struct ipv6hdr *ip6h = ipv6_hdr(skb); 114 - int thoff; 115 - __be16 fo; 116 - u8 proto = ip6h->nexthdr; 117 - 118 - if (skb_csum_unnecessary(skb)) 119 - return true; 120 - 121 - if (ip6h->payload_len && 122 - pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h))) 123 - return false; 124 - 125 - ip6h = ipv6_hdr(skb); 126 - thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); 127 - if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) 128 - return false; 129 - 130 - if (!nf_reject_verify_csum(proto)) 131 - return true; 132 - 133 - return nf_ip6_checksum(skb, hook, thoff, proto) == 0; 134 - } 135 200 136 201 static void nft_reject_br_send_v6_unreach(struct net *net, 137 202 struct sk_buff *oldskb, ··· 97 246 int hook, u8 code) 98 247 { 99 248 struct sk_buff *nskb; 100 - struct ipv6hdr *nip6h; 101 - struct icmp6hdr *icmp6h; 102 - unsigned int len; 103 249 104 - if (!nft_bridge_ip6hdr_validate(oldskb)) 105 - return; 106 - 107 - /* Include "As much of invoking packet as possible without the ICMPv6 108 - * packet exceeding the minimum IPv6 MTU" in the ICMP payload. 109 - */ 110 - len = min_t(unsigned int, 1220, oldskb->len); 111 - 112 - if (!pskb_may_pull(oldskb, len)) 113 - return; 114 - 115 - if (!reject6_br_csum_ok(oldskb, hook)) 116 - return; 117 - 118 - nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) + 119 - LL_MAX_HEADER + len, GFP_ATOMIC); 250 + nskb = nf_reject_skb_v6_unreach(net, oldskb, dev, hook, code); 120 251 if (!nskb) 121 252 return; 122 - 123 - skb_reserve(nskb, LL_MAX_HEADER); 124 - nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_ICMPV6, 125 - net->ipv6.devconf_all->hop_limit); 126 - 127 - skb_reset_transport_header(nskb); 128 - icmp6h = skb_put_zero(nskb, sizeof(struct icmp6hdr)); 129 - icmp6h->icmp6_type = ICMPV6_DEST_UNREACH; 130 - icmp6h->icmp6_code = code; 131 - 132 - skb_put_data(nskb, skb_network_header(oldskb), len); 133 - nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr)); 134 - 135 - icmp6h->icmp6_cksum = 136 - csum_ipv6_magic(&nip6h->saddr, &nip6h->daddr, 137 - nskb->len - sizeof(struct ipv6hdr), 138 - IPPROTO_ICMPV6, 139 - csum_partial(icmp6h, 140 - nskb->len - sizeof(struct ipv6hdr), 141 - 0)); 142 253 143 254 nft_reject_br_push_etherhdr(oldskb, nskb); 144 255
+122
net/ipv4/netfilter/nf_reject_ipv4.c
··· 12 12 #include <linux/netfilter_ipv4.h> 13 13 #include <linux/netfilter_bridge.h> 14 14 15 + static int nf_reject_iphdr_validate(struct sk_buff *skb) 16 + { 17 + struct iphdr *iph; 18 + u32 len; 19 + 20 + if (!pskb_may_pull(skb, sizeof(struct iphdr))) 21 + return 0; 22 + 23 + iph = ip_hdr(skb); 24 + if (iph->ihl < 5 || iph->version != 4) 25 + return 0; 26 + 27 + len = ntohs(iph->tot_len); 28 + if (skb->len < len) 29 + return 0; 30 + else if (len < (iph->ihl*4)) 31 + return 0; 32 + 33 + if (!pskb_may_pull(skb, iph->ihl*4)) 34 + return 0; 35 + 36 + return 1; 37 + } 38 + 39 + struct sk_buff *nf_reject_skb_v4_tcp_reset(struct net *net, 40 + struct sk_buff *oldskb, 41 + const struct net_device *dev, 42 + int hook) 43 + { 44 + const struct tcphdr *oth; 45 + struct sk_buff *nskb; 46 + struct iphdr *niph; 47 + struct tcphdr _oth; 48 + 49 + if (!nf_reject_iphdr_validate(oldskb)) 50 + return NULL; 51 + 52 + oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook); 53 + if (!oth) 54 + return NULL; 55 + 56 + nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + 57 + LL_MAX_HEADER, GFP_ATOMIC); 58 + if (!nskb) 59 + return NULL; 60 + 61 + nskb->dev = (struct net_device *)dev; 62 + 63 + skb_reserve(nskb, LL_MAX_HEADER); 64 + niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP, 65 + net->ipv4.sysctl_ip_default_ttl); 66 + nf_reject_ip_tcphdr_put(nskb, oldskb, oth); 67 + niph->tot_len = htons(nskb->len); 68 + ip_send_check(niph); 69 + 70 + return nskb; 71 + } 72 + EXPORT_SYMBOL_GPL(nf_reject_skb_v4_tcp_reset); 73 + 74 + struct sk_buff *nf_reject_skb_v4_unreach(struct net *net, 75 + struct sk_buff *oldskb, 76 + const struct net_device *dev, 77 + int hook, u8 code) 78 + { 79 + struct sk_buff *nskb; 80 + struct iphdr *niph; 81 + struct icmphdr *icmph; 82 + unsigned int len; 83 + __wsum csum; 84 + u8 proto; 85 + 86 + if (!nf_reject_iphdr_validate(oldskb)) 87 + return NULL; 88 + 89 + /* IP header checks: fragment. */ 90 + if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) 91 + return NULL; 92 + 93 + /* RFC says return as much as we can without exceeding 576 bytes. */ 94 + len = min_t(unsigned int, 536, oldskb->len); 95 + 96 + if (!pskb_may_pull(oldskb, len)) 97 + return NULL; 98 + 99 + if (pskb_trim_rcsum(oldskb, ntohs(ip_hdr(oldskb)->tot_len))) 100 + return NULL; 101 + 102 + proto = ip_hdr(oldskb)->protocol; 103 + 104 + if (!skb_csum_unnecessary(oldskb) && 105 + nf_reject_verify_csum(proto) && 106 + nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), proto)) 107 + return NULL; 108 + 109 + nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmphdr) + 110 + LL_MAX_HEADER + len, GFP_ATOMIC); 111 + if (!nskb) 112 + return NULL; 113 + 114 + nskb->dev = (struct net_device *)dev; 115 + 116 + skb_reserve(nskb, LL_MAX_HEADER); 117 + niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP, 118 + net->ipv4.sysctl_ip_default_ttl); 119 + 120 + skb_reset_transport_header(nskb); 121 + icmph = skb_put_zero(nskb, sizeof(struct icmphdr)); 122 + icmph->type = ICMP_DEST_UNREACH; 123 + icmph->code = code; 124 + 125 + skb_put_data(nskb, skb_network_header(oldskb), len); 126 + 127 + csum = csum_partial((void *)icmph, len + sizeof(struct icmphdr), 0); 128 + icmph->checksum = csum_fold(csum); 129 + 130 + niph->tot_len = htons(nskb->len); 131 + ip_send_check(niph); 132 + 133 + return nskb; 134 + } 135 + EXPORT_SYMBOL_GPL(nf_reject_skb_v4_unreach); 136 + 15 137 const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb, 16 138 struct tcphdr *_oth, int hook) 17 139 {
+134
net/ipv6/netfilter/nf_reject_ipv6.c
··· 12 12 #include <linux/netfilter_ipv6.h> 13 13 #include <linux/netfilter_bridge.h> 14 14 15 + static bool nf_reject_v6_csum_ok(struct sk_buff *skb, int hook) 16 + { 17 + const struct ipv6hdr *ip6h = ipv6_hdr(skb); 18 + int thoff; 19 + __be16 fo; 20 + u8 proto = ip6h->nexthdr; 21 + 22 + if (skb_csum_unnecessary(skb)) 23 + return true; 24 + 25 + if (ip6h->payload_len && 26 + pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h))) 27 + return false; 28 + 29 + ip6h = ipv6_hdr(skb); 30 + thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); 31 + if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) 32 + return false; 33 + 34 + if (!nf_reject_verify_csum(proto)) 35 + return true; 36 + 37 + return nf_ip6_checksum(skb, hook, thoff, proto) == 0; 38 + } 39 + 40 + static int nf_reject_ip6hdr_validate(struct sk_buff *skb) 41 + { 42 + struct ipv6hdr *hdr; 43 + u32 pkt_len; 44 + 45 + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 46 + return 0; 47 + 48 + hdr = ipv6_hdr(skb); 49 + if (hdr->version != 6) 50 + return 0; 51 + 52 + pkt_len = ntohs(hdr->payload_len); 53 + if (pkt_len + sizeof(struct ipv6hdr) > skb->len) 54 + return 0; 55 + 56 + return 1; 57 + } 58 + 59 + struct sk_buff *nf_reject_skb_v6_tcp_reset(struct net *net, 60 + struct sk_buff *oldskb, 61 + const struct net_device *dev, 62 + int hook) 63 + { 64 + struct sk_buff *nskb; 65 + const struct tcphdr *oth; 66 + struct tcphdr _oth; 67 + unsigned int otcplen; 68 + struct ipv6hdr *nip6h; 69 + 70 + if (!nf_reject_ip6hdr_validate(oldskb)) 71 + return NULL; 72 + 73 + oth = nf_reject_ip6_tcphdr_get(oldskb, &_oth, &otcplen, hook); 74 + if (!oth) 75 + return NULL; 76 + 77 + nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 78 + LL_MAX_HEADER, GFP_ATOMIC); 79 + if (!nskb) 80 + return NULL; 81 + 82 + nskb->dev = (struct net_device *)dev; 83 + 84 + skb_reserve(nskb, LL_MAX_HEADER); 85 + nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP, 86 + net->ipv6.devconf_all->hop_limit); 87 + nf_reject_ip6_tcphdr_put(nskb, oldskb, oth, otcplen); 88 + nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr)); 89 + 90 + return nskb; 91 + } 92 + EXPORT_SYMBOL_GPL(nf_reject_skb_v6_tcp_reset); 93 + 94 + struct sk_buff *nf_reject_skb_v6_unreach(struct net *net, 95 + struct sk_buff *oldskb, 96 + const struct net_device *dev, 97 + int hook, u8 code) 98 + { 99 + struct sk_buff *nskb; 100 + struct ipv6hdr *nip6h; 101 + struct icmp6hdr *icmp6h; 102 + unsigned int len; 103 + 104 + if (!nf_reject_ip6hdr_validate(oldskb)) 105 + return NULL; 106 + 107 + /* Include "As much of invoking packet as possible without the ICMPv6 108 + * packet exceeding the minimum IPv6 MTU" in the ICMP payload. 109 + */ 110 + len = min_t(unsigned int, 1220, oldskb->len); 111 + 112 + if (!pskb_may_pull(oldskb, len)) 113 + return NULL; 114 + 115 + if (!nf_reject_v6_csum_ok(oldskb, hook)) 116 + return NULL; 117 + 118 + nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) + 119 + LL_MAX_HEADER + len, GFP_ATOMIC); 120 + if (!nskb) 121 + return NULL; 122 + 123 + nskb->dev = (struct net_device *)dev; 124 + 125 + skb_reserve(nskb, LL_MAX_HEADER); 126 + nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_ICMPV6, 127 + net->ipv6.devconf_all->hop_limit); 128 + 129 + skb_reset_transport_header(nskb); 130 + icmp6h = skb_put_zero(nskb, sizeof(struct icmp6hdr)); 131 + icmp6h->icmp6_type = ICMPV6_DEST_UNREACH; 132 + icmp6h->icmp6_code = code; 133 + 134 + skb_put_data(nskb, skb_network_header(oldskb), len); 135 + nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr)); 136 + 137 + icmp6h->icmp6_cksum = 138 + csum_ipv6_magic(&nip6h->saddr, &nip6h->daddr, 139 + nskb->len - sizeof(struct ipv6hdr), 140 + IPPROTO_ICMPV6, 141 + csum_partial(icmp6h, 142 + nskb->len - sizeof(struct ipv6hdr), 143 + 0)); 144 + 145 + return nskb; 146 + } 147 + EXPORT_SYMBOL_GPL(nf_reject_skb_v6_unreach); 148 + 15 149 const struct tcphdr *nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb, 16 150 struct tcphdr *otcph, 17 151 unsigned int *otcplen, int hook)