diff --git a/plugins/process/network/helper/Accumulator.cpp b/plugins/process/network/helper/Accumulator.cpp --- a/plugins/process/network/helper/Accumulator.cpp +++ b/plugins/process/network/helper/Accumulator.cpp @@ -25,6 +25,9 @@ #include "ConnectionMapping.h" #include "Packet.h" +#include +#include + using namespace std::chrono_literals; Accumulator::Accumulator(std::shared_ptr capture, std::shared_ptr mapping) diff --git a/plugins/process/network/helper/ConnectionMapping.h b/plugins/process/network/helper/ConnectionMapping.h --- a/plugins/process/network/helper/ConnectionMapping.h +++ b/plugins/process/network/helper/ConnectionMapping.h @@ -24,9 +24,6 @@ #include #include -#include - -// #include #include "Packet.h" @@ -56,9 +53,6 @@ std::unordered_map m_inodeToPid; std::unordered_set m_inodes; std::unordered_set m_pids; - -// QRegularExpression m_socketFileMatch; - std::regex m_socketFileMatch; }; #endif // CONNECTIONMAPPING_H diff --git a/plugins/process/network/helper/ConnectionMapping.cpp b/plugins/process/network/helper/ConnectionMapping.cpp --- a/plugins/process/network/helper/ConnectionMapping.cpp +++ b/plugins/process/network/helper/ConnectionMapping.cpp @@ -26,31 +26,13 @@ #include #include +#include #include using namespace std::string_literals; -// Convert /proc/net/tcp's mangled big-endian notation to a host-endian int32' -uint32_t tcpToInt(const std::string &part) -{ - uint32_t result = 0; - result |= std::stoi(part.substr(0, 2), 0, 16) << 24; - result |= std::stoi(part.substr(2, 2), 0, 16) << 16; - result |= std::stoi(part.substr(4, 2), 0, 16) << 8; - result |= std::stoi(part.substr(6, 2), 0, 16) << 0; - return result; -} - ConnectionMapping::ConnectionMapping() { - m_socketFileMatch = - // Format of /proc/net/tcp is: - // sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode - // 0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 31896 ... - // Where local_address is a hex representation of the IP Address and port, in big endian notation. - // Since we care only about local address, local port and inode we ignore the middle 70 characters. - std::regex("\\s*\\d+: (?:(\\w{8})|(\\w{32})):([A-F0-9]{4}) (.{94}|.{70}) (\\d+) .*", std::regex::ECMAScript | std::regex::optimize); - parseProc(); } @@ -157,34 +139,88 @@ if (!file.is_open()) return; + // Format of /proc/net/tcp is: + // sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode + // 0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 31896 ... + + // Format of /proc/net/tcp6 is: + // sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode + // 0: 00000000000000000000000001000000:0277 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 16741 ... + + // Where local_address is a hex representation of the IP Address and port, in big endian notation. + // Since we care only about local address, local port and inode we ignore the middle 70 characters. + std::string data; while (std::getline(file, data)) { - std::smatch match; - if (!std::regex_match(data, match, m_socketFileMatch)) { + // Find the first ':'. + // Should be within the first 16 characters. + size_t data_start = data.find(':'); + if (data_start >= 16) { + // Out of range. continue; } Packet::Address localAddress; - if (!match.str(1).empty()) { - localAddress.address[3] = tcpToInt(match.str(1)); + int inode = 0; // TODO: 64-bit? + + // Check for IPv4. + if (data.size() < data_start + 87 + 1) { + continue; + } + if (data[data_start + 10] == ':') { + // IPv4 entry. + // Value is one 32-bit hexadecimal chunk. + // NOTE: The chunks is technically byteswapped, but it needs + // to be kept in the byteswapped format here. + char *const ipv4 = &data[data_start + 2]; + ipv4[8] = '\0'; + localAddress.address[3] = (uint32_t)strtoul(ipv4, nullptr, 16); + + // Port number (16-bit hexadecimal) + ipv4[13] = '\0'; + localAddress.port = (uint16_t)strtoul(&ipv4[9], nullptr, 16); + + // inode number (decimal) + inode = (int)strtol(&ipv4[85], nullptr, 10); } else { - auto ipv6 = match.str(2); - if (ipv6.compare(0, 24, "0000000000000000FFFF0000")) { - // Some applications (like Steam) use ipv6 sockets with ipv4. - // This results in ipv4 addresses that end up in the tcp6 file. - // They seem to start with 0000000000000000FFFF0000, so if we - // detect that, assume it is ipv4-over-ipv6. - localAddress.address[3] = tcpToInt(ipv6.substr(24,8)); - } else { - localAddress.address[0] = tcpToInt(ipv6.substr(0, 8)); - localAddress.address[1] = tcpToInt(ipv6.substr(8, 8)); - localAddress.address[2] = tcpToInt(ipv6.substr(16, 8)); - localAddress.address[3] = tcpToInt(ipv6.substr(24, 8)); + // Check for IPv6. + if (data.size() < data_start + 135 + 1) { + continue; + } + if (data[data_start + 34] == ':') { + // IPv4 entry. + // Value is in four 32-bit byteswapped hexadecimal chunks. + // NOTE: The chunks are technically byteswapped, but they need + // to be kept in the byteswapped format here. + char *const ipv6 = &data[data_start + 2]; + + if (!memcmp(ipv6, "0000000000000000FFFF0000", 24)) { + // Some applications (like Steam) use ipv6 sockets with ipv4. + // This results in ipv4 addresses that end up in the tcp6 file. + // They seem to start with 0000000000000000FFFF0000, so if we + // detect that, assume it is ipv4-over-ipv6. + ipv6[32] = '\0'; + localAddress.address[3] = (uint32_t)strtoul(&ipv6[24], nullptr, 16); + } else { + ipv6[32] = '\0'; + localAddress.address[3] = (uint32_t)strtoul(&ipv6[24], nullptr, 16); + ipv6[24] = '\0'; + localAddress.address[2] = (uint32_t)strtoul(&ipv6[16], nullptr, 16); + ipv6[16] = '\0'; + localAddress.address[1] = (uint32_t)strtoul(&ipv6[8], nullptr, 16); + ipv6[8] = '\0'; + localAddress.address[0] = (uint32_t)strtoul(ipv6, nullptr, 16); + } + + // Port number (16-bit hexadecimal) + ipv6[38] = '\0'; + localAddress.port = (uint16_t)strtoul(&ipv6[34], nullptr, 16); + + // inode number (decimal) + inode = (int)strtol(&ipv6[133], nullptr, 10); } } - localAddress.port = std::stoi(match.str(3), 0, 16); - auto inode = std::stoi(match.str(5)); m_localToINode.insert(std::make_pair(localAddress, inode)); m_inodes.insert(inode); }