From 5285bc36efa8110de47db2d05cc39b32ce6e4cac Mon Sep 17 00:00:00 2001 From: Pavel Odintsov Date: Sun, 2 Aug 2020 12:04:37 +0100 Subject: [PATCH] Added new structures for network packets processing #833 (#834) --- src/CMakeLists.txt | 7 +- src/iana_ethertypes.h | 12 + src/iana_ip_protocols.h | 522 ++++++++++++++++++++++++++++ src/network_data_structures.cpp | 18 + src/network_data_structures.hpp | 581 ++++++++++++++++++++++++++++++++ 5 files changed, 1139 insertions(+), 1 deletion(-) create mode 100644 src/iana_ethertypes.h create mode 100644 src/iana_ip_protocols.h create mode 100644 src/network_data_structures.cpp create mode 100644 src/network_data_structures.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4e9833e6..dcf415e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -236,8 +236,13 @@ if (ENABLE_AFPACKET_SUPPORT) target_link_libraries(afpacket_plugin unified_parser) endif() +add_library(network_data_structures STATIC network_data_structures.cpp) + # sFLOW plugin -add_library(sflow_plugin STATIC sflow_plugin/sflow_collector.cpp) +add_library(sflow_plugin STATIC sflow_plugin/sflow_collector.cpp) + +# Link sFlow plugin with new network data structures parser +target_link_libraries(sflow_plugin network_data_structures) # netflow plugin add_library(netflow_plugin STATIC netflow_plugin/netflow_collector.cpp) diff --git a/src/iana_ethertypes.h b/src/iana_ethertypes.h new file mode 100644 index 00000000..edbe8f18 --- /dev/null +++ b/src/iana_ethertypes.h @@ -0,0 +1,12 @@ +#pragma once +enum IanaEthertype : unsigned int { + + IanaEthertypeIPv4 = 2048, + IanaEthertypeARP = 2054, + IanaEthertypeVLAN = 33024, + IanaEthertypeIPv6 = 34525, + IanaEthertypeMPLS_unicast = 34887, + IanaEthertypeMPLS_multicast = 34888, + IanaEthertypePPPoE_discovery = 34915, + IanaEthertypePPPoE_session = 34916, +}; diff --git a/src/iana_ip_protocols.h b/src/iana_ip_protocols.h new file mode 100644 index 00000000..471a1acc --- /dev/null +++ b/src/iana_ip_protocols.h @@ -0,0 +1,522 @@ +#pragma once +const char* get_ip_protocol_name_by_number_iana(unsigned int protocol_number); +enum class IpProtocolNumber : unsigned int { + HOPOPT = 0, + ICMP = 1, + IGMP = 2, + GGP = 3, + IPV4 = 4, + ST = 5, + TCP = 6, + CBT = 7, + EGP = 8, + IGP = 9, + BBN_RCC_MON = 10, + NVP_II = 11, + PUP = 12, + ARGUS_DEPRECATED = 13, + EMCON = 14, + XNET = 15, + CHAOS = 16, + UDP = 17, + MUX = 18, + DCN_MEAS = 19, + HMP = 20, + PRM = 21, + XNS_IDP = 22, + TRUNK_1 = 23, + TRUNK_2 = 24, + LEAF_1 = 25, + LEAF_2 = 26, + RDP = 27, + IRTP = 28, + ISO_TP4 = 29, + NETBLT = 30, + MFE_NSP = 31, + MERIT_INP = 32, + DCCP = 33, + THREEPC = 34, + IDPR = 35, + XTP = 36, + DDP = 37, + IDPR_CMTP = 38, + TPPPPP = 39, + IL = 40, + IPV6 = 41, + SDRP = 42, + IPV6_ROUTE = 43, + IPV6_FRAG = 44, + IDRP = 45, + RSVP = 46, + GRE = 47, + DSR = 48, + BNA = 49, + ESP = 50, + AH = 51, + I_NLSP = 52, + SWIPE_DEPRECATED = 53, + NARP = 54, + MOBILE = 55, + TLSP = 56, + SKIP = 57, + IPV6_ICMP = 58, + IPV6_NONXT = 59, + IPV6_OPTS = 60, + UNKNOWN_61 = 61, + CFTP = 62, + UNKNOWN_63 = 63, + SAT_EXPAK = 64, + KRYPTOLAN = 65, + RVD = 66, + IPPC = 67, + UNKNOWN_68 = 68, + SAT_MON = 69, + VISA = 70, + IPCV = 71, + CPNX = 72, + CPHB = 73, + WSN = 74, + PVP = 75, + BR_SAT_MON = 76, + SUN_ND = 77, + WB_MON = 78, + WB_EXPAK = 79, + ISO_IP = 80, + VMTP = 81, + SECURE_VMTP = 82, + VINES = 83, + IPTM_OR_TTP = 84, + NSFNET_IGP = 85, + DGP = 86, + TCF = 87, + EIGRP = 88, + OSPFIGP = 89, + SPRITE_RPC = 90, + LARP = 91, + MTP = 92, + AX_25 = 93, + IPIP = 94, + MICP_DEPRECATED = 95, + SCC_SP = 96, + ETHERIP = 97, + ENCAP = 98, + UNKNOWN_99 = 99, + GMTP = 100, + IFMP = 101, + PNNI = 102, + PIM = 103, + ARIS = 104, + SCPS = 105, + QNX = 106, + A_N = 107, + IPCOMP = 108, + SNP = 109, + COMPAQ_PEER = 110, + IPX_IN_IP = 111, + VRRP = 112, + PGM = 113, + UNKNOWN_114 = 114, + L2TP = 115, + DDX = 116, + IATP = 117, + STP = 118, + SRP = 119, + UTI = 120, + SMP = 121, + SM_DEPRECATED = 122, + PTP = 123, + ISISOVERIPV4 = 124, + FIRE = 125, + CRTP = 126, + CRUDP = 127, + SSCOPMCE = 128, + IPLT = 129, + SPS = 130, + PIPE = 131, + SCTP = 132, + FC = 133, + RSVP_E2E_IGNORE = 134, + MOBILITYHEADER = 135, + UDPLITE = 136, + MPLS_IN_IP = 137, + MANET = 138, + HIP = 139, + SHIM6 = 140, + WESP = 141, + ROHC = 142, + UNKNOWN_143 = 143, + UNKNOWN_144 = 144, + UNKNOWN_145 = 145, + UNKNOWN_146 = 146, + UNKNOWN_147 = 147, + UNKNOWN_148 = 148, + UNKNOWN_149 = 149, + UNKNOWN_150 = 150, + UNKNOWN_151 = 151, + UNKNOWN_152 = 152, + UNKNOWN_153 = 153, + UNKNOWN_154 = 154, + UNKNOWN_155 = 155, + UNKNOWN_156 = 156, + UNKNOWN_157 = 157, + UNKNOWN_158 = 158, + UNKNOWN_159 = 159, + UNKNOWN_160 = 160, + UNKNOWN_161 = 161, + UNKNOWN_162 = 162, + UNKNOWN_163 = 163, + UNKNOWN_164 = 164, + UNKNOWN_165 = 165, + UNKNOWN_166 = 166, + UNKNOWN_167 = 167, + UNKNOWN_168 = 168, + UNKNOWN_169 = 169, + UNKNOWN_170 = 170, + UNKNOWN_171 = 171, + UNKNOWN_172 = 172, + UNKNOWN_173 = 173, + UNKNOWN_174 = 174, + UNKNOWN_175 = 175, + UNKNOWN_176 = 176, + UNKNOWN_177 = 177, + UNKNOWN_178 = 178, + UNKNOWN_179 = 179, + UNKNOWN_180 = 180, + UNKNOWN_181 = 181, + UNKNOWN_182 = 182, + UNKNOWN_183 = 183, + UNKNOWN_184 = 184, + UNKNOWN_185 = 185, + UNKNOWN_186 = 186, + UNKNOWN_187 = 187, + UNKNOWN_188 = 188, + UNKNOWN_189 = 189, + UNKNOWN_190 = 190, + UNKNOWN_191 = 191, + UNKNOWN_192 = 192, + UNKNOWN_193 = 193, + UNKNOWN_194 = 194, + UNKNOWN_195 = 195, + UNKNOWN_196 = 196, + UNKNOWN_197 = 197, + UNKNOWN_198 = 198, + UNKNOWN_199 = 199, + UNKNOWN_200 = 200, + UNKNOWN_201 = 201, + UNKNOWN_202 = 202, + UNKNOWN_203 = 203, + UNKNOWN_204 = 204, + UNKNOWN_205 = 205, + UNKNOWN_206 = 206, + UNKNOWN_207 = 207, + UNKNOWN_208 = 208, + UNKNOWN_209 = 209, + UNKNOWN_210 = 210, + UNKNOWN_211 = 211, + UNKNOWN_212 = 212, + UNKNOWN_213 = 213, + UNKNOWN_214 = 214, + UNKNOWN_215 = 215, + UNKNOWN_216 = 216, + UNKNOWN_217 = 217, + UNKNOWN_218 = 218, + UNKNOWN_219 = 219, + UNKNOWN_220 = 220, + UNKNOWN_221 = 221, + UNKNOWN_222 = 222, + UNKNOWN_223 = 223, + UNKNOWN_224 = 224, + UNKNOWN_225 = 225, + UNKNOWN_226 = 226, + UNKNOWN_227 = 227, + UNKNOWN_228 = 228, + UNKNOWN_229 = 229, + UNKNOWN_230 = 230, + UNKNOWN_231 = 231, + UNKNOWN_232 = 232, + UNKNOWN_233 = 233, + UNKNOWN_234 = 234, + UNKNOWN_235 = 235, + UNKNOWN_236 = 236, + UNKNOWN_237 = 237, + UNKNOWN_238 = 238, + UNKNOWN_239 = 239, + UNKNOWN_240 = 240, + UNKNOWN_241 = 241, + UNKNOWN_242 = 242, + UNKNOWN_243 = 243, + UNKNOWN_244 = 244, + UNKNOWN_245 = 245, + UNKNOWN_246 = 246, + UNKNOWN_247 = 247, + UNKNOWN_248 = 248, + UNKNOWN_249 = 249, + UNKNOWN_250 = 250, + UNKNOWN_251 = 251, + UNKNOWN_252 = 252, + UNKNOWN_253 = 253, + UNKNOWN_254 = 254, + RESERVED = 255, + BROKEN_PROTOCOL = 256 +}; + +enum IpProtocolNumberNotTyped : unsigned int { + IpProtocolNumberHOPOPT = 0, + IpProtocolNumberICMP = 1, + IpProtocolNumberIGMP = 2, + IpProtocolNumberGGP = 3, + IpProtocolNumberIPV4 = 4, + IpProtocolNumberST = 5, + IpProtocolNumberTCP = 6, + IpProtocolNumberCBT = 7, + IpProtocolNumberEGP = 8, + IpProtocolNumberIGP = 9, + IpProtocolNumberBBN_RCC_MON = 10, + IpProtocolNumberNVP_II = 11, + IpProtocolNumberPUP = 12, + IpProtocolNumberARGUS_DEPRECATED = 13, + IpProtocolNumberEMCON = 14, + IpProtocolNumberXNET = 15, + IpProtocolNumberCHAOS = 16, + IpProtocolNumberUDP = 17, + IpProtocolNumberMUX = 18, + IpProtocolNumberDCN_MEAS = 19, + IpProtocolNumberHMP = 20, + IpProtocolNumberPRM = 21, + IpProtocolNumberXNS_IDP = 22, + IpProtocolNumberTRUNK_1 = 23, + IpProtocolNumberTRUNK_2 = 24, + IpProtocolNumberLEAF_1 = 25, + IpProtocolNumberLEAF_2 = 26, + IpProtocolNumberRDP = 27, + IpProtocolNumberIRTP = 28, + IpProtocolNumberISO_TP4 = 29, + IpProtocolNumberNETBLT = 30, + IpProtocolNumberMFE_NSP = 31, + IpProtocolNumberMERIT_INP = 32, + IpProtocolNumberDCCP = 33, + IpProtocolNumberTHREEPC = 34, + IpProtocolNumberIDPR = 35, + IpProtocolNumberXTP = 36, + IpProtocolNumberDDP = 37, + IpProtocolNumberIDPR_CMTP = 38, + IpProtocolNumberTPPPPP = 39, + IpProtocolNumberIL = 40, + IpProtocolNumberIPV6 = 41, + IpProtocolNumberSDRP = 42, + IpProtocolNumberIPV6_ROUTE = 43, + IpProtocolNumberIPV6_FRAG = 44, + IpProtocolNumberIDRP = 45, + IpProtocolNumberRSVP = 46, + IpProtocolNumberGRE = 47, + IpProtocolNumberDSR = 48, + IpProtocolNumberBNA = 49, + IpProtocolNumberESP = 50, + IpProtocolNumberAH = 51, + IpProtocolNumberI_NLSP = 52, + IpProtocolNumberSWIPE_DEPRECATED = 53, + IpProtocolNumberNARP = 54, + IpProtocolNumberMOBILE = 55, + IpProtocolNumberTLSP = 56, + IpProtocolNumberSKIP = 57, + IpProtocolNumberIPV6_ICMP = 58, + IpProtocolNumberIPV6_NONXT = 59, + IpProtocolNumberIPV6_OPTS = 60, + IpProtocolNumberUNKNOWN_61 = 61, + IpProtocolNumberCFTP = 62, + IpProtocolNumberUNKNOWN_63 = 63, + IpProtocolNumberSAT_EXPAK = 64, + IpProtocolNumberKRYPTOLAN = 65, + IpProtocolNumberRVD = 66, + IpProtocolNumberIPPC = 67, + IpProtocolNumberUNKNOWN_68 = 68, + IpProtocolNumberSAT_MON = 69, + IpProtocolNumberVISA = 70, + IpProtocolNumberIPCV = 71, + IpProtocolNumberCPNX = 72, + IpProtocolNumberCPHB = 73, + IpProtocolNumberWSN = 74, + IpProtocolNumberPVP = 75, + IpProtocolNumberBR_SAT_MON = 76, + IpProtocolNumberSUN_ND = 77, + IpProtocolNumberWB_MON = 78, + IpProtocolNumberWB_EXPAK = 79, + IpProtocolNumberISO_IP = 80, + IpProtocolNumberVMTP = 81, + IpProtocolNumberSECURE_VMTP = 82, + IpProtocolNumberVINES = 83, + IpProtocolNumberIPTM_OR_TTP = 84, + IpProtocolNumberNSFNET_IGP = 85, + IpProtocolNumberDGP = 86, + IpProtocolNumberTCF = 87, + IpProtocolNumberEIGRP = 88, + IpProtocolNumberOSPFIGP = 89, + IpProtocolNumberSPRITE_RPC = 90, + IpProtocolNumberLARP = 91, + IpProtocolNumberMTP = 92, + IpProtocolNumberAX_25 = 93, + IpProtocolNumberIPIP = 94, + IpProtocolNumberMICP_DEPRECATED = 95, + IpProtocolNumberSCC_SP = 96, + IpProtocolNumberETHERIP = 97, + IpProtocolNumberENCAP = 98, + IpProtocolNumberUNKNOWN_99 = 99, + IpProtocolNumberGMTP = 100, + IpProtocolNumberIFMP = 101, + IpProtocolNumberPNNI = 102, + IpProtocolNumberPIM = 103, + IpProtocolNumberARIS = 104, + IpProtocolNumberSCPS = 105, + IpProtocolNumberQNX = 106, + IpProtocolNumberA_N = 107, + IpProtocolNumberIPCOMP = 108, + IpProtocolNumberSNP = 109, + IpProtocolNumberCOMPAQ_PEER = 110, + IpProtocolNumberIPX_IN_IP = 111, + IpProtocolNumberVRRP = 112, + IpProtocolNumberPGM = 113, + IpProtocolNumberUNKNOWN_114 = 114, + IpProtocolNumberL2TP = 115, + IpProtocolNumberDDX = 116, + IpProtocolNumberIATP = 117, + IpProtocolNumberSTP = 118, + IpProtocolNumberSRP = 119, + IpProtocolNumberUTI = 120, + IpProtocolNumberSMP = 121, + IpProtocolNumberSM_DEPRECATED = 122, + IpProtocolNumberPTP = 123, + IpProtocolNumberISISOVERIPV4 = 124, + IpProtocolNumberFIRE = 125, + IpProtocolNumberCRTP = 126, + IpProtocolNumberCRUDP = 127, + IpProtocolNumberSSCOPMCE = 128, + IpProtocolNumberIPLT = 129, + IpProtocolNumberSPS = 130, + IpProtocolNumberPIPE = 131, + IpProtocolNumberSCTP = 132, + IpProtocolNumberFC = 133, + IpProtocolNumberRSVP_E2E_IGNORE = 134, + IpProtocolNumberMOBILITYHEADER = 135, + IpProtocolNumberUDPLITE = 136, + IpProtocolNumberMPLS_IN_IP = 137, + IpProtocolNumberMANET = 138, + IpProtocolNumberHIP = 139, + IpProtocolNumberSHIM6 = 140, + IpProtocolNumberWESP = 141, + IpProtocolNumberROHC = 142, + IpProtocolNumberUNKNOWN_143 = 143, + IpProtocolNumberUNKNOWN_144 = 144, + IpProtocolNumberUNKNOWN_145 = 145, + IpProtocolNumberUNKNOWN_146 = 146, + IpProtocolNumberUNKNOWN_147 = 147, + IpProtocolNumberUNKNOWN_148 = 148, + IpProtocolNumberUNKNOWN_149 = 149, + IpProtocolNumberUNKNOWN_150 = 150, + IpProtocolNumberUNKNOWN_151 = 151, + IpProtocolNumberUNKNOWN_152 = 152, + IpProtocolNumberUNKNOWN_153 = 153, + IpProtocolNumberUNKNOWN_154 = 154, + IpProtocolNumberUNKNOWN_155 = 155, + IpProtocolNumberUNKNOWN_156 = 156, + IpProtocolNumberUNKNOWN_157 = 157, + IpProtocolNumberUNKNOWN_158 = 158, + IpProtocolNumberUNKNOWN_159 = 159, + IpProtocolNumberUNKNOWN_160 = 160, + IpProtocolNumberUNKNOWN_161 = 161, + IpProtocolNumberUNKNOWN_162 = 162, + IpProtocolNumberUNKNOWN_163 = 163, + IpProtocolNumberUNKNOWN_164 = 164, + IpProtocolNumberUNKNOWN_165 = 165, + IpProtocolNumberUNKNOWN_166 = 166, + IpProtocolNumberUNKNOWN_167 = 167, + IpProtocolNumberUNKNOWN_168 = 168, + IpProtocolNumberUNKNOWN_169 = 169, + IpProtocolNumberUNKNOWN_170 = 170, + IpProtocolNumberUNKNOWN_171 = 171, + IpProtocolNumberUNKNOWN_172 = 172, + IpProtocolNumberUNKNOWN_173 = 173, + IpProtocolNumberUNKNOWN_174 = 174, + IpProtocolNumberUNKNOWN_175 = 175, + IpProtocolNumberUNKNOWN_176 = 176, + IpProtocolNumberUNKNOWN_177 = 177, + IpProtocolNumberUNKNOWN_178 = 178, + IpProtocolNumberUNKNOWN_179 = 179, + IpProtocolNumberUNKNOWN_180 = 180, + IpProtocolNumberUNKNOWN_181 = 181, + IpProtocolNumberUNKNOWN_182 = 182, + IpProtocolNumberUNKNOWN_183 = 183, + IpProtocolNumberUNKNOWN_184 = 184, + IpProtocolNumberUNKNOWN_185 = 185, + IpProtocolNumberUNKNOWN_186 = 186, + IpProtocolNumberUNKNOWN_187 = 187, + IpProtocolNumberUNKNOWN_188 = 188, + IpProtocolNumberUNKNOWN_189 = 189, + IpProtocolNumberUNKNOWN_190 = 190, + IpProtocolNumberUNKNOWN_191 = 191, + IpProtocolNumberUNKNOWN_192 = 192, + IpProtocolNumberUNKNOWN_193 = 193, + IpProtocolNumberUNKNOWN_194 = 194, + IpProtocolNumberUNKNOWN_195 = 195, + IpProtocolNumberUNKNOWN_196 = 196, + IpProtocolNumberUNKNOWN_197 = 197, + IpProtocolNumberUNKNOWN_198 = 198, + IpProtocolNumberUNKNOWN_199 = 199, + IpProtocolNumberUNKNOWN_200 = 200, + IpProtocolNumberUNKNOWN_201 = 201, + IpProtocolNumberUNKNOWN_202 = 202, + IpProtocolNumberUNKNOWN_203 = 203, + IpProtocolNumberUNKNOWN_204 = 204, + IpProtocolNumberUNKNOWN_205 = 205, + IpProtocolNumberUNKNOWN_206 = 206, + IpProtocolNumberUNKNOWN_207 = 207, + IpProtocolNumberUNKNOWN_208 = 208, + IpProtocolNumberUNKNOWN_209 = 209, + IpProtocolNumberUNKNOWN_210 = 210, + IpProtocolNumberUNKNOWN_211 = 211, + IpProtocolNumberUNKNOWN_212 = 212, + IpProtocolNumberUNKNOWN_213 = 213, + IpProtocolNumberUNKNOWN_214 = 214, + IpProtocolNumberUNKNOWN_215 = 215, + IpProtocolNumberUNKNOWN_216 = 216, + IpProtocolNumberUNKNOWN_217 = 217, + IpProtocolNumberUNKNOWN_218 = 218, + IpProtocolNumberUNKNOWN_219 = 219, + IpProtocolNumberUNKNOWN_220 = 220, + IpProtocolNumberUNKNOWN_221 = 221, + IpProtocolNumberUNKNOWN_222 = 222, + IpProtocolNumberUNKNOWN_223 = 223, + IpProtocolNumberUNKNOWN_224 = 224, + IpProtocolNumberUNKNOWN_225 = 225, + IpProtocolNumberUNKNOWN_226 = 226, + IpProtocolNumberUNKNOWN_227 = 227, + IpProtocolNumberUNKNOWN_228 = 228, + IpProtocolNumberUNKNOWN_229 = 229, + IpProtocolNumberUNKNOWN_230 = 230, + IpProtocolNumberUNKNOWN_231 = 231, + IpProtocolNumberUNKNOWN_232 = 232, + IpProtocolNumberUNKNOWN_233 = 233, + IpProtocolNumberUNKNOWN_234 = 234, + IpProtocolNumberUNKNOWN_235 = 235, + IpProtocolNumberUNKNOWN_236 = 236, + IpProtocolNumberUNKNOWN_237 = 237, + IpProtocolNumberUNKNOWN_238 = 238, + IpProtocolNumberUNKNOWN_239 = 239, + IpProtocolNumberUNKNOWN_240 = 240, + IpProtocolNumberUNKNOWN_241 = 241, + IpProtocolNumberUNKNOWN_242 = 242, + IpProtocolNumberUNKNOWN_243 = 243, + IpProtocolNumberUNKNOWN_244 = 244, + IpProtocolNumberUNKNOWN_245 = 245, + IpProtocolNumberUNKNOWN_246 = 246, + IpProtocolNumberUNKNOWN_247 = 247, + IpProtocolNumberUNKNOWN_248 = 248, + IpProtocolNumberUNKNOWN_249 = 249, + IpProtocolNumberUNKNOWN_250 = 250, + IpProtocolNumberUNKNOWN_251 = 251, + IpProtocolNumberUNKNOWN_252 = 252, + IpProtocolNumberUNKNOWN_253 = 253, + IpProtocolNumberUNKNOWN_254 = 254, + IpProtocolNumberRESERVED = 255, +}; +IpProtocolNumber get_ip_protocol_enum_type_from_integer(int protocol_as_integer); +unsigned int get_ip_protocol_enum_as_number(IpProtocolNumber ip_protocol_enum); diff --git a/src/network_data_structures.cpp b/src/network_data_structures.cpp new file mode 100644 index 00000000..5349ca1a --- /dev/null +++ b/src/network_data_structures.cpp @@ -0,0 +1,18 @@ +#include "network_data_structures.hpp" +#include + +namespace network_data_stuctures { + +std::string parser_code_to_string(parser_code_t code) { + if (code == parser_code_t::memory_violation) { + return "memory_violation"; + } else if (code == parser_code_t::not_ipv4) { + return "not_ipv4"; + } else if (code == parser_code_t::success) { + return "success"; + } else { + return "unknown"; + } +} + +} // namespace network_data_stuctures diff --git a/src/network_data_structures.hpp b/src/network_data_structures.hpp new file mode 100644 index 00000000..f3ee4289 --- /dev/null +++ b/src/network_data_structures.hpp @@ -0,0 +1,581 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "iana_ethertypes.h" +#include "iana_ip_protocols.h" + +/* + * TODO: + * Add strict type check for ntohl/ntohs and ntonl/htons + * +*/ + +#include // ntohs, ntohl + +// This function could copy X bytes from src to dst. +// Where X - size of dst object (referenced by pointer) +template inline void* smart_memcpy(dst_type* dst, const src_type* src) { + return memcpy(dst, src, sizeof(dst_type)); +} + +namespace network_data_stuctures { +/* We are using this structure as pretty interface for IPv4 address bytes in + * host byte order (little + * endian) */ +struct __attribute__((__packed__)) ipv4_octets_form_little_endian_t { + uint8_t fourth; + uint8_t third; + uint8_t second; + uint8_t first; +}; + +// Convert IP as integer to string representation +inline std::string convert_ip_as_little_endian_to_string(uint32_t ip) { + /* + Actually we could use inet_ntoa but it's implementation uses not very + convenient data + structures (struct in_addr) + Also it has multi thread issues (because it's using common buffer) and it + solved by thread + local storage. + Which could produce performance issues too (chec http://www.agner.org) + + Here you could + https://github.com/bminor/glibc/blob/0a1f1e78fbdfaf2c01e9c2368023b2533e7136cf/inet/inet_ntoa.c#L31 + And has known performance issues: https://github.com/h2o/qrintf + I decided to implement it manually + */ + + const size_t max_ip_as_string_size = 16; // Maximum string length as integer + char buffer[max_ip_as_string_size]; + + ipv4_octets_form_little_endian_t* ipv4_octets = (ipv4_octets_form_little_endian_t*)&ip; + + snprintf(buffer, max_ip_as_string_size, "%d.%d.%d.%d", ipv4_octets->first, ipv4_octets->second, ipv4_octets->third, + ipv4_octets->fourth); + + return std::string(buffer); +} + +// Here we are using very cryptic form of pointer to fixed size array +inline std::string convert_mac_to_string(uint8_t (&mac_as_array)[6]) { + std::stringstream buffer; + + for (int i = 0; i < 6; i++) { + buffer << std::hex << std::setfill('0') << std::setw(2) << int(mac_as_array[i]); + + if (i != 5) { + buffer << ":"; + } + } + + return buffer.str(); +} + +// TODO: it's not finished yet +class __attribute__((__packed__)) mpls_label_t { + public: + uint32_t label : 20, qos : 3, bottom_of_stack : 1, ttl : 8; + + std::string print() { + std::stringstream buffer; + + buffer << "label: " << uint32_t(label) << " " + << "qos: " << uint32_t(qos) << " " + << "bottom of stack: " << uint32_t(bottom_of_stack) << " " + << "ttl: " << uint32_t(ttl); + + return buffer.str(); + } +}; + +static_assert(sizeof(mpls_label_t) == 4, "Bad size for mpls_label_t"); + +// We are storing vlan meta data and next ethertype in same packet +// It's not standard approach! Be careful! +class __attribute__((__packed__)) ethernet_vlan_header_t { + public: + union { + __extension__ struct { uint16_t vlan_id : 12, cfi : 1, priority : 3; }; + uint16_t vlan_metadata_as_integer; + }; + + uint16_t ethertype; + + void convert() { + ethertype = ntohs(ethertype); + vlan_metadata_as_integer = ntohs(vlan_metadata_as_integer); + } + + std::string print() { + std::stringstream buffer; + + buffer << "priority: " << uint32_t(priority) << " " + << "cfi: " << uint32_t(cfi) << " " + << "vlan_id: " << uint32_t(vlan_id) << " " + << "ethertype: " << ethertype; + + return buffer.str(); + } +}; + +static_assert(sizeof(ethernet_vlan_header_t) == 4, "Bad size for ethernet_vlan_header_t"); + +class __attribute__((__packed__)) ethernet_header_t { + public: + uint8_t destination_mac[6]; + uint8_t source_mac[6]; + uint16_t ethertype; + + void convert() { + ethertype = ntohs(ethertype); + } + + std::string print() { + std::stringstream buffer; + + buffer << "ethertype: 0x" << std::setfill('0') << std::setw(4) << std::hex << ethertype << " " + << "source mac: " << convert_mac_to_string(source_mac) << " " + << "destination mac: " << convert_mac_to_string(destination_mac); + + return buffer.str(); + } +}; + +static_assert(sizeof(ethernet_header_t) == 14, "Bad size for ethernet_header_t"); + +// Please be careful! +// This structure will work only for IPv4 (4 byte address) + ethernet (6 byte +// address) +class __attribute__((__packed__)) arp_header_t { + public: + uint16_t hardware_type; + uint16_t protocol_type; + + uint8_t hardware_address_length; + uint8_t protocol_address_length; + + uint16_t operation; + uint8_t sender_hardware_address[6]; + uint32_t sender_protocol_address; + uint8_t target_hardware_address[6]; + uint32_t target_protocol_address; + + void convert() { + // 16 bit + hardware_type = ntohs(hardware_type); + protocol_type = ntohs(protocol_type); + operation = ntohs(operation); + + // 32 bit + sender_protocol_address = ntohl(sender_protocol_address); + target_protocol_address = ntohl(target_protocol_address); + } + + std::string print() { + std::stringstream buffer; + + buffer << "hardware_type: " << uint32_t(hardware_type) << " " + << "protocol_type: " << uint32_t(protocol_type) << " " + << "hardware_address_length: " << uint32_t(hardware_address_length) << " " + << "protocol_address_length: " << uint32_t(protocol_address_length) << " " + << "operation: " << uint32_t(operation) << " " + << "sender_hardware_address: " << convert_mac_to_string(sender_hardware_address) << " " + << "sender_protocol_address: " << convert_ip_as_little_endian_to_string(sender_protocol_address) << " " + << "target_hardware_address: " << convert_mac_to_string(target_hardware_address) << " " + << "target_protocol_address: " << convert_ip_as_little_endian_to_string(target_protocol_address); + + return buffer.str(); + } +}; + +class __attribute__((__packed__)) icmp_header_t { + public: + uint8_t type; + uint8_t code; + uint16_t checksum; + uint32_t rest_of_header; + + void convert() { + checksum = htons(checksum); + } + + std::string print() { + std::stringstream buffer; + + buffer << "type: " << uint32_t(type) << " " + << "code: " << uint32_t(code) << " " + << "checksum: " << uint32_t(checksum); + + return buffer.str(); + } +}; + +class __attribute__((__packed__)) udp_header_t { + public: + uint16_t source_port; + uint16_t destination_port; + uint16_t length; + uint16_t checksum; + + void convert() { + source_port = ntohs(source_port); + destination_port = ntohs(destination_port); + length = ntohs(length); + checksum = ntohs(checksum); + } + + std::string print() { + std::stringstream buffer; + + buffer << "source_port: " << source_port << " " + << "destination_port: " << destination_port << " " + << "length: " << length << " " + << "cheksum: " << checksum; + + return buffer.str(); + } +}; + +static_assert(sizeof(udp_header_t) == 8, "Bad size for udp_header_t"); + +// It's tcp packet flags represented as bitfield for user friendly access to this flags +class __attribute__((__packed__)) tcp_flags_as_uint16_t { + public: + uint16_t fin : 1, syn : 1, rst : 1, psh : 1, ack : 1, urg : 1, ece : 1, cwr : 1, ns : 1, reserved : 3, data_offset : 4; + + std::string print() { + std::stringstream buffer; + + buffer << "data_offset: " << uint32_t(data_offset) << " " + << "reserved: " << uint32_t(reserved) << " " + << "ns: " << uint32_t(ns) << " " + << "cwr: " << uint32_t(cwr) << " " + << "ece: " << uint32_t(ece) << " " + << "urg: " << uint32_t(urg) << " " + << "ack: " << uint32_t(ack) << " " + << "psh: " << uint32_t(psh) << " " + << "rst: " << uint32_t(rst) << " " + << "syn: " << uint32_t(syn) << " " + << "fin: " << uint32_t(fin); + + return buffer.str(); + } +}; + +// It's another version of previous code suitable for nice casting from 32 bit +class __attribute__((__packed__)) tcp_flags_as_uint32_t { + public: + tcp_flags_as_uint16_t data; + uint16_t not_used1; + uint8_t not_used2; + std::string print() { + return data.print(); + } +}; + +class __attribute__((__packed__)) tcp_header_t { + public: + uint16_t source_port; + uint16_t destination_port; + uint32_t sequence_number; + uint32_t ack_number; + union { + __extension__ struct __attribute__((__packed__)) { + // uint16_t data_offset : 4, reserved : 3, ns : 1, cwr : 1, ece : 1, urg : + // 1, ack : 1, + // psh : 1, rst : 1, syn : 1, fin : 1; + uint16_t fin : 1, syn : 1, rst : 1, psh : 1, ack : 1, urg : 1, ece : 1, cwr : 1, ns : 1, reserved : 3, data_offset : 4; + }; + + uint16_t data_offset_and_flags_as_integer; + }; + uint16_t window_size; + uint16_t checksum; + uint16_t urgent; + + void convert() { + // 16 bit data + source_port = ntohs(source_port); + destination_port = ntohs(destination_port); + window_size = ntohs(window_size); + checksum = ntohs(checksum); + urgent = ntohs(urgent); + + data_offset_and_flags_as_integer = ntohs(data_offset_and_flags_as_integer); + + // 32 bit data + sequence_number = ntohl(sequence_number); + ack_number = ntohl(ack_number); + } + + std::string print() { + std::stringstream buffer; + + buffer << "source_port: " << source_port << " " + << "destination_port: " << destination_port << " " + << "sequence_number: " << sequence_number << " " + << "ack_number: " << ack_number << " " + << "data_offset: " << uint32_t(data_offset) << " " + << "reserved: " << uint32_t(reserved) << " " + << "ns: " << uint32_t(ns) << " " + << "cwr: " << uint32_t(cwr) << " " + << "ece: " << uint32_t(ece) << " " + << "urg: " << uint32_t(urg) << " " + << "ack: " << uint32_t(ack) << " " + << "psh: " << uint32_t(psh) << " " + << "rst: " << uint32_t(rst) << " " + << "syn: " << uint32_t(syn) << " " + << "fin: " << uint32_t(fin) << " " + << "window_size: " << window_size << " " + << "checksum: " << checksum << " " + << "urgent: " << urgent; + + return buffer.str(); + } +}; + +static_assert(sizeof(tcp_header_t) == 20, "Bad size for tcp_header_t"); + +typedef uint8_t ipv6_address[16]; + +// Custom type for pretty printing +typedef uint16_t ipv6_address_16bit_blocks[8]; + +inline std::string convert_ipv6_in_big_endian_to_string(uint8_t (&v6_address)[16]) { + std::stringstream buffer; + + uint16_t* pretty_print = (uint16_t*)v6_address; + + for (int i = 0; i < 8; i++) { + buffer << std::hex << ntohs(pretty_print[i]); + + if (i != 7) { + buffer << ":"; + } + } + + return buffer.str(); +} + +/* + For full IPv6 support we should implement following option types: + https://tools.ietf.org/html/rfc2460#page-7 + + Hop-by-Hop Options - IpProtocolNumberHOPOPT + Routing (Type 0) - IpProtocolNumberIPV6_ROUTE + Fragment - IpProtocolNumberIPV6_FRAG + Destination Options - IpProtocolNumberIPV6_OPTS + Authentication - IpProtocolNumberAH + Encapsulating Security Payload - IpProtocolNumberESP +*/ + +/* IPv6 fragmentation header option */ +class __attribute__((__packed__)) ipv6_extention_header_fragment_t { + public: + uint8_t next_header; + uint8_t reserved1; + union { + __extension__ struct { + // uint16_t fragment_offset : 13, reserved2 : 2, more_fragments : 1; + uint16_t more_fragments : 1, reserved2 : 2, fragment_offset : 13; + }; + uint16_t fragmentation_and_flags_as_integer; + }; + + uint32_t identification; + + void convert() { + fragmentation_and_flags_as_integer = ntohs(fragmentation_and_flags_as_integer); + identification = ntohl(identification); + } + + std::string print() { + std::stringstream buffer; + + buffer << "next_header: " << uint32_t(next_header) << " " + << "reserved1: " << uint32_t(reserved1) << " " + << "fragment_offset: " << uint32_t(fragment_offset) << " " + << "reserverd2: " << uint32_t(reserved2) << " " + << "more_fragments: " << uint32_t(more_fragments) << " " + << "identification: " << identification; + + return buffer.str(); + } +}; + +static_assert(sizeof(ipv6_extention_header_fragment_t) == 8, "Bad size for ipv6_extention_header_fragment_t"); + +class __attribute__((__packed__)) ipv6_header_t { + public: + union { + __extension__ struct { uint32_t flow_label : 20, traffic_class : 8, version : 4; }; + + uint32_t version_and_traffic_class_as_integer; + }; + uint16_t payload_length; + uint8_t next_header; + uint8_t hop_limit; + ipv6_address source_address; + ipv6_address destination_address; + + void convert() { + payload_length = ntohs(payload_length); + version_and_traffic_class_as_integer = ntohl(version_and_traffic_class_as_integer); + } + + std::string print() { + std::stringstream buffer; + + buffer << "version: " << uint32_t(version) << " " + << "traffic_class: " << uint32_t(traffic_class) << " " + << "flow_label: " << uint32_t(flow_label) << " " + << "payload_length: " << uint32_t(payload_length) << " " + << "next_header: " << uint32_t(next_header) << " " + << "hop_limit: " << uint32_t(hop_limit) << " " + << "source_address: " << convert_ipv6_in_big_endian_to_string(source_address) << " " + << "destination_address: " << convert_ipv6_in_big_endian_to_string(destination_address); + + return buffer.str(); + } +}; + +static_assert(sizeof(ipv6_header_t) == 40, "Bad size for ipv6_header_t"); + +// It's class for fragmentation flag representation. It's pretty useful in some cases +class __attribute__((__packed__)) ipv4_header_fragmentation_flags_t { + public: + union { + // We should store bitfields in nested struct. Othervise each of bitfields + // will use same + // storage as each other! + // We are using GCC extension here. It's working perfectly for clang and gcc + // but could + // produce warning in pedantic mode + __extension__ struct { + uint16_t fragment_offset : 13, more_fragments_flag : 1, dont_fragment_flag : 1, reserved_flag : 1; + }; + + uint16_t fragmentation_details_as_integer; + }; + + std::string print() { + + std::stringstream buffer; + buffer << "fragment_offset: " << uint32_t(fragment_offset) << " " + << "reserved_flag: " << uint32_t(reserved_flag) << " " + << "dont_fragment_flag: " << uint32_t(dont_fragment_flag) << " " + << "more_fragments_flag: " << uint32_t(more_fragments_flag); + + return buffer.str(); + } +}; + +// It's another version of previous code suitable for nice casting from 32 bit +class __attribute__((__packed__)) ipv4_header_fragmentation_flags_as_32bit_t { + public: + ipv4_header_fragmentation_flags_t data; + uint16_t not_used1; + + std::string print() { + return data.print(); + } +}; + +class __attribute__((__packed__)) ipv4_header_t { + public: + uint8_t ihl : 4, version : 4; + uint8_t ecn : 2, dscp : 6; + + // This is the combined length of the header and the data + uint16_t total_length; + uint16_t identification; + + union { + // We should store bitfields in nested struct. Othervise each of bitfields + // will use same + // storage as each other! + // We are using GCC extension here. It's working perfectly for clang and gcc + // but could + // produce warning in pedantic mode + __extension__ struct { + uint16_t fragment_offset : 13, more_fragments_flag : 1, dont_fragment_flag : 1, reserved_flag : 1; + }; + + uint16_t fragmentation_details_as_integer; + }; + + uint8_t ttl; + uint8_t protocol; + uint16_t checksum; + uint32_t source_ip; + uint32_t destination_ip; + + ipv4_header_t() + : version(0), ihl(0), ecn(0), dscp(0), total_length(0), identification(0), ttl(0), protocol(0), checksum(0), + source_ip(0), destination_ip(0), fragmentation_details_as_integer(0) { + } + + // Should be called AFTER convert() call + bool is_fragmented() { + if (this->more_fragments_flag != 0) { + return true; + } + + if (this->fragment_offset != 0) { + return true; + } + + return false; + } + + void convert() { + // Convert all 2 or 4 byte values to little endian from network format (big + // endian) + + // 4 byte integers + source_ip = ntohl(source_ip); + destination_ip = ntohl(destination_ip); + + fragmentation_details_as_integer = ntohs(fragmentation_details_as_integer); + + // 2 byte integers + identification = ntohs(identification); + total_length = ntohs(total_length); + } + + std::string print() { + std::stringstream buffer; + + buffer << "version: " << uint32_t(version) << " " + << "ihl: " << uint32_t(ihl) << " " + << "dscp: " << uint32_t(dscp) << " " + << "ecn: " << uint32_t(ecn) << " " + << "length: " << uint32_t(total_length) << " " + << "identification: " << uint32_t(identification) << " " + << "fragment_offset: " << uint32_t(fragment_offset) << " " + << "reserved_flag: " << uint32_t(reserved_flag) << " " + << "dont_fragment_flag: " << uint32_t(dont_fragment_flag) << " " + << "more_fragments_flag: " << uint32_t(more_fragments_flag) << " " + << "ttl: " << uint32_t(ttl) << " " + << "protocol: " << uint32_t(protocol) << " " + << "cheksum: " << uint32_t(checksum) << " " + << "source_ip: " << convert_ip_as_little_endian_to_string(source_ip) << " " + << "destination_ip: " << convert_ip_as_little_endian_to_string(destination_ip); + + return buffer.str(); + } +}; + +static_assert(sizeof(ipv4_header_t) == 20, "Bad size for ipv4_header_t"); + +enum class parser_code_t { memory_violation, not_ipv4, success }; + +std::string parser_code_to_string(parser_code_t code); +} // namespace network_data_stuctures