Skip to content

Commit 30c689a

Browse files
committed
ts-warp-1.5.5 release
1 parent e7d3829 commit 30c689a

File tree

9 files changed

+103
-44
lines changed

9 files changed

+103
-44
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGELOG
22

3+
* **2024.08.15 ts-warp-1.5.5, gui-warp-1.0.25 (gui-warp-v1.0.30-mac), ns-warp-1.0.7****
4+
* `ts-warp.c`, `http.c`: Deep Packet Inspections bypass. Option `-D` to disable it.
5+
* `ts-warp.c`: Internal proxy servers allowed making direct connection to destinations
6+
37
* **2024.07.23 ts-warp-1.5.4, gui-warp-1.0.25 (gui-warp-v1.0.30-mac), ns-warp-1.0.7**
48
* `ts-warp.c`: `ACT`-file created as `RUNAS_USER` user owner
59
* `ts-warp.c`: On `macOS` delayed `setuid()`/`setgid()` disabled as almost useless

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
\* HTTP Connect method is implemented
5252

5353
- Miscellaneous features
54+
- [X] Deep Packet Inspections bypass
5455
- [x] Simple configuration structure as INI-like file
5556
- [x] Password encoding (obfuscation) in configuration files
5657
- [x] Daemon mode
@@ -201,6 +202,14 @@ Note, Python 3 interpreter with `tkinter` support is required to run the GUI fro
201202
Check [releases](https://github.com/mezantrop/ts-warp/releases) and download macOS standalone precompiled application.
202203
Read related [README.md](gui/ports/macOS/README.md) for information and instructions.
203204

205+
### Experimental Deep Packet Inspections bypass
206+
207+
According to [SpoofDPI](https://github.com/xvzc/SpoofDPI?tab=readme-ov-file#https) project, sending the first 1 byte
208+
of a request to the server, and then sending the rest of the data can help to bypass Deep Packet Inspections of HTTPS.
209+
210+
`TS-Warp` has the feature enabled by default. Just use TS-Warp in `Transparent` mode, or point your browser to `TS-Warp`
211+
Internal `HTTP(S)` proxy at default `127.0.0.1:8080` or `SOCKS5` proxy at `127.0.0.1:7080`.
212+
204213
### Contacts
205214

206215
Not so early stage of development, yet don't expect everything to work properly. If you have an idea, a question,

gui/gui-warp.ini.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ inifile = /etc/ts-warp.ini
1212
logfile = /var/log/ts-warp.log
1313
pidfile = /var/run/ts-warp.pid
1414
actfile = /var/spool/ts-warp/ts-warp.act
15-
daemon_options =
15+
daemon_options =

gui/ports/macOS/gui-warp.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ inifile = /etc/ts-warp.ini
1212
logfile = /var/log/ts-warp.log
1313
pidfile = /var/run/ts-warp.pid
1414
actfile = /var/spool/ts-warp/ts-warp.act
15-
daemon_options =
15+
daemon_options =

http.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ int http_server_request(int socket, struct uvaddr *daddr) {
9595
}
9696

9797
/* ------------------------------------------------------------------------------------------------------------------ */
98-
int http_client_request(chs cs, struct sockaddr_storage *daddr, char *user, char *password) {
98+
int http_client_request(chs cs, struct sockaddr_storage *daddr, char *user, char *password, int sdpi) {
9999
char r[BUF_SIZE_1KB] = {0};
100100
char b[HOST_NAME_MAX] = {0};
101101
char usr_pwd_plain[BUF_SIZE_1KB] = {0};
@@ -104,7 +104,6 @@ int http_client_request(chs cs, struct sockaddr_storage *daddr, char *user, char
104104
int rcount = 0;
105105
int l = 0;
106106

107-
108107
/* Request startline: CONNECT address:port PROTOCOL */
109108
if (user && password) {
110109
sprintf(usr_pwd_plain, "%s:%s", user, password);
@@ -120,10 +119,18 @@ int http_client_request(chs cs, struct sockaddr_storage *daddr, char *user, char
120119

121120
switch (cs.t) {
122121
case CHS_SOCKET:
123-
if (send(cs.s, r, l, 0) == -1) {
124-
printl(LOG_CRIT, "Unable to send a request to the HTTP server via socket");
125-
return 1;
126-
}
122+
if (sdpi) {
123+
printl(LOG_VERB, "Trying to bypass Deep Packet Inspections");
124+
125+
if (send(cs.s, r, 1, 0) == -1 || send(cs.s, r + 1, l - 1, 0) == -1) {
126+
printl(LOG_CRIT, "SDPI: Unable to send a request to the HTTP server via socket");
127+
return 1;
128+
}
129+
} else
130+
if (send(cs.s, r, l, 0) == -1) {
131+
printl(LOG_CRIT, "Unable to send a request to the HTTP server via socket");
132+
return 1;
133+
}
127134

128135
printl(LOG_VERB, "Expecting HTTP reply");
129136

http.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@
3838

3939
/* ------------------------------------------------------------------------------------------------------------------ */
4040
int http_server_request(int socket, struct uvaddr *daddr);
41-
int http_client_request(chs cs, struct sockaddr_storage *daddr, char *user, char *password);
41+
int http_client_request(chs cs, struct sockaddr_storage *daddr, char *user, char *password, int sdpi);

network.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ char *inet2str(struct sockaddr_storage *ai_addr, char *str_addr) {
115115
break;
116116

117117
case AF_UNSPEC:
118-
printl(LOG_WARN, "Address is not set");
118+
printl(LOG_VERB, "Address is not set");
119119
return NULL;
120120
break;
121121

ts-warp.c

Lines changed: 72 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ int tfd = -1; /* Traffic log file descript
108108
int main(int argc, char* argv[]) {
109109
/* Usage:
110110
Usage:
111-
ts-warp -T IP:Port -S IP:Port -H IP:Port -c file.ini -l file.log -v 0-4 -t file.act -d -p file.pid -f -u user -h
111+
ts-warp -T IP:Port -S IP:Port -H IP:Port -c file.ini -l file.log -v 0-4 -t file.act -d -p file.pid -f -u user -D -h
112112
113113
Version:
114114
TS-Warp-X.Y.Z
@@ -127,6 +127,7 @@ All parameters are optional:
127127
-f Force start
128128
129129
-u user A user to run ts-warp, default: nobody
130+
-D Do not try spoofing Deep Packet Inspections
130131
131132
-h This message */
132133

@@ -141,6 +142,9 @@ All parameters are optional:
141142
int l_flg = 0; /* User didn't set the log file */
142143
int d_flg = 0; /* Daemon mode */
143144
int f_flg = 0; /* Force start */
145+
int sdpi = 1; /* Try bypassing DPI */
146+
/* According to https://github.com/xvzc/SpoofDPI?tab=readme-ov-file#https sending the first 1 byte of a request
147+
to the server, and then sending the rest of the data can help to bypass Deep Packet Inspections of HTTPS */
144148

145149
char *runas_user = RUNAS_USER; /* A user to run ts-warp */
146150

@@ -177,7 +181,7 @@ All parameters are optional:
177181
#endif
178182

179183

180-
while ((flg = getopt(argc, argv, "T:S:H:c:l:v:t:dp:fu:h")) != -1)
184+
while ((flg = getopt(argc, argv, "T:S:H:c:l:v:t:dp:fu:Dh")) != -1)
181185
switch(flg) {
182186
case 'T': /* Internal Transparent server IP/name */
183187
taddr = strsep(&optarg, ":"); /* IP:PORT */
@@ -233,6 +237,10 @@ All parameters are optional:
233237
#endif
234238
break;
235239

240+
case 'D':
241+
sdpi = 0;
242+
break;
243+
236244
case 'h': /* Help */
237245
default:
238246
(void)usage(0);
@@ -268,7 +276,9 @@ All parameters are optional:
268276
if (mkfifo(tfile_name, S_IFIFO|S_IRWXU|S_IRGRP|S_IROTH) == -1 && errno != EEXIST)
269277
printl(LOG_WARN, "Unable to create active connections and traffic log pipe: [%s]", tfile_name);
270278
else {
271-
chown(tfile_name, pwd ? pwd->pw_uid : 0, pwd ? pwd->pw_gid : 0);
279+
if (chown(tfile_name, pwd ? pwd->pw_uid : 0, pwd ? pwd->pw_gid : 0) == -1)
280+
printl(LOG_WARN, "Unable change owner of the ACT log pipe[%s]", tfile_name);
281+
272282
if ((tfd = open(tfile_name, O_RDWR) ) == -1)
273283
printl(LOG_WARN, "Unable to open active connections and traffic log pipe: [%s]", tfile_name);
274284
else
@@ -577,21 +587,23 @@ All parameters are optional:
577587
memset(&daddr.ip_addr, 0, daddr_len);
578588
memset(&daddr.name, 0, sizeof(daddr.name) - 1);
579589

580-
#if defined(linux)
581-
/* On Linux && nftabeles/iptables */
582-
memset(&daddr.ip_addr, 0, daddr_len);
583-
daddr.ip_addr.ss_family = caddr.ss_family;
584-
ret = getsockopt(csock, SOL_IP, SO_ORIGINAL_DST, &daddr.ip_addr, &daddr_len);
585-
#else
586-
/* On *BSD with PF */
587-
ret = nat_lookup(pfd, &caddr, (struct sockaddr_storage *)tres->ai_addr, &daddr.ip_addr);
588-
#endif
589-
if (ret) {
590-
printl(LOG_WARN, "Failed to find the real destination IP, trying to get it from the socket");
591-
getpeername(csock, (struct sockaddr *)&daddr.ip_addr, &daddr_len);
592-
}
590+
if (isock == Tsock) {
591+
#if defined(linux)
592+
/* On Linux && nftabeles/iptables */
593+
memset(&daddr.ip_addr, 0, daddr_len);
594+
daddr.ip_addr.ss_family = caddr.ss_family;
595+
ret = getsockopt(csock, SOL_IP, SO_ORIGINAL_DST, &daddr.ip_addr, &daddr_len);
596+
#else
597+
/* On *BSD with PF */
598+
ret = nat_lookup(pfd, &caddr, (struct sockaddr_storage *)tres->ai_addr, &daddr.ip_addr);
599+
#endif
600+
if (ret) {
601+
printl(LOG_WARN, "Failed to find the real destination IP, trying to get it from the socket");
602+
getpeername(csock, (struct sockaddr *)&daddr.ip_addr, &daddr_len);
603+
}
593604

594-
printl(LOG_INFO, "The client destination address is: [%s]", inet2str(&daddr.ip_addr, buf));
605+
printl(LOG_INFO, "The client destination address is: [%s]", inet2str(&daddr.ip_addr, buf));
606+
}
595607

596608
/* -- Process the PIDs list: remove exitted clients and execute workload balance functions ------------------ */
597609
c = pids;
@@ -648,19 +660,28 @@ All parameters are optional:
648660
pid = getpid();
649661
printl(LOG_VERB, "A new client process started");
650662

651-
if (!s_ini) {
663+
if (!s_ini && isock == Tsock) {
652664
/* -- No proxy server found for the destination IP -------------------------------------------------- */
653665
printl(LOG_INFO, "No proxy server is defined for the destination: [%s]", inet2str(&daddr.ip_addr, buf));
654666

655-
if ((daddr.ip_addr.ss_family == AF_INET && S4_ADDR(daddr.ip_addr) == S4_ADDR(*tres->ai_addr)) ||
667+
if ((daddr.ip_addr.ss_family == AF_INET &&
668+
S4_ADDR(daddr.ip_addr) == S4_ADDR(*tres->ai_addr) &&
669+
SIN4_PORT(daddr.ip_addr) == SIN4_PORT(*tres->ai_addr)) ||
656670
(daddr.ip_addr.ss_family == AF_INET6 &&
657-
!memcmp(S6_ADDR(daddr.ip_addr), S6_ADDR(*tres->ai_addr), sizeof(S6_ADDR(daddr.ip_addr)))) ||
658-
(daddr.ip_addr.ss_family == AF_INET && S4_ADDR(daddr.ip_addr) == S4_ADDR(*sres->ai_addr)) ||
671+
!memcmp(S6_ADDR(daddr.ip_addr), S6_ADDR(*tres->ai_addr), sizeof(S6_ADDR(daddr.ip_addr))) &&
672+
SIN6_PORT(daddr.ip_addr) == SIN6_PORT(*tres->ai_addr)) ||
673+
(daddr.ip_addr.ss_family == AF_INET &&
674+
S4_ADDR(daddr.ip_addr) == S4_ADDR(*sres->ai_addr) &&
675+
SIN4_PORT(daddr.ip_addr) == SIN4_PORT(*sres->ai_addr)) ||
659676
(daddr.ip_addr.ss_family == AF_INET6 &&
660-
!memcmp(S6_ADDR(daddr.ip_addr), S6_ADDR(*sres->ai_addr), sizeof(S6_ADDR(daddr.ip_addr)))) ||
661-
(daddr.ip_addr.ss_family == AF_INET && S4_ADDR(daddr.ip_addr) == S4_ADDR(*hres->ai_addr)) ||
677+
!memcmp(S6_ADDR(daddr.ip_addr), S6_ADDR(*sres->ai_addr), sizeof(S6_ADDR(daddr.ip_addr))) &&
678+
SIN6_PORT(daddr.ip_addr) == SIN6_PORT(*sres->ai_addr)) ||
679+
(daddr.ip_addr.ss_family == AF_INET &&
680+
S4_ADDR(daddr.ip_addr) == S4_ADDR(*hres->ai_addr) &&
681+
SIN4_PORT(daddr.ip_addr) == SIN4_PORT(*hres->ai_addr)) ||
662682
(daddr.ip_addr.ss_family == AF_INET6 &&
663-
!memcmp(S6_ADDR(daddr.ip_addr), S6_ADDR(*hres->ai_addr), sizeof(S6_ADDR(daddr.ip_addr))))) {
683+
!memcmp(S6_ADDR(daddr.ip_addr), S6_ADDR(*hres->ai_addr), sizeof(S6_ADDR(daddr.ip_addr))) &&
684+
SIN6_PORT(daddr.ip_addr) == SIN6_PORT(*hres->ai_addr))) {
664685
/* Desination address:port is the same as ts-warp incominig (Taransparent, Socks or HTTP) ip:port,
665686
i.e., a client contacted ts-warp dirctly: no NAT/redirection and TS-Warp is not defined as
666687
proxy server */
@@ -935,7 +956,8 @@ All parameters are optional:
935956
inet2str(&sc->next->chain_member->proxy_server, buf));
936957

937958
if (http_client_request(ssock, &sc->next->chain_member->proxy_server,
938-
sc->next->chain_member->proxy_user, sc->next->chain_member->proxy_password)) {
959+
sc->next->chain_member->proxy_user,
960+
sc->next->chain_member->proxy_password, sdpi)) {
939961

940962
printl(LOG_WARN, "CHAIN HTTP server returned an error");
941963
close(csock);
@@ -948,7 +970,7 @@ All parameters are optional:
948970
inet2str(&s_ini->proxy_server, buf));
949971

950972
if (http_client_request(ssock,
951-
&s_ini->proxy_server, s_ini->proxy_user, s_ini->proxy_password)) {
973+
&s_ini->proxy_server, s_ini->proxy_user, s_ini->proxy_password, sdpi)) {
952974

953975
printl(LOG_WARN, "CHAIN HTTP server returned an error");
954976
close(csock);
@@ -1117,7 +1139,7 @@ All parameters are optional:
11171139
printl(LOG_VERB, "Initiate HTTP protocol: request: [%s] -> [%s]",
11181140
inet2str(&s_ini->proxy_server, suf), inet2str(&daddr.ip_addr, buf));
11191141

1120-
if (http_client_request(ssock, &daddr.ip_addr, s_ini->proxy_user, s_ini->proxy_password)) {
1142+
if (http_client_request(ssock, &daddr.ip_addr, s_ini->proxy_user, s_ini->proxy_password, sdpi)) {
11211143
printl(LOG_WARN, "HTTP proxy server returned an error");
11221144
close(csock);
11231145
exit(2);
@@ -1276,11 +1298,27 @@ All parameters are optional:
12761298
printl(LOG_CRIT, "Error receving data from the client");
12771299
break;
12781300
}
1279-
while ((snd = send(ssock.s, buf, rec, 0)) == 0) {
1280-
printl(LOG_CRIT, "C:[0] -> S:[0] bytes");
1281-
usleep(100); /* 0.1 ms */
1282-
break;
1283-
}
1301+
1302+
if (sdpi && rec > 1) {
1303+
printl(LOG_VERB, "Trying to bypass Deep Packet Inspections");
1304+
1305+
if ((snd = send(ssock.s, buf, 1, 0)) == -1) {
1306+
printl(LOG_CRIT, "Error sending data to proxy server");
1307+
break;
1308+
}
1309+
int _snd = send(ssock.s, buf + 1, rec - 1, 0);
1310+
if (_snd == -1) {
1311+
printl(LOG_CRIT, "Error sending data to proxy server");
1312+
break;
1313+
}
1314+
snd += _snd;
1315+
sdpi = 0; /* No need to split more packets */
1316+
} else
1317+
while ((snd = send(ssock.s, buf, rec, 0)) == 0) {
1318+
printl(LOG_CRIT, "C:[0] -> S:[0] bytes");
1319+
usleep(100); /* 0.1 ms */
1320+
break;
1321+
}
12841322
if (snd == -1) {
12851323
printl(LOG_CRIT, "Error sending data to proxy server");
12861324
break;
@@ -1420,7 +1458,7 @@ void trap_signal(int sig) {
14201458
/* ------------------------------------------------------------------------------------------------------------------ */
14211459
void usage(int ecode) {
14221460
printf("Usage:\n\
1423-
ts-warp -T IP:Port -S IP:Port -H IP:Port -c file.ini -l file.log -v 0-4 -t file.act -d -p file.pid -f -u user -h\n\n\
1461+
ts-warp -T IP:Port -S IP:Port -H IP:Port -c file.ini -l file.log -v 0-4 -t file.act -d -p file.pid -f -u user -D -h\n\n\
14241462
Version:\n\
14251463
%s-%s\n\n\
14261464
All parameters are optional:\n\
@@ -1438,6 +1476,7 @@ All parameters are optional:\n\
14381476
-f\t\t Force start\n\
14391477
\n\
14401478
-u user\t A user to run ts-warp, default: %s. Note, this option has no effect on macOS\n\
1479+
-D\t\t Do not try bypass Deep Packet Inspections\n\
14411480
\n\
14421481
-h\t\t This message\n\n",
14431482
PROG_NAME, PROG_VERSION, INI_FILE_NAME, LOG_FILE_NAME, LOG_LEVEL_DEFAULT, PID_FILE_NAME, RUNAS_USER);

version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#define PROG_NAME_SHORT "TSW"
3030
#define PROG_VERSION_MAJOR "1"
3131
#define PROG_VERSION_MINOR "5"
32-
#define PROG_VERSION_BUILD "4"
32+
#define PROG_VERSION_BUILD "5"
3333
#define PROG_VERSION PROG_VERSION_MAJOR "." PROG_VERSION_MINOR "." PROG_VERSION_BUILD
3434
#define PROG_NAME_FULL PROG_NAME " " PROG_VERSION
3535
#define PROG_NAME_CODE PROG_NAME_SHORT PROG_VERSION

0 commit comments

Comments
 (0)