This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
stellar-stellar/decoders/session_flags/fet.cpp

123 lines
3.2 KiB
C++
Raw Normal View History

/*ref: https://github.com/apernet/OpenGFW/blob/1dce82745d0bc8b3813aea147954ba3a2294ef30/analyzer/tcp/fet.go
https://www.usenix.org/system/files/usenixsecurity23-wu-mingshi.pdf
*/
#include <string.h>
#include <stdlib.h>
#include "fet.h"
bool isPrintable(unsigned char b) {
return b >= 0x20 && b <= 0x7e;
}
int popCount(unsigned char b) {
int count = 0;
while (b != 0) {
count += (int)(b & 1);
b >>= 1;
}
return count;
}
float averagePopCount(const unsigned char* bytes, int bytes_len) {
if (bytes_len == 0) {
return 0;
}
int total = 0;
for (int i = 0; i < bytes_len; i++) {
total += popCount(bytes[i]);
}
return (float)total / (float)bytes_len;
}
bool isFirstSixPrintable(const unsigned char* bytes, int bytes_len) {
if (bytes_len < 6) {
return false;
}
for (int i = 0; i < 6; i++) {
if (!isPrintable(bytes[i])) {
return false;
}
}
return true;
}
float printablePercentage(const unsigned char* bytes, int bytes_len) {
if (bytes_len == 0) {
return 0;
}
int count = 0;
for (int i = 0; i < bytes_len; i++) {
if (isPrintable(bytes[i])) {
count++;
}
}
return (float)count / (float)bytes_len;
}
int contiguousPrintable(const unsigned char* bytes, int bytes_len) {
if (bytes_len == 0) {
return 0;
}
int maxCount = 0;
int current = 0;
for (int i = 0; i < bytes_len; i++) {
if (isPrintable(bytes[i])) {
current++;
} else {
if (current > maxCount) {
maxCount = current;
}
current = 0;
}
}
if (current > maxCount) {
maxCount = current;
}
return maxCount;
}
bool isTLS(const unsigned char* bytes, int bytes_len) {
if (bytes_len < 3) {
return false;
}
// "We observe that the GFW exempts any connection whose first
// three bytes match the following regular expression:
// [\x16-\x17]\x03[\x00-\x09]" - from the paper in Section 4.3
if (bytes[0] >= 0x16 && bytes[0] <= 0x17 &&
bytes[1] == 0x03 && bytes[2] <= 0x09) {
return true;
}
return false;
}
bool isHTTP(const unsigned char* bytes, int bytes_len) {
if (bytes_len < 3) {
return false;
}
// HTTP request
bool result = memcmp(bytes, "GET", 3) == 0 || memcmp(bytes, "HEA", 3) == 0 || memcmp(bytes, "POS", 3) == 0 ||
memcmp(bytes, "PUT", 3) == 0 || memcmp(bytes, "DEL", 3) == 0 || memcmp(bytes, "CON", 3) == 0 ||
memcmp(bytes, "OPT", 3) == 0 || memcmp(bytes, "TRA", 3) == 0 || memcmp(bytes, "PAT", 3) == 0;
return result;
}
int is_data_fet(unsigned char* data, int data_len, struct fet_detail* detail) {
if (data_len == 0) {
return 0;
}
float ex1 = averagePopCount(data, data_len);
bool ex2 = isFirstSixPrintable(data, data_len);
float ex3 = printablePercentage(data, data_len);
int ex4 = contiguousPrintable(data, data_len);
bool ex5 = isTLS(data, data_len);
bool ex6 = isHTTP(data, data_len);
bool exempt = (ex1 <= 3.4 || ex1 >= 4.6) || ex2 || ex3 > 0.5 || ex4 > 20 || ex5 || ex6;
detail->is_tls = ex5;
return !exempt;
}