/* * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "TestsUtils.h" #include "IPv4Packet.h" #include "memory.h" using namespace IPA; static const unsigned char TCP_IP_PACKET_DUMP[] = { 0x45, // IPv4, IHL = 5 0x00, // ToS = 0 0x00, 0x28, // Total length 0x11, 0xc2, // ID 0x40, 0x00, //ID + Fragment Offset 0x80, // TTL 0x06, // Protocol = TCP 0x70, 0x3a, //Checksum 0x0a, 0x05, 0x07, 0x46, // Source IP 10.5.7.70 0x81, 0x2e, 0xe6, 0x5a, // Destination IP 129.46.230.90 0xf3, 0xa2, // Source Port 62370 0x01, 0xbd, // Destination Port 445 0x26, 0x26, 0x1d, 0x7d, // Seq Number 0x15, 0xaa, 0xbc, 0xdb, // Ack Num 0x50, 0x10, 0x80, 0xd4, // TCP Params 0xaa, 0xa3, // TCP Checksum 0x00, 0x00 // Urgent PTR }; static const unsigned char UDP_IP_PACKET_DUMP[] = { 0x45, // IPv4, IHL = 5 0x00, // ToS = 0 0x00, 0x34, // Total Length 0x12, 0xa2, // ID 0x00, 0x00, //ID + fragment offset 0x80, // TTL 0x11, // Protocol = UDP 0xe4, 0x92, // Checksum 0x0a, 0x05, 0x07, 0x46, // Source IP 10.5.7.70 0x0a, 0x2b, 0x28, 0x0f, // Destination IP 10.43.40.15 0x03, 0x4a, // Source port 842 0x1b, 0x4f, // Destination Port 6991 0x00, 0x20, // UDP length 0x36, 0xac, // UDP checksum 0x00, 0x05, 0x20, 0x6d, // Data 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x13, 0x05, 0x20, 0x6c }; static unsigned char ICMP_IP_PACKET_DUMP[] = { //IP 0x45, 0x00, 0x00, 0xdc, 0x03, 0xfe, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x81, 0x2e, 0xe4, 0xf6, 0x81, 0x2e, 0xe6, 0xd4, //ICMP 0x00, 0x00, 0xa9, 0xcd, 0x28, 0xa3, 0x01, 0x00, //DATA 0xee, 0x7c, 0xf7, 0x90, 0x39, 0x06, 0xd4, 0x41, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51 }; static void LittleToBigEndianUint32(unsigned char *pBigEndianBuffer, unsigned int nUint32LittleEndianValue) { unsigned char nLsb = nUint32LittleEndianValue & 0xff; unsigned char nLsbMsbLow = (nUint32LittleEndianValue >> 8) & 0xff; unsigned char nLsbMsbHigh = (nUint32LittleEndianValue >> 16) & 0xff; unsigned char nMsb = (nUint32LittleEndianValue >> 24) & 0xff; pBigEndianBuffer[0] = nMsb; pBigEndianBuffer[1] = nLsbMsbHigh; pBigEndianBuffer[2] = nLsbMsbLow; pBigEndianBuffer[3] = nLsb; } static unsigned short BigToLittleEndianUint16(unsigned char *pBigEndianStart) { unsigned char nMsb = pBigEndianStart[0]; unsigned char nLsb = pBigEndianStart[1]; return (nMsb << 8 | nLsb << 0); } static unsigned int BigToLittleEndianUint32(unsigned char *pBigEndianStart) { unsigned char nMsb = pBigEndianStart[0]; unsigned char nMsbLsbHigh = pBigEndianStart[1]; unsigned char nMsbLsbLow = pBigEndianStart[2]; unsigned char nLsb = pBigEndianStart[3]; return (nMsb << 24 | nMsbLsbHigh << 16 | nMsbLsbLow << 8 | nLsb << 0); } static void LittleToBigEndianUint16(unsigned char *pBigEndianBuffer, unsigned int nUint16LittleEndianValue) { unsigned char nLsb = nUint16LittleEndianValue & 0xff; unsigned char nMsb = (nUint16LittleEndianValue >> 8) & 0xff; pBigEndianBuffer[0] = nMsb; pBigEndianBuffer[1] = nLsb; } static unsigned short Get2BBIGEndian(const unsigned char *pBuff, int offset) { unsigned char upperByte = 0; unsigned char lowerByte = 0; memcpy(&upperByte, pBuff + offset, 1); memcpy(&lowerByte, pBuff + offset + 1, 1); return (upperByte << 8 | lowerByte); } IPv4Packet::IPv4Packet(unsigned int size) : m_PacketSize(size) { } IPv4Packet::~IPv4Packet(void) { if (0 != m_Packet) { delete[] m_Packet; m_Packet = 0; } } void IPv4Packet::ToNetworkByteStream(unsigned char *buffer) { if (0 == buffer) { LOG_MSG_ERROR("IPv4Packet::ToNetworkByteStream : NULL arguments"); return; } memcpy(buffer, m_Packet, GetSize()); } unsigned int IPv4Packet::GetSrcAddr(void) { return BigToLittleEndianUint32(m_Packet + 12); } void IPv4Packet::SetSrcAddr(unsigned int addr) { LittleToBigEndianUint32(m_Packet + 12, addr); RecalculateChecksum(); } unsigned int IPv4Packet::GetDstAddr(void) { return BigToLittleEndianUint32(m_Packet + 16); } void IPv4Packet::SetDstAddr(unsigned int addr) { LittleToBigEndianUint32(m_Packet + 16, addr); RecalculateChecksum(); } unsigned char IPv4Packet::GetProtocol(void) { unsigned char retVal = 0; memcpy(&retVal, m_Packet + 9, sizeof(unsigned char)); return retVal; } unsigned short IPv4Packet::GetSrcPort(void) { return BigToLittleEndianUint16(m_Packet + 20); } unsigned short IPv4Packet::GetDstPort(void) { return BigToLittleEndianUint16(m_Packet + 22); } void IPv4Packet::SetDstPort(unsigned short port) { LittleToBigEndianUint16(m_Packet + 22, port); RecalculateChecksum(); } void IPv4Packet::SetSrcPort(unsigned short port) { LittleToBigEndianUint16(m_Packet + 20, port); RecalculateChecksum(); } /////////////////////////////////////////////////////////////////////////////// //Set the third MSB bit of the IPV4_FLAGS_BYTE_OFFSET's byte void IPv4Packet::SetMF(bool bValue) { Byte * pFlags = m_Packet + IPV4_FLAGS_BYTE_OFFSET; //clear the bit if (true == bValue) { *pFlags |= (0x20); } else { *pFlags &= (~0x20); } } /////////////////////////////////////////////////////////////////////////////// void IPv4Packet::RecalculateChecksum(void) { RecalculateIPChecksum(); RecalculateTCPChecksum(); RecalculateUDPChecksum(); } void IPv4Packet::RecalculateIPChecksum(void) { unsigned short pUint16[100]; int headerLen = (m_Packet[0] & 0x0F) * 2; int checksum = 0; unsigned short result = 0; memset(&pUint16, 0, 100 * sizeof(unsigned short)); //clear the IP checksum field first memset(m_Packet + 10, 0, sizeof(unsigned short)); memcpy(&pUint16, m_Packet, headerLen * sizeof(unsigned short)); for (int i = 0; i < headerLen; i++) { checksum += pUint16[i]; checksum = (checksum & 0xFFFF) + (checksum >> 16); } result = (~checksum & 0xFFFF); memcpy(m_Packet + 10, &result, sizeof(unsigned short)); return; } void TCPPacket::RecalculateTCPChecksum(void) { unsigned short *pUint16 = new unsigned short[100]; int checksum = 0; int headerLen = 0; unsigned short *pTemp = 0; unsigned short result = 0; headerLen = Get2BBIGEndian(m_Packet, 2) - (m_Packet[0] & 0x0F) * 4; memset(pUint16, 0, 100); //clear the TCP checksum field first memset(m_Packet + 36, 0, sizeof(unsigned short)); memcpy(pUint16, m_Packet, headerLen * sizeof(unsigned short)); pTemp = pUint16; // Pseudo Header pUint16 += 6; // Source IP for (int i = 0; i < 4; i++) { checksum += pUint16[i]; checksum = (checksum & 0xFFFF) + (checksum >> 16); } checksum += 0x0600; // TCP Protocol checksum += Get2BBIGEndian((unsigned char*) &headerLen, 0); pUint16 = pTemp + (m_Packet[0] & 0x0F) * 2; headerLen /= 2; for (int i = 0; i < headerLen; i++) { checksum += pUint16[i]; checksum = (checksum & 0xFFFF) + (checksum >> 16); } result = (~checksum & 0xFFFF); memcpy(m_Packet + 36, &result, sizeof(unsigned short)); delete[] pTemp; return; } void UDPPacket::RecalculateUDPChecksum(void) { unsigned short *pUint16 = new unsigned short[100]; int checksum = 0; int headerLen = 0; unsigned short *pTemp = 0; unsigned short result = 0; headerLen = Get2BBIGEndian(m_Packet, (m_Packet[0] & 0x0F) * 4 + 4); memset(pUint16, 0, 100); //clear the UDP checksum field first memset(m_Packet + 26, 0, sizeof(unsigned short)); memcpy(pUint16, m_Packet, headerLen * sizeof(unsigned short)); pTemp = pUint16; // Pseudo Header pUint16 += 6; // Source IP for (int i = 0; i < 4; i++) { checksum += pUint16[i]; checksum = (checksum & 0xFFFF) + (checksum >> 16); } checksum += 0x1100; // UDP Protocol checksum += Get2BBIGEndian((unsigned char*) &headerLen, 0); pUint16 = pTemp + (m_Packet[0] & 0x0F) * 2; headerLen /= 2; for (int i = 0; i < headerLen; i++) { checksum += pUint16[i]; checksum = (checksum & 0xFFFF) + (checksum >> 16); } result = (~checksum & 0xFFFF); memcpy(m_Packet + 26, &result, sizeof(unsigned short)); delete[] pTemp; return; } TCPPacket::TCPPacket(void) : IPv4Packet(sizeof(TCP_IP_PACKET_DUMP)) { size_t length = GetSize(); m_Packet = new unsigned char[length]; if (0 == m_Packet) { LOG_MSG_ERROR("TCPPacket : packet allocation failed"); return; } memcpy(m_Packet, TCP_IP_PACKET_DUMP, length); } UDPPacket::UDPPacket(void) : IPv4Packet(sizeof(UDP_IP_PACKET_DUMP)) { size_t length = GetSize(); m_Packet = new unsigned char[length]; if (0 == m_Packet) { LOG_MSG_ERROR("UDPPacket : packet allocation failed"); return; } memcpy(m_Packet, UDP_IP_PACKET_DUMP, length); } ICMPPacket::ICMPPacket(void) : IPv4Packet(sizeof(ICMP_IP_PACKET_DUMP)) { size_t length = GetSize(); m_Packet = new unsigned char[length]; if (0 == m_Packet) { LOG_MSG_ERROR("ICMPPacket : packet allocation failed"); return; } memcpy(m_Packet, ICMP_IP_PACKET_DUMP, length); } unsigned short ICMPPacket::GetSrcPort(void) { return 0; } unsigned short ICMPPacket::GetDstPort(void) { return 0; } void ICMPPacket::SetDstPort(unsigned short port) { (void) port; return; } void ICMPPacket::SetSrcPort(unsigned short port) { (void) port; return; }