From: Josh Date: Wed, 7 May 2014 16:37:26 +0000 (-0400) Subject: tweaking checksums X-Git-Tag: 3.0.0-233~1526^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=97a875baceaa925b8e97e4e512431721e89cc995;p=thirdparty%2Fsnort3.git tweaking checksums --- diff --git a/src/codecs/CMakeLists.txt b/src/codecs/CMakeLists.txt index 446422f66..23ab13e81 100644 --- a/src/codecs/CMakeLists.txt +++ b/src/codecs/CMakeLists.txt @@ -19,6 +19,8 @@ add_library( codecs STATIC ipv6_util.cc codec_events.cc codec_events.h + checksum.h + checksum.cc ) diff --git a/src/codecs/Makefile.am b/src/codecs/Makefile.am index 4c1cbfb84..38fc4da46 100644 --- a/src/codecs/Makefile.am +++ b/src/codecs/Makefile.am @@ -19,7 +19,9 @@ libcodec_utils_a_SOURCES = \ codec_events.cc \ codec_events.h \ ipv6_util.h \ -ipv6_util.cc +ipv6_util.cc \ +checksum.h \ +checksum.cc SUBDIRS = \ diff --git a/src/codecs/checksum.cc b/src/codecs/checksum.cc new file mode 100644 index 000000000..1898e0d30 --- /dev/null +++ b/src/codecs/checksum.cc @@ -0,0 +1,258 @@ +/* +** Copyright (C) 2002-2013 Sourcefire, Inc. +** Copyright (C) 1998-2002 Martin Roesch +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License Version 2 as +** published by the Free Software Foundation. You may not use, modify or +** distribute this program under any other version of the GNU General +** Public License. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +// checksum.h author Josh Rosenbaum + + + +#include "protocols/checksum.h" + +/************************************************************ + *********** Checksum information ************************* + ************************************************************/ + +namespace checksum +{ + +static inline void add_ipv4_pseudoheader(const uint16_t *h, uint32_t &cksum) +{ + /* ipv4 pseudo header must have 12 bytes */ + cksum += h[0]; + cksum += h[1]; + cksum += h[2]; + cksum += h[3]; + cksum += h[4]; + cksum += h[5]; +} + + +static inline void add_ipv6_pseudoheader(const uint16_t *h, uint32_t &cksum) +{ + /* PseudoHeader must have 36 bytes */ + cksum += h[0]; + cksum += h[1]; + cksum += h[2]; + cksum += h[3]; + cksum += h[4]; + cksum += h[5]; + cksum += h[6]; + cksum += h[7]; + cksum += h[8]; + cksum += h[9]; + cksum += h[10]; + cksum += h[11]; + cksum += h[12]; + cksum += h[13]; + cksum += h[14]; + cksum += h[15]; + cksum += h[16]; + cksum += h[17]; +} + + +static inline void add_tcp_header(const uint16_t* &d, + size_t &len, + uint32_t &cksum) +{ + /* TCP hdr must have 20 hdr bytes */ + cksum += d[0]; + cksum += d[1]; + cksum += d[2]; + cksum += d[3]; + cksum += d[4]; + cksum += d[5]; + cksum += d[6]; + cksum += d[7]; + cksum += d[8]; + cksum += d[9]; + d += 10; + len -= 20; +} + +static inline void add_udp_header(const uint16_t* &d, + size_t &len, + uint32_t &cksum) +{ + /* UDP must have 8 hdr bytes */ + cksum += d[0]; + cksum += d[1]; + cksum += d[2]; + cksum += d[3]; + len -= 8; + d += 4; +} + +static inline void add_ip_header(const uint16_t* &d, + size_t &len, + uint32_t &cksum) +{ + /* IP must be >= 20 bytes */ + cksum += d[0]; + cksum += d[1]; + cksum += d[2]; + cksum += d[3]; + cksum += d[4]; + cksum += d[5]; + cksum += d[6]; + cksum += d[7]; + cksum += d[8]; + cksum += d[9]; + d += 10; + len -= 20; +} + + +uint16_t icmp_cksum(const uint16_t *buf, size_t len, Pseudoheader6* ph) +{ + uint32_t cksum = 0; + + add_ipv6_pseudoheader((uint16_t *)ph, cksum); + return cksum_add(buf, len, cksum); +} + +uint16_t tcp_cksum(const uint16_t *h, size_t len, Pseudoheader *ph ) +{ + uint32_t cksum = 0; + + add_ipv4_pseudoheader((uint16_t *)ph, cksum); + add_tcp_header(h, len, cksum); + return cksum_add(h, len, cksum); +} + + +uint16_t tcp_cksum(const uint16_t *buf, size_t len, Pseudoheader6 *ph ) +{ + uint32_t cksum = 0; + + add_ipv6_pseudoheader((uint16_t *)ph, cksum); + add_tcp_header(buf, len, cksum); + return cksum_add(buf, len, cksum); +} + + +uint16_t udp_cksum(const uint16_t *buf, size_t len, Pseudoheader *ph ) +{ + uint32_t cksum = 0; + + add_ipv4_pseudoheader((uint16_t *)ph, cksum); + add_udp_header(buf, len, cksum); + return cksum_add(buf, len, cksum); +} + + +uint16_t udp_cksum(const uint16_t *buf, size_t len, Pseudoheader6 *ph ) +{ + uint32_t cksum = 0; + + add_ipv6_pseudoheader((uint16_t *)ph, cksum); + add_udp_header(buf, len, cksum); + return cksum_add(buf, len, cksum); +} + +uint16_t ip_cksum(const uint16_t *buf, size_t len) +{ + uint32_t cksum = 0; + + add_ip_header(buf, len, cksum); + return cksum_add(buf, len, cksum); +} + + +// credit belong to dnet.h. copied directrly from their source code +// src/ip-util.cc +uint16_t cksum_add(const uint16_t *buf, size_t len, uint32_t cksum) +{ + uint16_t *sp = (uint16_t *)buf; + int n, sn; + + if (len > 1 ) + { + sn = ((len / 2) & 0xF); // len divided by two mod 16 == len/2 % 16 + n = (((len / 2) + 15) / 16) ; // ceiling of (len / 2) / 16 + + switch (sn) { + case 0: + sn = 16; + cksum += sp[15]; + case 15: + cksum += sp[14]; + case 14: + cksum += sp[13]; + case 13: + cksum += sp[12]; + case 12: + cksum += sp[11]; + case 11: + cksum += sp[10]; + case 10: + cksum += sp[9]; + case 9: + cksum += sp[8]; + case 8: + cksum += sp[7]; + case 7: + cksum += sp[6]; + case 6: + cksum += sp[5]; + case 5: + cksum += sp[4]; + case 4: + cksum += sp[3]; + case 3: + cksum += sp[2]; + case 2: + cksum += sp[1]; + case 1: + cksum += sp[0]; + } + sp += sn; + + + /* XXX - unroll loop using Duff's device. */ + while (--n > 0) { + cksum += sp[0]; + cksum += sp[1]; + cksum += sp[2]; + cksum += sp[3]; + cksum += sp[4]; + cksum += sp[5]; + cksum += sp[6]; + cksum += sp[7]; + cksum += sp[8]; + cksum += sp[9]; + cksum += sp[10]; + cksum += sp[11]; + cksum += sp[12]; + cksum += sp[13]; + cksum += sp[14]; + cksum += sp[15]; + sp += 16; + }; + } + + if (len & 1) + cksum += (*(unsigned char*)sp); + + cksum = (cksum >> 16) + (cksum & 0x0000ffff); + cksum += (cksum >> 16); + + return (uint16_t)(~cksum); +} + +} // namespace checksum diff --git a/src/protocols/checksum.h b/src/codecs/checksum.h similarity index 97% rename from src/protocols/checksum.h rename to src/codecs/checksum.h index c5272bcb1..95dd4c3fe 100644 --- a/src/protocols/checksum.h +++ b/src/codecs/checksum.h @@ -66,6 +66,7 @@ uint16_t tcp_cksum(const uint16_t *buf, size_t len, Pseudoheader6 *ph ); uint16_t udp_cksum(const uint16_t *buf, size_t len, Pseudoheader*); uint16_t udp_cksum(const uint16_t *buf, size_t len, Pseudoheader6*); uint16_t icmp_cksum(const uint16_t *buf, size_t len, Pseudoheader6*); +uint16_t ip_cksum(const uint16_t *buf, size_t len); static inline int16_t icmp_cksum(const uint16_t *buf, size_t len) diff --git a/src/codecs/encode.cc b/src/codecs/encode.cc index 806fdd1d2..8d2975107 100644 --- a/src/codecs/encode.cc +++ b/src/codecs/encode.cc @@ -49,7 +49,7 @@ #include "protocols/udp.h" #include "protocols/eth.h" #include "protocols/gtp.h" -#include "protocols/checksum.h" +#include "codecs/checksum.h" diff --git a/src/codecs/ip/cd_icmp4.cc b/src/codecs/ip/cd_icmp4.cc index 0dfda019c..28ef5c42a 100644 --- a/src/codecs/ip/cd_icmp4.cc +++ b/src/codecs/ip/cd_icmp4.cc @@ -35,7 +35,7 @@ #include "codecs/decode_module.h" #include "protocols/icmp4.h" #include "codecs/codec_events.h" -#include "protocols/checksum.h" +#include "codecs/checksum.h" namespace{ diff --git a/src/codecs/ip/cd_icmp6.cc b/src/codecs/ip/cd_icmp6.cc index 9fc93afeb..9bf41fee7 100644 --- a/src/codecs/ip/cd_icmp6.cc +++ b/src/codecs/ip/cd_icmp6.cc @@ -28,7 +28,7 @@ #include "snort.h" #include "codecs/decode_module.h" #include "codecs/codec_events.h" -#include "protocols/checksum.h" +#include "codecs/checksum.h" #include "protocols/icmp6.h" #include "protocols/icmp4.h" diff --git a/src/codecs/ip/cd_ipv4.cc b/src/codecs/ip/cd_ipv4.cc index 7283a37a0..ea939efb6 100644 --- a/src/codecs/ip/cd_ipv4.cc +++ b/src/codecs/ip/cd_ipv4.cc @@ -42,7 +42,7 @@ #include "packet_io/active.h" #include "codecs/decode_module.h" #include "codecs/codec_events.h" -#include "protocols/checksum.h" +#include "codecs/checksum.h" namespace{ @@ -259,7 +259,7 @@ bool Ipv4Codec::decode(const uint8_t *raw_packet, const uint32_t len, * need to check them (should make this a command line/config * option */ - int16_t csum = checksum::cksum_add( (u_short *)p->iph, hlen); + int16_t csum = checksum::ip_cksum((uint16_t *)p->iph, hlen); if(csum) { diff --git a/src/codecs/ip/cd_pgm.cc b/src/codecs/ip/cd_pgm.cc index fcaf45473..b98bd1585 100644 --- a/src/codecs/ip/cd_pgm.cc +++ b/src/codecs/ip/cd_pgm.cc @@ -28,7 +28,7 @@ #include "codecs/decode_module.h" #include "codecs/codec_events.h" #include "protocols/ipv4.h" -#include "protocols/checksum.h" +#include "codecs/checksum.h" namespace { diff --git a/src/codecs/ip/cd_tcp.cc b/src/codecs/ip/cd_tcp.cc index 56ebe3c89..f06da8442 100644 --- a/src/codecs/ip/cd_tcp.cc +++ b/src/codecs/ip/cd_tcp.cc @@ -36,7 +36,7 @@ #include "packet_io/sfdaq.h" #include "parser/parse_ip.h" #include "codecs/codec_events.h" -#include "protocols/checksum.h" +#include "codecs/checksum.h" #include "snort.h" #include "packet_io/active.h" @@ -175,7 +175,7 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t len, /* setup the pseudo header for checksum calculation */ ph.zero = 0; ph.protocol = GET_IPH_PROTO(p); - ph.len = htons((u_short)len); + ph.len = htons((uint16_t)len); /* if we're being "stateless" we probably don't care about the TCP * checksum, but it's not bad to keep around for shits and giggles */ @@ -203,7 +203,7 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t len, COPY4(ph6.dip, p->ip6h->ip_dst.ip32); ph6.zero = 0; ph6.protocol = GET_IPH_PROTO(p); - ph6.len = htons((u_short)len); + ph6.len = htons((uint16_t)len); csum = checksum::tcp_cksum((uint16_t *)(p->tcph), len, &ph6); @@ -327,7 +327,7 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t len, if(lyr_len < len) { - p->dsize = (u_short)(len - lyr_len); + p->dsize = (uint16_t)(len - lyr_len); } else { diff --git a/src/codecs/ip/cd_udp.cc b/src/codecs/ip/cd_udp.cc index d0d0e95c8..cb0f4ad3d 100644 --- a/src/codecs/ip/cd_udp.cc +++ b/src/codecs/ip/cd_udp.cc @@ -35,7 +35,7 @@ #include "protocols/udp.h" #include "protocols/teredo.h" #include "protocols/protocol_ids.h" -#include "protocols/checksum.h" +#include "codecs/checksum.h" #include "framework/codec.h" #include "packet_io/active.h" diff --git a/src/protocols/CMakeLists.txt b/src/protocols/CMakeLists.txt index 029776e17..541a51277 100644 --- a/src/protocols/CMakeLists.txt +++ b/src/protocols/CMakeLists.txt @@ -19,8 +19,6 @@ set (PROTOCOL_HEADERS add_library (protocols STATIC packet.cc - checksum.h - checksum.cc ${PROTOCOL_HEADERS} ) diff --git a/src/protocols/Makefile.am b/src/protocols/Makefile.am index bf13a55f4..d2ba1143b 100644 --- a/src/protocols/Makefile.am +++ b/src/protocols/Makefile.am @@ -24,9 +24,7 @@ protocol_ids.h \ tcp.h \ teredo.h \ udp.h \ -wlan.h \ -checksum.h \ -checksum.cc +wlan.h AM_CXXFLAGS = @AM_CXXFLAGS@ diff --git a/src/protocols/checksum.cc b/src/protocols/checksum.cc deleted file mode 100644 index 7c6e5420b..000000000 --- a/src/protocols/checksum.cc +++ /dev/null @@ -1,256 +0,0 @@ -/* -** Copyright (C) 2002-2013 Sourcefire, Inc. -** Copyright (C) 1998-2002 Martin Roesch -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License Version 2 as -** published by the Free Software Foundation. You may not use, modify or -** distribute this program under any other version of the GNU General -** Public License. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -// checksum.h author Josh Rosenbaum - - - -#include "protocols/checksum.h" - -/************************************************************ - *********** Checksum information ************************* - ************************************************************/ - -namespace checksum -{ - -static inline uint32_t add_ipv4_pseudoheader(const uint16_t *h) -{ - uint32_t cksum1; - - /* ipv4 pseudo header must have 12 bytes */ - cksum1 = h[0]; - cksum1 = h[1]; - cksum1 += h[2]; - cksum1 += h[3]; - cksum1 += h[4]; - cksum1 += h[5]; - - return cksum1; -} - - -static inline uint32_t add_ipv6_pseudoheader(const uint16_t *h) -{ - uint32_t cksum1; - uint32_t cksum2; - - /* PseudoHeader must have 36 bytes */ - cksum1 = h[0]; - cksum2 = h[1]; - cksum1 += h[2]; - cksum2 += h[3]; - cksum1 += h[4]; - cksum2 += h[5]; - cksum1 += h[6]; - cksum2 += h[7]; - cksum1 += h[8]; - cksum2 += h[9]; - cksum1 += h[10]; - cksum2 += h[11]; - cksum1 += h[12]; - cksum2 += h[13]; - cksum1 += h[14]; - cksum2 += h[15]; - cksum1 += h[16]; - cksum2 += h[17]; - - return cksum1 + cksum2; -} - - -static inline uint32_t add_tcp_header(const uint16_t* &d, - size_t &len) -{ - uint32_t cksum1; - uint32_t cksum2; - - /* TCP hdr must have 20 hdr bytes */ - cksum1 = d[0]; - cksum2 = d[1]; - cksum1 += d[2]; - cksum2 += d[3]; - cksum1 += d[4]; - cksum2 += d[5]; - cksum1 += d[6]; - cksum2 += d[7]; - cksum1 += d[8]; - cksum2 += d[9]; - d += 10; - len -= 20; - - return cksum1 + cksum2; -} - -static inline uint32_t add_udp_header(const uint16_t* &d, - size_t &len) -{ - uint32_t cksum1; - - /* UDP must have 8 hdr bytes */ - cksum1 = d[0]; - cksum1 += d[1]; - cksum1 += d[2]; - cksum1 += d[3]; - len -= 8; - d += 4; - - return cksum1; -} - - -uint16_t icmp_cksum(const uint16_t *buf, size_t len, Pseudoheader6* ph) -{ - uint32_t cksum; - - - cksum = add_ipv6_pseudoheader((uint16_t *)ph); - return cksum_add(buf, len, cksum); -} - -uint16_t tcp_cksum(const uint16_t *h, size_t len, Pseudoheader *ph ) -{ - uint32_t cksum; - - cksum = add_ipv4_pseudoheader((uint16_t *)ph); - cksum += add_tcp_header(h, len); - return cksum_add(h, len, cksum); -} - - -uint16_t tcp_cksum(const uint16_t *buf, size_t len, Pseudoheader6 *ph ) -{ - uint32_t cksum; - - cksum = add_ipv6_pseudoheader((uint16_t *)ph); - cksum += add_tcp_header(buf, len); - return cksum_add(buf, len, cksum); -} - - -uint16_t udp_cksum(const uint16_t *buf, size_t len, Pseudoheader *ph ) -{ - uint32_t cksum; - - cksum = add_ipv4_pseudoheader((uint16_t *)ph); - cksum += add_udp_header(buf, len); - return cksum_add(buf, len, cksum); -} - - -uint16_t udp_cksum(const uint16_t *buf, size_t len, Pseudoheader6 *ph ) -{ - uint32_t cksum; - - cksum = add_ipv6_pseudoheader((uint16_t *)ph); - cksum += add_udp_header(buf, len); - return cksum_add(buf, len, cksum); -} - - - -// credit belong to dnet.h. copied directrly from their source code -// src/ip-util.cc -uint16_t cksum_add(const uint16_t *buf, size_t len, uint32_t cksum1) -{ - uint16_t *sp = (uint16_t *)buf; - int n, sn; - uint32_t cksum2 = 0; - uint32_t cksum3 = 0; - uint32_t cksum4 = 0; - - if (len > 1 ) - { - sn = ((len / 2) & 0xF); // len divided by two mod 16 == len/2 % 16 - n = (((len / 2) + 15) / 16) ; // ceiling of (len / 2) / 16 - - switch (sn) { - case 0: - sn = 16; - cksum1 += sp[15]; - case 15: - cksum2 += sp[14]; - case 14: - cksum3 += sp[13]; - case 13: - cksum4 += sp[12]; - case 12: - cksum1 += sp[11]; - case 11: - cksum2 += sp[10]; - case 10: - cksum3 += sp[9]; - case 9: - cksum4 += sp[8]; - case 8: - cksum1 += sp[7]; - case 7: - cksum2 += sp[6]; - case 6: - cksum3 += sp[5]; - case 5: - cksum4 += sp[4]; - case 4: - cksum1 += sp[3]; - case 3: - cksum2 += sp[2]; - case 2: - cksum3 += sp[1]; - case 1: - cksum4 += sp[0]; - } - sp += sn; - - - /* XXX - unroll loop using Duff's device. */ - while (--n > 0) { - cksum1 += sp[0]; - cksum2 += sp[1]; - cksum3 += sp[2]; - cksum4 += sp[3]; - cksum1 += sp[4]; - cksum2 += sp[5]; - cksum3 += sp[6]; - cksum4 += sp[7]; - cksum1 += sp[8]; - cksum2 += sp[9]; - cksum3 += sp[10]; - cksum4 += sp[11]; - cksum1 += sp[12]; - cksum2 += sp[13]; - cksum3 += sp[14]; - cksum4 += sp[15]; - sp += 16; - }; - - cksum1 += cksum2; - cksum3 += cksum4; - cksum1 += cksum3; - } - - if (len & 1) - cksum1 += (*(unsigned char*)sp); - - cksum1 = (cksum1 >> 16) + (cksum1 & 0x0000ffff); - cksum1 += (cksum1 >> 16); - - return (uint16_t)(~cksum1); -} - -} // namespace checksum