From: Alin Nastac <alin.nastac@xxxxxxxxx> Some protocols have other means to verify the payload integrity (AH, ESP, SCTP) while others are incompatible with nf_ip(6)_checksum implementation because checksum is either optional or might be partial (UDPLITE, DCCP, GRE). Because nf_ip(6)_checksum was used to validate the packets, ip(6)tables REJECT rules were not capable to generate ICMP(v6) errors for the protocols mentioned above. This commit also fixes the incorrect pseudo-header protocol used for IPv4 packets that carry other transport protocols than TCP or UDP (pseudo-header used protocol 0 iso the proper value). Signed-off-by: Alin Nastac <alin.nastac@xxxxxxxxx> --- net/ipv4/netfilter/nf_reject_ipv4.c | 33 ++++++++++++++++++++++++--------- net/ipv6/netfilter/nf_reject_ipv6.c | 18 ++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c index aa8304c..9225b7f 100644 --- a/net/ipv4/netfilter/nf_reject_ipv4.c +++ b/net/ipv4/netfilter/nf_reject_ipv4.c @@ -178,18 +178,33 @@ void nf_send_unreach(struct sk_buff *skb_in, int code, int hook) if (iph->frag_off & htons(IP_OFFSET)) return; - if (skb_csum_unnecessary(skb_in)) { - icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); - return; + if (skb_csum_unnecessary(skb_in)) + goto send_unreach; + + /* Skip checksum verification for protocols that don't use + * 16-bit one's complement checksum of the entire payload. + */ + proto = iph->protocol; + switch (proto) { + /* Protocols with other integrity checks. */ + case IPPROTO_AH: + case IPPROTO_ESP: + case IPPROTO_SCTP: + + /* Protocols with partial checksums. */ + case IPPROTO_UDPLITE: + case IPPROTO_DCCP: + + /* Protocols with optional checksums. */ + case IPPROTO_GRE: + goto send_unreach; } - if (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) - proto = iph->protocol; - else - proto = 0; + if (nf_ip_checksum(skb_in, hook, ip_hdrlen(skb_in), proto)) + return; - if (nf_ip_checksum(skb_in, hook, ip_hdrlen(skb_in), proto) == 0) - icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); + send_unreach: + icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); } EXPORT_SYMBOL_GPL(nf_send_unreach); diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index b9c8a76..2af014e 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c @@ -233,6 +233,24 @@ static bool reject6_csum_ok(struct sk_buff *skb, int hook) if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) return false; + /* Skip protocols that don't use 16-bit one's complement checksum + * of the entire payload. + */ + switch (proto) { + /* Protocols with other integrity checks. */ + case IPPROTO_AH: + case IPPROTO_ESP: + case IPPROTO_SCTP: + + /* Protocols with partial checksums. */ + case IPPROTO_UDPLITE: + case IPPROTO_DCCP: + + /* Protocols with optional checksums. */ + case IPPROTO_GRE: + return true; + } + return nf_ip6_checksum(skb, hook, thoff, proto) == 0; } -- 2.7.4