6 Commits
0.1.3 ... 0.1.4

Author SHA1 Message Date
ValdikSS
23babdc8fa Windows Service support.
Program can now be started as a Windows Service. No additional
arguments needed. Refer to `service_install` and `service_remove`
scripts in released zip file.
2017-12-20 17:03:22 +03:00
ValdikSS
95765f3ed9 Store fragment_size_message as a pointer 2017-12-20 17:01:21 +03:00
ValdikSS
a5b185c2a9 Set proper options if started without arguments 2017-12-20 12:36:21 +03:00
ValdikSS
c9cd3ac8c7 Fix signed/unsigned integer comparison warning for HTTP fragmentation 2017-12-20 04:05:28 +03:00
ValdikSS
fab9662ac9 Use WinDivert TCP Header structure to change Window Size 2017-12-20 04:04:40 +03:00
ValdikSS
a88ab4337e Apply HTTP Persistent fragmentation only for sufficiently large packets 2017-12-20 03:33:30 +03:00
5 changed files with 121 additions and 38 deletions

View File

@@ -79,26 +79,8 @@ And for x86_64:
# How to install as Windows Service # How to install as Windows Service
One way is using an [srvstart](http://www.rozanski.org.uk/software) program. Use `service_install_russia_blacklist.cmd`, `service_install_russia_blacklist_dnsredir.cmd` and `service_remove.cmd` scripts.
Unpack it to `goodbyedpi` directory and create 3 files: Modify them according to your own needs.
*goodbyedpi.ini*
```INI
[GoodByeDPI]
startup=goodbyedpi.exe
shutdown_method=winmessage
auto_restart=n
```
*srvinstall.bat*
```Batchfile
srvstart install GoodByeDPI -c %CD%\goodbyedpi.ini
```
*srvremove.bat*
```Batchfile
srvstart remove GoodByeDPI
```
Run these batch files as Administrator to install/remove service.
Open Windows Services panel to run service or make it start automaticaly.
# Similar projects # Similar projects

View File

@@ -11,6 +11,7 @@
#include <getopt.h> #include <getopt.h>
#include "windivert.h" #include "windivert.h"
#include "goodbyedpi.h" #include "goodbyedpi.h"
#include "service.h"
#include "dnsredir.h" #include "dnsredir.h"
#include "blackwhitelist.h" #include "blackwhitelist.h"
@@ -20,9 +21,6 @@
#define MAX_FILTERS 4 #define MAX_FILTERS 4
#define MAX_PACKET_SIZE 9016 #define MAX_PACKET_SIZE 9016
#define IPV4_HDR_LEN 20
#define TCP_HDR_LEN 20
#define TCP_WINDOWSIZE_OFFSET 14
#define DIVERT_NO_LOCALNETS_DST "(" \ #define DIVERT_NO_LOCALNETS_DST "(" \
"(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \ "(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \
@@ -41,13 +39,13 @@
#define SET_HTTP_FRAGMENT_SIZE_OPTION(fragment_size) do { \ #define SET_HTTP_FRAGMENT_SIZE_OPTION(fragment_size) do { \
if (!http_fragment_size) { \ if (!http_fragment_size) { \
http_fragment_size = fragment_size; \ if (fragment_size <= 0 || fragment_size > 65535) { \
if (http_fragment_size <= 0 || http_fragment_size > 65535) { \ puts(fragment_size_message); \
printf(fragment_size_message); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
http_fragment_size = fragment_size; \
} \ } \
else if (http_fragment_size != fragment_size) { \ else if (http_fragment_size != (unsigned int)fragment_size) { \
printf( \ printf( \
"WARNING: HTTP fragment size is already set to %d, not changing.\n", \ "WARNING: HTTP fragment size is already set to %d, not changing.\n", \
http_fragment_size \ http_fragment_size \
@@ -55,6 +53,7 @@
} \ } \
} while (0) } while (0)
static int running_from_service = 0;
static HANDLE filters[MAX_FILTERS]; static HANDLE filters[MAX_FILTERS];
static int filter_num = 0; static int filter_num = 0;
static const char *http10_redirect_302 = "HTTP/1.0 302 "; static const char *http10_redirect_302 = "HTTP/1.0 302 ";
@@ -147,7 +146,7 @@ static int deinit(HANDLE handle) {
return FALSE; return FALSE;
} }
static void deinit_all() { void deinit_all() {
for (int i = 0; i < filter_num; i++) { for (int i = 0; i < filter_num; i++) {
deinit(filters[i]); deinit(filters[i]);
} }
@@ -216,9 +215,9 @@ static int find_header_and_get_info(const char *pktdata, int pktlen,
return FALSE; return FALSE;
} }
static void change_window_size(const char *pkt, int size) { static inline void change_window_size(const PWINDIVERT_TCPHDR ppTcpHdr, int size) {
if (size >= 1 && size <= 65535) { if (size >= 1 && size <= 65535) {
*(uint16_t*)(pkt + IPV4_HDR_LEN + TCP_WINDOWSIZE_OFFSET) = htons(size); ppTcpHdr->Window = htons(size);
} }
} }
@@ -246,7 +245,7 @@ static PVOID find_http_method_end(const char *pkt, int http_frag, int *is_fragme
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
static const char fragment_size_message[] = static const char *fragment_size_message =
"Fragment size should be in range [0 - 65535]\n"; "Fragment size should be in range [0 - 65535]\n";
int i, should_reinject, should_recalc_checksum = 0; int i, should_reinject, should_recalc_checksum = 0;
int opt; int opt;
@@ -269,8 +268,8 @@ int main(int argc, char *argv[]) {
do_http_allports = 0, do_http_allports = 0,
do_host_mixedcase = 0, do_dns_redirect = 0, do_host_mixedcase = 0, do_dns_redirect = 0,
do_dns_verb = 0, do_blacklist = 0; do_dns_verb = 0, do_blacklist = 0;
int http_fragment_size = 2; unsigned int http_fragment_size = 2;
int https_fragment_size = 2; unsigned int https_fragment_size = 2;
uint32_t dns_addr = 0; uint32_t dns_addr = 0;
uint16_t dns_port = htons(53); uint16_t dns_port = htons(53);
char *host_addr, *useragent_addr, *method_addr; char *host_addr, *useragent_addr, *method_addr;
@@ -280,6 +279,15 @@ int main(int argc, char *argv[]) {
char *hdr_name_addr = NULL, *hdr_value_addr = NULL; char *hdr_name_addr = NULL, *hdr_value_addr = NULL;
int hdr_value_len; int hdr_value_len;
if (!running_from_service && service_register(argc, argv)) {
/* We've been called as a service. Register service
* and exit this thread. main() would be called from
* service.c next time.
*/
running_from_service = 1;
return 0;
}
if (filter_string == NULL) { if (filter_string == NULL) {
filter_string = malloc(strlen(filter_string_template) + 1); filter_string = malloc(strlen(filter_string_template) + 1);
strcpy(filter_string, filter_string_template); strcpy(filter_string, filter_string_template);
@@ -290,7 +298,9 @@ int main(int argc, char *argv[]) {
if (argc == 1) { if (argc == 1) {
/* enable mode -1 by default */ /* enable mode -1 by default */
do_passivedpi = do_host = do_host_removespace \ do_passivedpi = do_host = do_host_removespace \
= do_fragment_http = do_fragment_https = 1; = do_fragment_http = do_fragment_https \
= do_fragment_http_persistent \
= do_fragment_http_persistent_nowait = 1;
} }
while ((opt = getopt_long(argc, argv, "1234prsaf:e:mwk:n", long_options, NULL)) != -1) { while ((opt = getopt_long(argc, argv, "1234prsaf:e:mwk:n", long_options, NULL)) != -1) {
@@ -347,7 +357,7 @@ int main(int argc, char *argv[]) {
do_fragment_https = 1; do_fragment_https = 1;
https_fragment_size = atoi(optarg); https_fragment_size = atoi(optarg);
if (https_fragment_size <= 0 || https_fragment_size > 65535) { if (https_fragment_size <= 0 || https_fragment_size > 65535) {
printf(fragment_size_message); puts(fragment_size_message);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
break; break;
@@ -533,7 +543,9 @@ int main(int argc, char *argv[]) {
* ack number of received packet and retransmitting missing part again, * ack number of received packet and retransmitting missing part again,
* but it's better to send it anyway since it eliminates one RTT. * but it's better to send it anyway since it eliminates one RTT.
*/ */
if (do_fragment_http_persistent && !http_req_fragmented) { if (do_fragment_http_persistent && !http_req_fragmented &&
(packet_dataLen > http_fragment_size)
) {
ppIpHdr->Length = htons( ppIpHdr->Length = htons(
ntohs(ppIpHdr->Length) - ntohs(ppIpHdr->Length) -
packet_dataLen + http_fragment_size packet_dataLen + http_fragment_size
@@ -658,11 +670,11 @@ int main(int argc, char *argv[]) {
* is enabled as there could be non-HTTP data on port 80 * is enabled as there could be non-HTTP data on port 80
*/ */
if (do_fragment_http && ppTcpHdr->SrcPort == htons(80)) { if (do_fragment_http && ppTcpHdr->SrcPort == htons(80)) {
change_window_size(packet, http_fragment_size); change_window_size(ppTcpHdr, http_fragment_size);
should_recalc_checksum = 1; should_recalc_checksum = 1;
} }
else if (do_fragment_https && ppTcpHdr->SrcPort != htons(80)) { else if (do_fragment_https && ppTcpHdr->SrcPort != htons(80)) {
change_window_size(packet, https_fragment_size); change_window_size(ppTcpHdr, https_fragment_size);
should_recalc_checksum = 1; should_recalc_checksum = 1;
} }
} }

View File

@@ -5,3 +5,6 @@
#else #else
#define debug(...) printf(__VA_ARGS__) #define debug(...) printf(__VA_ARGS__)
#endif #endif
int main(int argc, char *argv[]);
void deinit_all();

83
service.c Normal file
View File

@@ -0,0 +1,83 @@
#include <windows.h>
#include <stdio.h>
#include "goodbyedpi.h"
#include "service.h"
#define SERVICE_NAME "GoodbyeDPI"
static SERVICE_STATUS ServiceStatus;
static SERVICE_STATUS_HANDLE hStatus;
static int service_argc;
static char **service_argv;
int service_register(int argc, char *argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] = {
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main},
{NULL, NULL}
};
/*
* Save argc & argv as service_main is called with different
* arguments, which are passed from "start" command, not
* from the program command line.
* We don't need this behaviour.
*/
service_argc = argc;
service_argv = malloc(sizeof(void*) * argc);
for (int i = 0; i < argc; i++) {
service_argv[i] = strdup(argv[i]);
}
return StartServiceCtrlDispatcher(ServiceTable);
}
void service_main(int argc __attribute__((unused)),
char *argv[] __attribute__((unused)))
{
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 1;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(
SERVICE_NAME,
(LPHANDLER_FUNCTION)service_controlhandler);
if (hStatus == (SERVICE_STATUS_HANDLE)0)
{
// Registering Control Handler failed
return;
}
SetServiceStatus(hStatus, &ServiceStatus);
// Calling main with saved argc & argv
main(service_argc, service_argv);
if (ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
// If terminated with error
ServiceStatus.dwWin32ExitCode = 1;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
}
return;
}
// Control handler function
void service_controlhandler(DWORD request)
{
switch(request)
{
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
deinit_all();
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
default:
break;
}
// Report current status
SetServiceStatus (hStatus, &ServiceStatus);
return;
}

3
service.h Normal file
View File

@@ -0,0 +1,3 @@
int service_register();
void service_main(int argc, char *argv[]);
void service_controlhandler(DWORD request);