From 3074df048a2969f9d17dcd965e615f2566f32d7c Mon Sep 17 00:00:00 2001 From: jimraynor2470 Date: Mon, 8 May 2023 10:35:39 +0900 Subject: [PATCH 1/3] Add whitelist option --- src/blackwhitelist.c | 44 +++++++++++++++++++++++++++++++------------- src/blackwhitelist.h | 6 ++++-- src/goodbyedpi.c | 30 ++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/blackwhitelist.c b/src/blackwhitelist.c index 075ca29..a69f9ca 100644 --- a/src/blackwhitelist.c +++ b/src/blackwhitelist.c @@ -16,13 +16,14 @@ typedef struct blackwhitelist_record { UT_hash_handle hh; /* makes this structure hashable */ } blackwhitelist_record_t; -static blackwhitelist_record_t *blackwhitelist = NULL; +static blackwhitelist_record_t *blacklist = NULL; +static blackwhitelist_record_t *whitelist = NULL; -static int check_get_hostname(const char *host) { +static int check_get_hostname(const char *host, blackwhitelist_record_t **list) { blackwhitelist_record_t *tmp_record = NULL; - if (!blackwhitelist) return FALSE; + if (!*list) return FALSE; - HASH_FIND_STR(blackwhitelist, host, tmp_record); + HASH_FIND_STR(*list, host, tmp_record); if (tmp_record) { debug("check_get_hostname found host\n"); return TRUE; @@ -31,17 +32,17 @@ static int check_get_hostname(const char *host) { return FALSE; } -static int add_hostname(const char *host) { +static int add_hostname(const char *host, blackwhitelist_record_t **list) { if (!host) return FALSE; blackwhitelist_record_t *tmp_record = malloc(sizeof(blackwhitelist_record_t)); char *host_c = NULL; - if (!check_get_hostname(host)) { + if (!check_get_hostname(host, list)) { host_c = strdup(host); tmp_record->host = host_c; - HASH_ADD_KEYPTR(hh, blackwhitelist, tmp_record->host, + HASH_ADD_KEYPTR(hh, *list, tmp_record->host, strlen(tmp_record->host), tmp_record); debug("Added host %s\n", host_c); return TRUE; @@ -53,7 +54,7 @@ static int add_hostname(const char *host) { return FALSE; } -int blackwhitelist_load_list(const char *filename) { +static int blackwhitelist_load_list(const char *filename, blackwhitelist_record_t **list) { char *line = malloc(HOST_MAXLEN + 1); size_t linelen = HOST_MAXLEN + 1; int cnt = 0; @@ -74,17 +75,25 @@ int blackwhitelist_load_list(const char *filename) { printf("WARNING: host %s is less than 2 characters, skipping\n", line); continue; } - if (add_hostname(line)) + if (add_hostname(line, list)) cnt++; } free(line); - if (!blackwhitelist) return FALSE; + if (!*list) return FALSE; printf("Loaded %d hosts from file %s\n", cnt, filename); fclose(fp); return TRUE; } -int blackwhitelist_check_hostname(const char *host_addr, size_t host_len) { +int blackwhitelist_load_blacklist(const char *filename) { + return blackwhitelist_load_list(filename, &blacklist); +} + +int blackwhitelist_load_whitelist(const char *filename) { + return blackwhitelist_load_list(filename, &whitelist); +} + +static int blackwhitelist_check_hostname(const char *host_addr, size_t host_len, blackwhitelist_record_t **list) { char current_host[HOST_MAXLEN + 1]; char *tokenized_host = NULL; @@ -94,12 +103,13 @@ int blackwhitelist_check_hostname(const char *host_addr, size_t host_len) { current_host[host_len] = '\0'; } - if (check_get_hostname(current_host)) + if (check_get_hostname(current_host, list)) return TRUE; tokenized_host = strchr(current_host, '.'); while (tokenized_host != NULL && tokenized_host < (current_host + HOST_MAXLEN)) { - if (check_get_hostname(tokenized_host + 1)) + /* Search hostname only if there is next token */ + if (strchr(tokenized_host + 1, '.') && check_get_hostname(tokenized_host + 1, list)) return TRUE; tokenized_host = strchr(tokenized_host + 1, '.'); } @@ -107,3 +117,11 @@ int blackwhitelist_check_hostname(const char *host_addr, size_t host_len) { debug("____blackwhitelist_check_hostname FALSE: host %s\n", current_host); return FALSE; } + +int blackwhitelist_check_hostname_blacklist(const char *host_addr, size_t host_len) { + return blackwhitelist_check_hostname(host_addr, host_len, &blacklist); +} + +int blackwhitelist_check_hostname_whitelist(const char *host_addr, size_t host_len) { + return blackwhitelist_check_hostname(host_addr, host_len, &whitelist); +} diff --git a/src/blackwhitelist.h b/src/blackwhitelist.h index f8122a3..96eff04 100644 --- a/src/blackwhitelist.h +++ b/src/blackwhitelist.h @@ -1,2 +1,4 @@ -int blackwhitelist_load_list(const char *filename); -int blackwhitelist_check_hostname(const char *host_addr, size_t host_len); +int blackwhitelist_load_blacklist(const char *filename); +int blackwhitelist_load_whitelist(const char *filename); +int blackwhitelist_check_hostname_blacklist(const char *host_addr, size_t host_len); +int blackwhitelist_check_hostname_whitelist(const char *host_addr, size_t host_len); diff --git a/src/goodbyedpi.c b/src/goodbyedpi.c index 0c303dc..31e5d01 100644 --- a/src/goodbyedpi.c +++ b/src/goodbyedpi.c @@ -177,6 +177,7 @@ static struct option long_options[] = { {"dnsv6-port", required_argument, 0, '@' }, {"dns-verb", no_argument, 0, 'v' }, {"blacklist", required_argument, 0, 'b' }, + {"whitelist", required_argument, 0, 't' }, {"allow-no-sni",no_argument, 0, ']' }, {"frag-by-sni", no_argument, 0, '>' }, {"ip-id", required_argument, 0, 'i' }, @@ -610,7 +611,8 @@ int main(int argc, char *argv[]) { do_http_allports = 0, do_host_mixedcase = 0, do_dnsv4_redirect = 0, do_dnsv6_redirect = 0, - do_dns_verb = 0, do_tcp_verb = 0, do_blacklist = 0, + do_dns_verb = 0, do_tcp_verb = 0, + do_blacklist = 0, do_whitelist = 0, do_allow_no_sni = 0, do_fragment_by_sni = 0, do_fake_packet = 0, @@ -863,9 +865,16 @@ int main(int argc, char *argv[]) { break; case 'b': // --blacklist do_blacklist = 1; - if (!blackwhitelist_load_list(optarg)) { + if (!blackwhitelist_load_blacklist(optarg)) { printf("Can't load blacklist from file!\n"); - exit(ERROR_BLACKLIST_LOAD); + exit(EXIT_FAILURE); + } + break; + case 't': // --whitelist + do_whitelist = 1; + if (!blackwhitelist_load_whitelist(optarg)) { + printf("Can't load whitelist from file!\n"); + exit(EXIT_FAILURE); } break; case ']': // --allow-no-sni @@ -994,6 +1003,9 @@ int main(int argc, char *argv[]) { " --blacklist perform circumvention tricks only to host names and subdomains from\n" " supplied text file (HTTP Host/TLS SNI).\n" " This option can be supplied multiple times.\n" + " --whitelist does not perform circumvention tricks to host names and subdomains from\n" + " supplied text file.\n" + " This option can be supplied multiple times.\n" " --allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled.\n" " --frag-by-sni if SNI is detected in TLS packet, fragment the packet right before SNI value.\n" " --set-ttl activate Fake Request Mode and send it with supplied TTL value.\n" @@ -1264,16 +1276,17 @@ int main(int argc, char *argv[]) { if ((packet_dataLen == 2 && memcmp(packet_data, "\x16\x03", 2) == 0) || (packet_dataLen >= 3 && ( memcmp(packet_data, "\x16\x03\x01", 3) == 0 || memcmp(packet_data, "\x16\x03\x03", 3) == 0 ))) { - if (do_blacklist || do_fragment_by_sni) { + if (do_blacklist || do_whitelist) { sni_ok = extract_sni(packet_data, packet_dataLen, &host_addr, &host_len); } if ( - (do_blacklist && sni_ok && - blackwhitelist_check_hostname(host_addr, host_len) + ((do_blacklist && sni_ok && + blackwhitelist_check_hostname_blacklist(host_addr, host_len) ) || (do_blacklist && !sni_ok && do_allow_no_sni) || - (!do_blacklist) + (!do_blacklist)) && + (do_whitelist ? !blackwhitelist_check_hostname_whitelist(host_addr, host_len) : 1) ) { #ifdef DEBUG @@ -1309,7 +1322,8 @@ int main(int argc, char *argv[]) { if (find_header_and_get_info(packet_data, packet_dataLen, http_host_find, &hdr_name_addr, &hdr_value_addr, &hdr_value_len) && hdr_value_len > 0 && hdr_value_len <= HOST_MAXLEN && - (do_blacklist ? blackwhitelist_check_hostname(hdr_value_addr, hdr_value_len) : 1)) + (do_blacklist ? blackwhitelist_check_hostname_blacklist(hdr_value_addr, hdr_value_len) : 1) && + (do_whitelist ? !blackwhitelist_check_hostname_whitelist(hdr_value_addr, hdr_value_len) : 1)) { host_addr = hdr_value_addr; host_len = hdr_value_len; From 290d7fd9214094e8b0bbef32b4c72ac7806cd66f Mon Sep 17 00:00:00 2001 From: jimraynor2470 Date: Mon, 8 May 2023 11:48:57 +0900 Subject: [PATCH 2/3] Update README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9a88fa1..9d04c6b 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,9 @@ Usage: goodbyedpi.exe [OPTION...] --blacklist perform circumvention tricks only to host names and subdomains from supplied text file (HTTP Host/TLS SNI). This option can be supplied multiple times. + --whitelist does not perform circumvention tricks to host names and subdomains from + supplied text file. + This option can be supplied multiple times. --allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled. --frag-by-sni if SNI is detected in TLS packet, fragment the packet right before SNI value. --set-ttl activate Fake Request Mode and send it with supplied TTL value. From d9955d78aa079065acf92fa6420657b48442bbd3 Mon Sep 17 00:00:00 2001 From: Tarik Date: Sat, 23 May 2026 11:51:15 +0300 Subject: [PATCH 3/3] Fixing errors regarding whitelisting feature. --- README.md | 2 +- src/blackwhitelist.c | 12 +++++---- src/goodbyedpi.c | 58 +++++++++++++++++++++++++++++++------------- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 9d04c6b..3db22bf 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Usage: goodbyedpi.exe [OPTION...] --blacklist perform circumvention tricks only to host names and subdomains from supplied text file (HTTP Host/TLS SNI). This option can be supplied multiple times. - --whitelist does not perform circumvention tricks to host names and subdomains from + --whitelist do not perform circumvention tricks to host names and subdomains from supplied text file. This option can be supplied multiple times. --allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled. diff --git a/src/blackwhitelist.c b/src/blackwhitelist.c index a69f9ca..5062d77 100644 --- a/src/blackwhitelist.c +++ b/src/blackwhitelist.c @@ -1,5 +1,5 @@ /* - * Blacklist for GoodbyeDPI HTTP DPI circumvention tricks + * Blacklist and whitelist for GoodbyeDPI HTTP DPI circumvention tricks * * This is a simple domain hash table. * Domain records are added from a text file, where every @@ -71,15 +71,18 @@ static int blackwhitelist_load_list(const char *filename, blackwhitelist_record_ line); continue; } - if (strlen(line) < 2) { - printf("WARNING: host %s is less than 2 characters, skipping\n", line); + if (strlen(line) < 3) { + printf("WARNING: host %s is less than 3 bytes, skipping\n", line); continue; } if (add_hostname(line, list)) cnt++; } free(line); - if (!*list) return FALSE; + if (!*list) { + fclose(fp); + return FALSE; + } printf("Loaded %d hosts from file %s\n", cnt, filename); fclose(fp); return TRUE; @@ -108,7 +111,6 @@ static int blackwhitelist_check_hostname(const char *host_addr, size_t host_len, tokenized_host = strchr(current_host, '.'); while (tokenized_host != NULL && tokenized_host < (current_host + HOST_MAXLEN)) { - /* Search hostname only if there is next token */ if (strchr(tokenized_host + 1, '.') && check_get_hostname(tokenized_host + 1, list)) return TRUE; tokenized_host = strchr(tokenized_host + 1, '.'); diff --git a/src/goodbyedpi.c b/src/goodbyedpi.c index 31e5d01..975e7e6 100644 --- a/src/goodbyedpi.c +++ b/src/goodbyedpi.c @@ -177,7 +177,7 @@ static struct option long_options[] = { {"dnsv6-port", required_argument, 0, '@' }, {"dns-verb", no_argument, 0, 'v' }, {"blacklist", required_argument, 0, 'b' }, - {"whitelist", required_argument, 0, 't' }, + {"whitelist", required_argument, 0, 'W' }, {"allow-no-sni",no_argument, 0, ']' }, {"frag-by-sni", no_argument, 0, '>' }, {"ip-id", required_argument, 0, 'i' }, @@ -267,6 +267,36 @@ static void finalize_filter_strings() { filter_passive_string = newstr; } +static int host_is_circumvented(int do_blacklist, int do_whitelist, int do_allow_no_sni, + int sni_ok, const char *host_addr, size_t host_len) { + int host_blacklisted = 1; + int host_whitelisted = 0; + + if (do_blacklist || do_whitelist) { + if (sni_ok) { + if (do_blacklist) + host_blacklisted = blackwhitelist_check_hostname_blacklist(host_addr, host_len); + if (do_whitelist) + host_whitelisted = blackwhitelist_check_hostname_whitelist(host_addr, host_len); + } else { + host_blacklisted = 0; + } + + if (do_blacklist) { + if (!sni_ok) + return do_allow_no_sni; + return host_blacklisted && !host_whitelisted; + } + + if (!sni_ok) + return 0; + + return !host_whitelisted; + } + + return 1; +} + static char* dumb_memmem(const char* haystack, unsigned int hlen, const char* needle, unsigned int nlen) { @@ -688,7 +718,7 @@ int main(int argc, char *argv[]) { max_payload_size = 1200; } - while ((opt = getopt_long(argc, argv, "123456789pqrsaf:e:mwk:n", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "123456789pqrsaf:e:mwk:nW", long_options, NULL)) != -1) { switch (opt) { case '1': do_passivedpi = do_host = do_host_removespace \ @@ -867,14 +897,14 @@ int main(int argc, char *argv[]) { do_blacklist = 1; if (!blackwhitelist_load_blacklist(optarg)) { printf("Can't load blacklist from file!\n"); - exit(EXIT_FAILURE); + exit(ERROR_BLACKLIST_LOAD); } break; - case 't': // --whitelist + case 'W': // --whitelist do_whitelist = 1; if (!blackwhitelist_load_whitelist(optarg)) { printf("Can't load whitelist from file!\n"); - exit(EXIT_FAILURE); + exit(ERROR_BLACKLIST_LOAD); } break; case ']': // --allow-no-sni @@ -1003,7 +1033,7 @@ int main(int argc, char *argv[]) { " --blacklist perform circumvention tricks only to host names and subdomains from\n" " supplied text file (HTTP Host/TLS SNI).\n" " This option can be supplied multiple times.\n" - " --whitelist does not perform circumvention tricks to host names and subdomains from\n" + " --whitelist do not perform circumvention tricks to host names and subdomains from\n" " supplied text file.\n" " This option can be supplied multiple times.\n" " --allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled.\n" @@ -1276,18 +1306,12 @@ int main(int argc, char *argv[]) { if ((packet_dataLen == 2 && memcmp(packet_data, "\x16\x03", 2) == 0) || (packet_dataLen >= 3 && ( memcmp(packet_data, "\x16\x03\x01", 3) == 0 || memcmp(packet_data, "\x16\x03\x03", 3) == 0 ))) { - if (do_blacklist || do_whitelist) { + if (do_blacklist || do_whitelist || do_fragment_by_sni) { sni_ok = extract_sni(packet_data, packet_dataLen, &host_addr, &host_len); } - if ( - ((do_blacklist && sni_ok && - blackwhitelist_check_hostname_blacklist(host_addr, host_len) - ) || - (do_blacklist && !sni_ok && do_allow_no_sni) || - (!do_blacklist)) && - (do_whitelist ? !blackwhitelist_check_hostname_whitelist(host_addr, host_len) : 1) - ) + if (host_is_circumvented(do_blacklist, do_whitelist, do_allow_no_sni, + sni_ok, host_addr, host_len)) { #ifdef DEBUG char lsni[HOST_MAXLEN + 1] = {0}; @@ -1322,8 +1346,8 @@ int main(int argc, char *argv[]) { if (find_header_and_get_info(packet_data, packet_dataLen, http_host_find, &hdr_name_addr, &hdr_value_addr, &hdr_value_len) && hdr_value_len > 0 && hdr_value_len <= HOST_MAXLEN && - (do_blacklist ? blackwhitelist_check_hostname_blacklist(hdr_value_addr, hdr_value_len) : 1) && - (do_whitelist ? !blackwhitelist_check_hostname_whitelist(hdr_value_addr, hdr_value_len) : 1)) + host_is_circumvented(do_blacklist, do_whitelist, 1, + 1, hdr_value_addr, hdr_value_len)) { host_addr = hdr_value_addr; host_len = hdr_value_len;