From 41dd0f8e6242b347acf0496d90f2a81743b79e7c Mon Sep 17 00:00:00 2001 From: Anoop Saldanha Date: Tue, 25 Aug 2009 12:23:21 +0530 Subject: [PATCH] checksum calculation functions for ipv4, tcp, udpv4, icmpv4 --- src/decode-icmpv4.c | 90 ++++++++++++++++++++++++++++++++ src/decode-ipv4.c | 89 ++++++++++++++++++++++++++++++++ src/decode-tcp.c | 108 +++++++++++++++++++++++++++++++++++++++ src/decode-tcp.h | 2 + src/decode-udp.c | 122 ++++++++++++++++++++++++++++++++++++++++++++ src/decode-udp.h | 2 + src/eidps.c | 2 + 7 files changed, 415 insertions(+) diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index e454cf1bde..1217cdeb79 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -5,6 +5,58 @@ #include "decode-icmpv4.h" #include "util-unittest.h" +/** + * \brief Calculates the checksum for the ICMP packet + * + * \param pkt Pointer to the start of the ICMP packet + * \param hlen Total length of the ICMP packet(header + payload) + * + * \retval csum Checksum for the ICMP packet + */ +static inline uint16_t ICMPV4CalculateChecksum(uint16_t *pkt, uint16_t tlen) +{ + uint16_t pad = 0; + uint32_t csum = pkt[0]; + + tlen -= 4; + pkt += 2; + + while (tlen >= 32) { + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + + pkt[14] + pkt[15]; + tlen -= 32; + pkt += 16; + } + + while(tlen >= 8) { + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; + tlen -= 8; + pkt += 4; + } + + while(tlen >= 4) { + csum += pkt[0] + pkt[1]; + tlen -= 4; + pkt += 2; + } + + while (tlen > 1) { + csum += pkt[0]; + tlen -= 2; + pkt += 1; + } + + if (tlen == 1) { + *(uint8_t *)(&pad) = (*(uint8_t *)pkt); + csum += pad; + } + + csum = (csum >> 16) + (csum & 0x0000FFFF); + + return (uint16_t) ~csum; +} + /** DecodeICMPV4 * \brief Main ICMPv4 decoding function */ @@ -127,6 +179,40 @@ static int DecodeICMPV4test04(void) { return 0; } +static int ICMPV4CalculateValidChecksumtest05(void) { + uint16_t csum = 0; + + uint8_t raw_icmpv4[] = { + 0x08, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, + 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; + + csum = *( ((uint16_t *)raw_icmpv4) + 1); + return (csum == ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); +} + +static int ICMPV4CalculateInvalidChecksumtest06(void) { + uint16_t csum = 0; + + uint8_t raw_icmpv4[] = { + 0x08, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, + 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; + + csum = *( ((uint16_t *)raw_icmpv4) + 1); + return (csum == ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); +} + /** * \brief Registers ICMPV4 unit test * \todo More ICMPv4 tests @@ -136,6 +222,10 @@ void DecodeICMPV4RegisterTests(void) { UtRegisterTest("DecodeICMPV4ttest02", DecodeICMPV4test02, 0); UtRegisterTest("DecodeICMPV4ttest03", DecodeICMPV4test03, 0); UtRegisterTest("DecodeICMPV4ttest04", DecodeICMPV4test04, 0); + UtRegisterTest("ICMPV4CalculateValidChecksumtest05", + ICMPV4CalculateValidChecksumtest05, 1); + UtRegisterTest("ICMPV4CalculateInvalidChecksumtest06", + ICMPV4CalculateInvalidChecksumtest06, 0); } #endif /* UNITTESTS */ diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 6313d1ad8f..87fff43c20 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -11,6 +11,62 @@ #include "decode-events.h" #include "util-unittest.h" +/** + * \brief Calculates the checksum for the IP packet + * + * \param pkt Pointer to the start of the IP packet + * \param hlen Length of the IP header + * + * \retval csum Checksum for the IP packet + */ +static inline uint16_t IPV4CalculateChecksum(uint16_t *pkt, uint16_t hlen) +{ + uint32_t csum = pkt[0]; + + csum += pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] + pkt[8] + + pkt[9]; + + hlen -= 20; + pkt += 10; + + if (hlen == 0) + ; + if (hlen == 4) + csum += pkt[0] + pkt[1]; + else if (hlen == 8) + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; + else if (hlen == 12) + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5]; + else if (hlen == 16) + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7]; + else if (hlen == 20) + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[8] + pkt[9]; + else if (hlen == 24) + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11]; + else if (hlen == 28) + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13]; + else if (hlen == 32) + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + + pkt[14] + pkt[15]; + if (hlen == 36) + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + + pkt[14] + pkt[15] + pkt[16] + pkt[17]; + if (hlen == 40) + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + + pkt[14] + pkt[15] + pkt[16] + pkt[17] + pkt[18] + pkt[19]; + + csum = (csum >> 16) + (csum & 0x0000FFFF); + + return (uint16_t) ~csum; +} + /* Generic validation * * [--type--][--len---] @@ -1361,6 +1417,34 @@ int DecodeIPV4OptionsRTRALTTest02(void) { return 0; } +static int IPV4CalculateValidChecksumtest01(void) +{ + uint16_t csum = 0; + + uint8_t raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, + 0xc0, 0xa8, 0x01, 0x03}; + + csum = *( ((uint16_t *)raw_ipv4) + 5); + + return (csum == IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); +} + +static int IPV4CalculateInvalidChecksumtest02(void) +{ + uint16_t csum = 0; + + uint8_t raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, + 0xc0, 0xa8, 0x01, 0x07}; + + csum = *( ((uint16_t *)raw_ipv4) + 5); + + return (csum == IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); +} + void DecodeIPV4RegisterTests(void) { UtRegisterTest("DecodeIPV4OptionsNONETest01", DecodeIPV4OptionsNONETest01, 1); UtRegisterTest("DecodeIPV4OptionsEOLTest01", DecodeIPV4OptionsEOLTest01, 1); @@ -1390,6 +1474,11 @@ void DecodeIPV4RegisterTests(void) { UtRegisterTest("DecodeIPV4OptionsSSRRTest04", DecodeIPV4OptionsSSRRTest04, 1); UtRegisterTest("DecodeIPV4OptionsRTRALTTest01", DecodeIPV4OptionsRTRALTTest01, 1); UtRegisterTest("DecodeIPV4OptionsRTRALTTest02", DecodeIPV4OptionsRTRALTTest02, 1); + UtRegisterTest("IPV4CalculateValidChecksumtest01", + IPV4CalculateValidChecksumtest01, 1); + UtRegisterTest("IPV4CalculateInvalidChecksumtest02", + IPV4CalculateInvalidChecksumtest02, 0); + } #endif /* UNITTESTS */ diff --git a/src/decode-tcp.c b/src/decode-tcp.c index a38b2f71b3..0e38c08abb 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -4,9 +4,70 @@ #include "decode.h" #include "decode-tcp.h" #include "decode-events.h" +#include "util-unittest.h" #include "flow.h" +/** + * \brief Calculates the checksum for the TCP packet + * + * \param shdr Pointer to source address field from the IP packet. Used as a + * part of the psuedoheader for computing the checksum + * \param pkt Pointer to the start of the TCP packet + * \param hlen Total length of the TCP packet(header + payload) + * + * \retval csum Checksum for the TCP packet + */ +static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen) +{ + uint16_t pad = 0; + uint32_t csum = shdr[0]; + + csum += shdr[1] + shdr[2] + shdr[3] + htons(6 + tlen); + + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[9]; + + tlen -= 20; + pkt += 10; + + while (tlen >= 32) { + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + + pkt[14] + pkt[15]; + tlen -= 32; + pkt += 16; + } + + while(tlen >= 8) { + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; + tlen -= 8; + pkt += 4; + } + + while(tlen >= 4) { + csum += pkt[0] + pkt[1]; + tlen -= 4; + pkt += 2; + } + + while (tlen > 1) { + csum += pkt[0]; + pkt += 1; + tlen -= 2; + } + + if (tlen == 1) { + *(uint8_t *)(&pad) = (*(uint8_t *)pkt); + csum += pad; + } + + csum = (csum >> 16) + (csum & 0x0000FFFF); + + return (uint16_t) ~csum; +} + static int DecodeTCPOptions(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t len) { uint16_t plen = len; @@ -158,3 +219,50 @@ void DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u return; } +static int TCPCalculateValidChecksumtest01(void) +{ + uint16_t csum = 0; + + uint8_t raw_ipshdr[] = { + 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; + + uint8_t raw_tcp[] = { + 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, + 0xcf, 0x0d, 0x21, 0x80, 0xa0, 0x12, 0x16, 0xa0, + 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, + 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 02}; + + csum = *( ((uint16_t *)raw_tcp) + 8); + + return (csum == TCPCalculateChecksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_tcp, sizeof(raw_tcp))); +} + +static int TCPCalculateInvalidChecksumtest02(void) +{ + uint16_t csum = 0; + + uint8_t raw_ipshdr[] = { + 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; + + uint8_t raw_tcp[] = { + 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, + 0xcf, 0x0d, 0x21, 0x80, 0xa0, 0x12, 0x16, 0xa0, + 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, + 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 03}; + + csum = *( ((uint16_t *)raw_tcp) + 8); + + return (csum == TCPCalculateChecksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_tcp, sizeof(raw_tcp))); +} + +void DecodeTCPRegisterTests(void) +{ + UtRegisterTest("TCPCalculateValidChecksumtest01", + TCPCalculateValidChecksumtest01, 1); + UtRegisterTest("TCPCalculateInvalidChecksumtest02", + TCPCalculateInvalidChecksumtest02, 0); +} diff --git a/src/decode-tcp.h b/src/decode-tcp.h index 402c8e46a2..a247dfbf6d 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -114,5 +114,7 @@ typedef struct TCPVars_ (p)->tcpvars.mss = NULL; \ } +void DecodeTCPRegisterTests(void); + #endif /* __DECODE_TCP_H__ */ diff --git a/src/decode-udp.c b/src/decode-udp.c index 403c1f2690..d014481c2b 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -4,9 +4,69 @@ #include "decode.h" #include "decode-udp.h" #include "decode-events.h" +#include "util-unittest.h" #include "flow.h" +/** + * \brief Calculates the checksum for the UDP packet + * + * \param shdr Pointer to source address field from the IP packet. Used as a + * part of the psuedoheader for computing the checksum + * \param pkt Pointer to the start of the UDP packet + * \param hlen Total length of the UDP packet(header + payload) + * + * \retval csum Checksum for the UDP packet + */ +static inline uint16_t UDPV4CalculateChecksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen) +{ + uint16_t pad = 0; + uint32_t csum = shdr[0]; + + csum += shdr[1] + shdr[2] + shdr[3] + htons(17 + tlen); + + csum += pkt[0] + pkt[1] + pkt[2]; + + tlen -= 8; + pkt += 4; + + while (tlen >= 32) { + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + + pkt[14] + pkt[15]; + tlen -= 32; + pkt += 16; + } + + while(tlen >= 8) { + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; + tlen -= 8; + pkt += 4; + } + + while(tlen >= 4) { + csum += pkt[0] + pkt[1]; + tlen -= 4; + pkt += 2; + } + + while (tlen > 1) { + csum += pkt[0]; + pkt += 1; + tlen -= 2; + } + + if (tlen == 1) { + *(uint8_t *)(&pad) = (*(uint8_t *)pkt); + csum += pad; + } + + csum = (csum >> 16) + (csum & 0x0000FFFF); + + return (uint16_t) ~csum; +} + static int DecodeUDPPacket(ThreadVars *t, Packet *p, uint8_t *pkt, uint16_t len) { if (len < UDP_HEADER_LEN) { @@ -56,3 +116,65 @@ void DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u return; } + +static int UDPV4CalculateValidChecksumtest01(void) +{ + uint16_t csum = 0; + + uint8_t raw_ipshdr[] = { + 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x3}; + + uint8_t raw_udp[] = { + 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, + 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, + 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, + 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, + 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, + 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, + 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0xc0, 0x26}; + + csum = *( ((uint16_t *)raw_udp) + 3); + + return (csum == UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_udp, + sizeof(raw_udp))); +} + +static int UDPV4CalculateInvalidChecksumtest02(void) +{ + uint16_t csum = 0; + + uint8_t raw_ipshdr[] = { + 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x3}; + + uint8_t raw_udp[] = { + 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, + 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, + 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, + 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, + 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, + 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, + 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0xc0, 0x27}; + + csum = *( ((uint16_t *)raw_udp) + 3); + + return (csum == UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_udp, + sizeof(raw_udp))); +} + +void DecodeUDPV4RegisterTests(void) +{ + UtRegisterTest("UDPV4CalculateValidChecksumtest01", + UDPV4CalculateValidChecksumtest01, 1); + UtRegisterTest("UDPV4CalculateInvalidChecksumtest02", + UDPV4CalculateInvalidChecksumtest02, 0); +} diff --git a/src/decode-udp.h b/src/decode-udp.h index def4afb1ad..3e052cb719 100644 --- a/src/decode-udp.h +++ b/src/decode-udp.h @@ -28,4 +28,6 @@ typedef struct UDPVars_ uint8_t hlen; } UDPVars; +void DecodeUDPV4RegisterTests(void); + #endif /* __DECODE_UDP_H__ */ diff --git a/src/eidps.c b/src/eidps.c index 62d95c809e..aec7937fde 100644 --- a/src/eidps.c +++ b/src/eidps.c @@ -975,6 +975,8 @@ int main(int argc, char **argv) DecodePPPoERegisterTests(); DecodeICMPV4RegisterTests(); DecodeIPV4RegisterTests(); + DecodeTCPRegisterTests(); + DecodeUDPV4RegisterTests(); DecodeGRERegisterTests(); AlpDetectRegisterTests(); ConfRegisterTests();