Compare commits

..

9 Commits

Author SHA1 Message Date
bol-van
fc2d511d78 update changes.txt 2024-11-18 23:19:51 +03:00
bol-van
5207104c06 readme: fix-seg info 2024-11-18 23:19:11 +03:00
bol-van
06147836d0 tpws: segmentation failure warning and fix 2024-11-18 23:06:23 +03:00
bol-van
46eb30a897 build docs for unix and windows 2024-11-18 21:00:25 +03:00
bol-van
840617a0c3 install_easy: copy systemd units instead of linking 2024-11-18 20:42:55 +03:00
bol-van
f7ae5eaae5 doc works 2024-11-18 20:33:37 +03:00
bol-van
827a838715 doc works 2024-11-18 20:25:52 +03:00
bol-van
db5c60e19f doc works 2024-11-18 20:24:17 +03:00
bol-van
256c2d7e50 doc works 2024-11-18 16:28:22 +03:00
13 changed files with 769 additions and 518 deletions

View File

@ -143,7 +143,7 @@ $ ipfw -q -f flush
zapret, добавив в параметры `--daemon`. Например так: zapret, добавив в параметры `--daemon`. Например так:
```sh ```sh
$ pkill ^dvtws$ $ pkill ^dvtws$
$ /opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=split2 $ /opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=multisplit --dpi-desync-split-pos=2
``` ```
Для перезапуска фаервола и демонов достаточно будет сделать: Для перезапуска фаервола и демонов достаточно будет сделать:
@ -209,7 +209,7 @@ $ ipfw delete 100
$ ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0 $ ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0
# required for autottl mode only # required for autottl mode only
$ ipfw add 100 divert 989 tcp from any 80,443 to any tcpflags syn,ack in not diverted recv em0 $ ipfw add 100 divert 989 tcp from any 80,443 to any tcpflags syn,ack in not diverted recv em0
$ /opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2 $ /opt/zapret/nfq/dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
``` ```
#### Трафик только на таблицу zapret, за исключением таблицы nozapret #### Трафик только на таблицу zapret, за исключением таблицы nozapret
@ -220,7 +220,7 @@ $ ipfw add 100 allow tcp from me to table\(nozapret\) 80,443
$ ipfw add 100 divert 989 tcp from any to table\(zapret\) 80,443 out not diverted not sockarg xmit em0 $ ipfw add 100 divert 989 tcp from any to table\(zapret\) 80,443 out not diverted not sockarg xmit em0
# required for autottl mode only # required for autottl mode only
$ ipfw add 100 divert 989 tcp from table\(zapret\) 80,443 to any tcpflags syn,ack in not diverted not sockarg recv em0 $ ipfw add 100 divert 989 tcp from table\(zapret\) 80,443 to any tcpflags syn,ack in not diverted not sockarg recv em0
$ /opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2 $ /opt/zapret/nfq/dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
``` ```
@ -317,7 +317,7 @@ sysctl net.inet6.ip6.pfil.inbound=ipfw,pf
ipfw delete 100 ipfw delete 100
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0 ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0
pkill ^dvtws$ pkill ^dvtws$
dvtws --daemon --port 989 --dpi-desync=split2 dvtws --daemon --port 989 --dpi-desync=multisplit --dpi-desync-split-pos=2
# required for newer pfsense versions (2.6.0 tested) to return ipfw to functional state # required for newer pfsense versions (2.6.0 tested) to return ipfw to functional state
pfctl -d ; pfctl -e pfctl -d ; pfctl -e
@ -357,7 +357,7 @@ rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::20c:29ff:5ae3:4821 por
```sh ```sh
$ pfctl -a zapret -f /etc/zapret.anchor $ pfctl -a zapret -f /etc/zapret.anchor
$ pkill ^tpws$ $ pkill ^tpws$
$ tpws --daemon --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force --split-http-req=method --split-pos=2 $ tpws --daemon --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force --split-pos=2
``` ```
4. После перезагрузки проверьте, что правила создались: 4. После перезагрузки проверьте, что правила создались:
@ -424,7 +424,7 @@ pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no sta
```sh ```sh
$ pfctl -f /etc/pf.conf $ pfctl -f /etc/pf.conf
$ ./dvtws --port=989 --dpi-desync=split2 $ ./dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
``` ```
#### Трафик только на таблицу zapret, за исключением таблицы nozapret #### Трафик только на таблицу zapret, за исключением таблицы nozapret
@ -456,7 +456,7 @@ pass out quick on em0 inet6 proto tcp to <zapret6-user> port {80,443} divert-p
```sh ```sh
$ pfctl -f /etc/pf.conf $ pfctl -f /etc/pf.conf
$ ./dvtws --port=989 --dpi-desync=split2 $ ./dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
``` ```

View File

@ -70,7 +70,7 @@ pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet por
pass in quick on em0 proto tcp from port {80,443} no state pass in quick on em0 proto tcp from port {80,443} no state
pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no state pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no state
pfctl -f /etc/pf.conf pfctl -f /etc/pf.conf
./dvtws --port=989 --dpi-desync=split2 ./dvtws --port=989 --dpi-desync=multisplit --dpi-desync-split-pos=2
; dvtws with table limitations : to zapret,zapret6 but not to nozapret,nozapret6 ; dvtws with table limitations : to zapret,zapret6 but not to nozapret,nozapret6
; reload tables : pfctl -f /etc/pf.conf ; reload tables : pfctl -f /etc/pf.conf

View File

@ -363,3 +363,29 @@ nfqws,tpws: use alternate $ sign for $<config_file>
repo: binaries removed from repo. git actions binaries build in releases. repo: binaries removed from repo. git actions binaries build in releases.
uninstall_easy.sh: offer to remove dependencies in openwrt uninstall_easy.sh: offer to remove dependencies in openwrt
install_easy.sh: allow to download lists in autohostlist filter mode install_easy.sh: allow to download lists in autohostlist filter mode
v69:
nfqws, tpws: multisplit/multidisorder support.
nfqws: name change split->fakedsplit, disorder->fakeddisorder. compat : old names are synonyms
nfqws: --dpi-desync-split-http-req, --dpi-desync-split-tls deprecated. compat : these parameters add split point to multisplit.
nfqws: --dpi-desync=split2|disorder2 deprecated. compat: they are now synonyms for multisplit/multidisorder
nfqws: cancel seqovl if MTU is exceeded (linux only). cancel seqovl for disorder if seqovl>=first_part_size.
nfqws: fixed splits in multiple TLS segments.
tpws: --split-tls,--split-tls deprecated. compat : these parameters add split point to multisplit.
tpws: --tlsrec now takes pos markers. compat : old names are converted to pos markers
tpws: --tlsrec-pos deprecated. compat : sets absolute pos marker
nfqws,tpws: chown autohostlist, autohostlist debug log and debug log files after options parse
nfqws,tpws: set EXEDIR env var to use in @config (won't work for stadalone winws without /bin/sh)
dvtws: set random/increasing ip_id value in generated packets
mdig: fixed parsing of DNS reply in windows (stdin is opened as text, not binary)
tpws: support compile for android NDK api level >= 21 (Android 5.0)
tpws: --fix-seg segmentation fixer
repo: build for android NDK api level 21 (Android 5.0)
install_easy: support for APK package manager in openwrt
blockcheck: removed ignore CA question
blockcheck: removed IGNORE_CA, CURL_VERBOSE
blockcheck: added CURL_OPT
blockcheck: new strategies support
blockcheck: test sequence rework
blockcheck: view all working strategies in summary

View File

@ -0,0 +1,16 @@
debian,ubuntu :
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev
make -C /opt/zapret
FreeBSD :
make -C /opt/zapret
OpenBSD :
make -C /opt/zapret bsd
MacOS :
make -C /opt/zapret mac

View File

@ -0,0 +1,29 @@
Windows x64
1) Download latest cygwin for windows 7
curl -O https://www.cygwin.com/setup-x86_64.exe
setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215
2) During setup install packages : make gcc-core zlib-devel
3) Run Cygwin.bat
4) cd to %ZAPRET_BASE%/nfq
cd C:/Users/user/Downloads/zapret/nfq
5) Compile
make cygwin64
use winws.exe
6) Take windivert.dll and windivert64.sys here : https://reqrypt.org/download
Choose version 2.2.2 for Windows 10 and 2.2.0 for Windows 7.
7) Copy cygwin1.dll, winws.exe, windivert.dll and windivert64.sys to one folder.
8) Run winws.exe from cmd.exe running as administrator.
winws will not run from cygwin shell with cygwin1.dll copy in it's folder.
winws will not run without cygwin1.dll outside of cygwin shell.

View File

@ -1,4 +1,4 @@
# zapret v.68 # zapret v.69
# SCAMMER WARNING # SCAMMER WARNING

File diff suppressed because it is too large Load Diff

View File

@ -549,7 +549,7 @@ service_install_systemd()
if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then
rm -f "$INIT_SCRIPT" rm -f "$INIT_SCRIPT"
ln -fs "$EXEDIR/init.d/systemd/zapret.service" "$SYSTEMD_SYSTEM_DIR" cp -f "$EXEDIR/init.d/systemd/zapret.service" "$SYSTEMD_SYSTEM_DIR"
"$SYSTEMCTL" daemon-reload "$SYSTEMCTL" daemon-reload
"$SYSTEMCTL" enable zapret || { "$SYSTEMCTL" enable zapret || {
echo could not enable systemd service echo could not enable systemd service
@ -567,8 +567,8 @@ timer_install_systemd()
if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then
"$SYSTEMCTL" disable zapret-list-update.timer "$SYSTEMCTL" disable zapret-list-update.timer
"$SYSTEMCTL" stop zapret-list-update.timer "$SYSTEMCTL" stop zapret-list-update.timer
ln -fs "$EXEDIR/init.d/systemd/zapret-list-update.service" "$SYSTEMD_SYSTEM_DIR" cp -f "$EXEDIR/init.d/systemd/zapret-list-update.service" "$SYSTEMD_SYSTEM_DIR"
ln -fs "$EXEDIR/init.d/systemd/zapret-list-update.timer" "$SYSTEMD_SYSTEM_DIR" cp -f "$EXEDIR/init.d/systemd/zapret-list-update.timer" "$SYSTEMD_SYSTEM_DIR"
"$SYSTEMCTL" daemon-reload "$SYSTEMCTL" daemon-reload
"$SYSTEMCTL" enable zapret-list-update.timer || { "$SYSTEMCTL" enable zapret-list-update.timer || {
echo could not enable zapret-list-update.timer echo could not enable zapret-list-update.timer

View File

@ -11,6 +11,10 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <libgen.h> #include <libgen.h>
#ifdef __linux__
#include <linux/tcp.h>
#endif
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "andr/ifaddrs.h" #include "andr/ifaddrs.h"
#else #else
@ -34,9 +38,9 @@ static int cmp_size_t(const void * a, const void * b)
{ {
return *(size_t*)a < *(size_t*)b ? -1 : *(size_t*)a > *(size_t*)b; return *(size_t*)a < *(size_t*)b ? -1 : *(size_t*)a > *(size_t*)b;
} }
void qsort_size_t(size_t *array,size_t ct) void qsort_size_t(size_t *array, size_t ct)
{ {
qsort(array,ct,sizeof(*array),cmp_size_t); qsort(array, ct, sizeof(*array), cmp_size_t);
} }
@ -48,10 +52,10 @@ void rtrim(char *s)
void replace_char(char *s, char from, char to) void replace_char(char *s, char from, char to)
{ {
for(;*s;s++) if (*s==from) *s=to; for (; *s; s++) if (*s == from) *s = to;
} }
char *strncasestr(const char *s,const char *find, size_t slen) char *strncasestr(const char *s, const char *find, size_t slen)
{ {
char c, sc; char c, sc;
size_t len; size_t len;
@ -92,9 +96,9 @@ bool load_file(const char *filename, void *buffer, size_t *buffer_size)
bool append_to_list_file(const char *filename, const char *s) bool append_to_list_file(const char *filename, const char *s)
{ {
FILE *F = fopen(filename,"at"); FILE *F = fopen(filename, "at");
if (!F) return false; if (!F) return false;
bool bOK = fprintf(F,"%s\n",s)>0; bool bOK = fprintf(F, "%s\n", s) > 0;
fclose(F); fclose(F);
return bOK; return bOK;
} }
@ -102,7 +106,7 @@ bool append_to_list_file(const char *filename, const char *s)
void ntop46(const struct sockaddr *sa, char *str, size_t len) void ntop46(const struct sockaddr *sa, char *str, size_t len)
{ {
if (!len) return; if (!len) return;
*str=0; *str = 0;
switch (sa->sa_family) switch (sa->sa_family)
{ {
case AF_INET: case AF_INET:
@ -112,50 +116,50 @@ void ntop46(const struct sockaddr *sa, char *str, size_t len)
inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, str, len); inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, str, len);
break; break;
default: default:
snprintf(str,len,"UNKNOWN_FAMILY_%d",sa->sa_family); snprintf(str, len, "UNKNOWN_FAMILY_%d", sa->sa_family);
} }
} }
void ntop46_port(const struct sockaddr *sa, char *str, size_t len) void ntop46_port(const struct sockaddr *sa, char *str, size_t len)
{ {
char ip[40]; char ip[40];
ntop46(sa,ip,sizeof(ip)); ntop46(sa, ip, sizeof(ip));
switch (sa->sa_family) switch (sa->sa_family)
{ {
case AF_INET: case AF_INET:
snprintf(str,len,"%s:%u",ip,ntohs(((struct sockaddr_in*)sa)->sin_port)); snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in*)sa)->sin_port));
break; break;
case AF_INET6: case AF_INET6:
snprintf(str,len,"[%s]:%u",ip,ntohs(((struct sockaddr_in6*)sa)->sin6_port)); snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
break; break;
default: default:
snprintf(str,len,"%s",ip); snprintf(str, len, "%s", ip);
} }
} }
void print_sockaddr(const struct sockaddr *sa) void print_sockaddr(const struct sockaddr *sa)
{ {
char ip_port[48]; char ip_port[48];
ntop46_port(sa,ip_port,sizeof(ip_port)); ntop46_port(sa, ip_port, sizeof(ip_port));
printf("%s",ip_port); printf("%s", ip_port);
} }
// -1 = error, 0 = not local, 1 = local // -1 = error, 0 = not local, 1 = local
bool check_local_ip(const struct sockaddr *saddr) bool check_local_ip(const struct sockaddr *saddr)
{ {
struct ifaddrs *addrs,*a; struct ifaddrs *addrs, *a;
if (is_localnet(saddr)) if (is_localnet(saddr))
return true; return true;
if (getifaddrs(&addrs)<0) return false; if (getifaddrs(&addrs) < 0) return false;
a = addrs; a = addrs;
bool bres=false; bool bres = false;
while (a) while (a)
{ {
if (a->ifa_addr && sacmp(a->ifa_addr,saddr)) if (a->ifa_addr && sacmp(a->ifa_addr, saddr))
{ {
bres=true; bres = true;
break; break;
} }
a = a->ifa_next; a = a->ifa_next;
@ -177,7 +181,7 @@ void print_addrinfo(const struct addrinfo *ai)
break; break;
case AF_INET6: case AF_INET6:
if (inet_ntop(ai->ai_family, &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, str, sizeof(str))) if (inet_ntop(ai->ai_family, &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, str, sizeof(str)))
printf( "%s\n", str); printf("%s\n", str);
break; break;
} }
ai = ai->ai_next; ai = ai->ai_next;
@ -189,23 +193,23 @@ void print_addrinfo(const struct addrinfo *ai)
bool saismapped(const struct sockaddr_in6 *sa) bool saismapped(const struct sockaddr_in6 *sa)
{ {
// ::ffff:1.2.3.4 // ::ffff:1.2.3.4
return !memcmp(sa->sin6_addr.s6_addr,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff",12); return !memcmp(sa->sin6_addr.s6_addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff", 12);
} }
bool samappedcmp(const struct sockaddr_in *sa1,const struct sockaddr_in6 *sa2) bool samappedcmp(const struct sockaddr_in *sa1, const struct sockaddr_in6 *sa2)
{ {
return saismapped(sa2) && !memcmp(sa2->sin6_addr.s6_addr+12,&sa1->sin_addr.s_addr,4); return saismapped(sa2) && !memcmp(sa2->sin6_addr.s6_addr + 12, &sa1->sin_addr.s_addr, 4);
} }
bool sacmp(const struct sockaddr *sa1,const struct sockaddr *sa2) bool sacmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
{ {
return (sa1->sa_family==AF_INET && sa2->sa_family==AF_INET && !memcmp(&((struct sockaddr_in*)sa1)->sin_addr,&((struct sockaddr_in*)sa2)->sin_addr,sizeof(struct in_addr))) || return (sa1->sa_family == AF_INET && sa2->sa_family == AF_INET && !memcmp(&((struct sockaddr_in*)sa1)->sin_addr, &((struct sockaddr_in*)sa2)->sin_addr, sizeof(struct in_addr))) ||
(sa1->sa_family==AF_INET6 && sa2->sa_family==AF_INET6 && !memcmp(&((struct sockaddr_in6*)sa1)->sin6_addr,&((struct sockaddr_in6*)sa2)->sin6_addr,sizeof(struct in6_addr))) || (sa1->sa_family == AF_INET6 && sa2->sa_family == AF_INET6 && !memcmp(&((struct sockaddr_in6*)sa1)->sin6_addr, &((struct sockaddr_in6*)sa2)->sin6_addr, sizeof(struct in6_addr))) ||
(sa1->sa_family==AF_INET && sa2->sa_family==AF_INET6 && samappedcmp((struct sockaddr_in*)sa1,(struct sockaddr_in6*)sa2)) || (sa1->sa_family == AF_INET && sa2->sa_family == AF_INET6 && samappedcmp((struct sockaddr_in*)sa1, (struct sockaddr_in6*)sa2)) ||
(sa1->sa_family==AF_INET6 && sa2->sa_family==AF_INET && samappedcmp((struct sockaddr_in*)sa2,(struct sockaddr_in6*)sa1)); (sa1->sa_family == AF_INET6 && sa2->sa_family == AF_INET && samappedcmp((struct sockaddr_in*)sa2, (struct sockaddr_in6*)sa1));
} }
uint16_t saport(const struct sockaddr *sa) uint16_t saport(const struct sockaddr *sa)
{ {
return htons(sa->sa_family==AF_INET ? ((struct sockaddr_in*)sa)->sin_port : return htons(sa->sa_family == AF_INET ? ((struct sockaddr_in*)sa)->sin_port :
sa->sa_family==AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0); sa->sa_family == AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0);
} }
bool saconvmapped(struct sockaddr_storage *a) bool saconvmapped(struct sockaddr_storage *a)
{ {
@ -223,16 +227,16 @@ bool saconvmapped(struct sockaddr_storage *a)
void sacopy(struct sockaddr_storage *sa_dest, const struct sockaddr *sa) void sacopy(struct sockaddr_storage *sa_dest, const struct sockaddr *sa)
{ {
switch(sa->sa_family) switch (sa->sa_family)
{ {
case AF_INET: case AF_INET:
memcpy(sa_dest,sa,sizeof(struct sockaddr_in)); memcpy(sa_dest, sa, sizeof(struct sockaddr_in));
break; break;
case AF_INET6: case AF_INET6:
memcpy(sa_dest,sa,sizeof(struct sockaddr_in6)); memcpy(sa_dest, sa, sizeof(struct sockaddr_in6));
break; break;
default: default:
sa_dest->ss_family = 0; sa_dest->ss_family = 0;
} }
} }
void sa46copy(sockaddr_in46 *sa_dest, const struct sockaddr *sa) void sa46copy(sockaddr_in46 *sa_dest, const struct sockaddr *sa)
@ -243,17 +247,17 @@ void sa46copy(sockaddr_in46 *sa_dest, const struct sockaddr *sa)
bool is_localnet(const struct sockaddr *a) bool is_localnet(const struct sockaddr *a)
{ {
// match 127.0.0.0/8, 0.0.0.0, ::1, ::0, :ffff:127.0.0.0/104, :ffff:0.0.0.0 // match 127.0.0.0/8, 0.0.0.0, ::1, ::0, :ffff:127.0.0.0/104, :ffff:0.0.0.0
return (a->sa_family==AF_INET && (IN_LOOPBACK(ntohl(((struct sockaddr_in *)a)->sin_addr.s_addr)) || return (a->sa_family == AF_INET && (IN_LOOPBACK(ntohl(((struct sockaddr_in *)a)->sin_addr.s_addr)) ||
INADDR_ANY == ntohl((((struct sockaddr_in *)a)->sin_addr.s_addr)))) || INADDR_ANY == ntohl((((struct sockaddr_in *)a)->sin_addr.s_addr)))) ||
(a->sa_family==AF_INET6 && (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)a)->sin6_addr) || (a->sa_family == AF_INET6 && (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)a)->sin6_addr) ||
IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)a)->sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)a)->sin6_addr) ||
(IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr) && (IN_LOOPBACK(ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr))) || (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr) && (IN_LOOPBACK(ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr))) ||
INADDR_ANY == ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr)))))); INADDR_ANY == ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr))))));
} }
bool is_linklocal(const struct sockaddr_in6 *a) bool is_linklocal(const struct sockaddr_in6 *a)
{ {
// fe80::/10 // fe80::/10
return a->sin6_addr.s6_addr[0]==0xFE && (a->sin6_addr.s6_addr[1] & 0xC0)==0x80; return a->sin6_addr.s6_addr[0] == 0xFE && (a->sin6_addr.s6_addr[1] & 0xC0) == 0x80;
} }
bool is_private6(const struct sockaddr_in6* a) bool is_private6(const struct sockaddr_in6* a)
{ {
@ -265,23 +269,23 @@ bool is_private6(const struct sockaddr_in6* a)
bool set_keepalive(int fd) bool set_keepalive(int fd)
{ {
int yes=1; int yes = 1;
return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int))!=-1; return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int)) != -1;
} }
bool set_ttl(int fd, int ttl) bool set_ttl(int fd, int ttl)
{ {
return setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))!=-1; return setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) != -1;
} }
bool set_hl(int fd, int hl) bool set_hl(int fd, int hl)
{ {
return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hl, sizeof(hl))!=-1; return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hl, sizeof(hl)) != -1;
} }
bool set_ttl_hl(int fd, int ttl) bool set_ttl_hl(int fd, int ttl)
{ {
bool b1,b2; bool b1, b2;
// try to set both but one may fail if family is wrong // try to set both but one may fail if family is wrong
b1=set_ttl(fd, ttl); b1 = set_ttl(fd, ttl);
b2=set_hl(fd, ttl); b2 = set_hl(fd, ttl);
return b1 || b2; return b1 || b2;
} }
int get_so_error(int fd) int get_so_error(int fd)
@ -289,8 +293,8 @@ int get_so_error(int fd)
// getsockopt(SO_ERROR) clears error // getsockopt(SO_ERROR) clears error
int errn; int errn;
socklen_t optlen = sizeof(errn); socklen_t optlen = sizeof(errn);
if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1) if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1)
errn=errno; errn = errno;
return errn; return errn;
} }
@ -300,53 +304,53 @@ int fprint_localtime(FILE *F)
time_t now; time_t now;
time(&now); time(&now);
localtime_r(&now,&t); localtime_r(&now, &t);
return fprintf(F, "%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec); return fprintf(F, "%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
} }
time_t file_mod_time(const char *filename) time_t file_mod_time(const char *filename)
{ {
struct stat st; struct stat st;
return stat(filename,&st)==-1 ? 0 : st.st_mtime; return stat(filename, &st) == -1 ? 0 : st.st_mtime;
} }
bool pf_in_range(uint16_t port, const port_filter *pf) bool pf_in_range(uint16_t port, const port_filter *pf)
{ {
return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg); return port && (((!pf->from && !pf->to) || (port >= pf->from && port <= pf->to)) ^ pf->neg);
} }
bool pf_parse(const char *s, port_filter *pf) bool pf_parse(const char *s, port_filter *pf)
{ {
unsigned int v1,v2; unsigned int v1, v2;
char c; char c;
if (!s) return false; if (!s) return false;
if (*s=='*' && s[1]==0) if (*s == '*' && s[1] == 0)
{ {
pf->from=1; pf->to=0xFFFF; pf->from = 1; pf->to = 0xFFFF;
return true; return true;
} }
if (*s=='~') if (*s == '~')
{ {
pf->neg=true; pf->neg = true;
s++; s++;
} }
else else
pf->neg=false; pf->neg = false;
if (sscanf(s,"%u-%u%c",&v1,&v2,&c)==2) if (sscanf(s, "%u-%u%c", &v1, &v2, &c) == 2)
{ {
if (v1>65535 || v2>65535 || v1>v2) return false; if (v1 > 65535 || v2 > 65535 || v1 > v2) return false;
pf->from=(uint16_t)v1; pf->from = (uint16_t)v1;
pf->to=(uint16_t)v2; pf->to = (uint16_t)v2;
} }
else if (sscanf(s,"%u%c",&v1,&c)==1) else if (sscanf(s, "%u%c", &v1, &c) == 1)
{ {
if (v1>65535) return false; if (v1 > 65535) return false;
pf->to=pf->from=(uint16_t)v1; pf->to = pf->from = (uint16_t)v1;
} }
else else
return false; return false;
// deny all case // deny all case
if (!pf->from && !pf->to) pf->neg=true; if (!pf->from && !pf->to) pf->neg = true;
return true; return true;
} }
bool pf_is_empty(const port_filter *pf) bool pf_is_empty(const port_filter *pf)
@ -357,12 +361,12 @@ bool pf_is_empty(const port_filter *pf)
bool set_env_exedir(const char *argv0) bool set_env_exedir(const char *argv0)
{ {
char *s,*d; char *s, *d;
bool bOK=false; bool bOK = false;
if ((s = strdup(argv0))) if ((s = strdup(argv0)))
{ {
if ((d = dirname(s))) if ((d = dirname(s)))
setenv("EXEDIR",s,1); setenv("EXEDIR", s, 1);
free(s); free(s);
} }
return bOK; return bOK;
@ -372,23 +376,23 @@ bool set_env_exedir(const char *argv0)
static void mask_from_preflen6_make(uint8_t plen, struct in6_addr *a) static void mask_from_preflen6_make(uint8_t plen, struct in6_addr *a)
{ {
if (plen >= 128) if (plen >= 128)
memset(a->s6_addr,0xFF,16); memset(a->s6_addr, 0xFF, 16);
else else
{ {
uint8_t n = plen >> 3; uint8_t n = plen >> 3;
memset(a->s6_addr,0xFF,n); memset(a->s6_addr, 0xFF, n);
memset(a->s6_addr+n,0x00,16-n); memset(a->s6_addr + n, 0x00, 16 - n);
a->s6_addr[n] = (uint8_t)(0xFF00 >> (plen & 7)); a->s6_addr[n] = (uint8_t)(0xFF00 >> (plen & 7));
} }
} }
struct in6_addr ip6_mask[129]; struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void) void mask_from_preflen6_prepare(void)
{ {
for (int plen=0;plen<=128;plen++) mask_from_preflen6_make(plen, ip6_mask+plen); for (int plen = 0; plen <= 128; plen++) mask_from_preflen6_make(plen, ip6_mask + plen);
} }
#if defined(__GNUC__) && !defined(__llvm__) #if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing"))) __attribute__((optimize("no-strict-aliasing")))
#endif #endif
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result) void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result)
{ {
@ -400,64 +404,116 @@ void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restric
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr) void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
{ {
char s_ip[16]; char s_ip[16];
*s_ip=0; *s_ip = 0;
inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip)); inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<32 ? "%s/%u" : "%s", s_ip, cidr->preflen); snprintf(s, s_len, cidr->preflen < 32 ? "%s/%u" : "%s", s_ip, cidr->preflen);
} }
void print_cidr4(const struct cidr4 *cidr) void print_cidr4(const struct cidr4 *cidr)
{ {
char s[19]; char s[19];
str_cidr4(s,sizeof(s),cidr); str_cidr4(s, sizeof(s), cidr);
printf("%s",s); printf("%s", s);
} }
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr) void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr)
{ {
char s_ip[40]; char s_ip[40];
*s_ip=0; *s_ip = 0;
inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip)); inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<128 ? "%s/%u" : "%s", s_ip, cidr->preflen); snprintf(s, s_len, cidr->preflen < 128 ? "%s/%u" : "%s", s_ip, cidr->preflen);
} }
void print_cidr6(const struct cidr6 *cidr) void print_cidr6(const struct cidr6 *cidr)
{ {
char s[44]; char s[44];
str_cidr6(s,sizeof(s),cidr); str_cidr6(s, sizeof(s), cidr);
printf("%s",s); printf("%s", s);
} }
bool parse_cidr4(char *s, struct cidr4 *cidr) bool parse_cidr4(char *s, struct cidr4 *cidr)
{ {
char *p,d; char *p, d;
bool b; bool b;
unsigned int plen; unsigned int plen;
if ((p = strchr(s, '/'))) if ((p = strchr(s, '/')))
{ {
if (sscanf(p + 1, "%u", &plen)!=1 || plen>32) if (sscanf(p + 1, "%u", &plen) != 1 || plen > 32)
return false; return false;
cidr->preflen = (uint8_t)plen; cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char d = *p; *p = 0; // backup char
} }
else else
cidr->preflen = 32; cidr->preflen = 32;
b = (inet_pton(AF_INET, s, &cidr->addr)==1); b = (inet_pton(AF_INET, s, &cidr->addr) == 1);
if (p) *p=d; // restore char if (p) *p = d; // restore char
return b; return b;
} }
bool parse_cidr6(char *s, struct cidr6 *cidr) bool parse_cidr6(char *s, struct cidr6 *cidr)
{ {
char *p,d; char *p, d;
bool b; bool b;
unsigned int plen; unsigned int plen;
if ((p = strchr(s, '/'))) if ((p = strchr(s, '/')))
{ {
if (sscanf(p + 1, "%u", &plen)!=1 || plen>128) if (sscanf(p + 1, "%u", &plen) != 1 || plen > 128)
return false; return false;
cidr->preflen = (uint8_t)plen; cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char d = *p; *p = 0; // backup char
} }
else else
cidr->preflen = 128; cidr->preflen = 128;
b = (inet_pton(AF_INET6, s, &cidr->addr)==1); b = (inet_pton(AF_INET6, s, &cidr->addr) == 1);
if (p) *p=d; // restore char if (p) *p = d; // restore char
return b; return b;
} }
void msleep(unsigned int ms)
{
struct timespec time = {
.tv_nsec = (ms % 1000) * 1000000,
.tv_sec = ms / 1000
};
nanosleep(&time, 0);
}
#ifdef __linux__
bool socket_has_notsent(int sfd)
{
struct tcp_info tcpi;
socklen_t ts = sizeof(tcpi);
if (getsockopt(sfd, IPPROTO_TCP, TCP_INFO, (char *)&tcpi, &ts) < 0)
return false;
if (tcpi.tcpi_state != 1)
return false;
size_t s = (char *)&tcpi.tcpi_notsent_bytes - (char *)&tcpi.tcpi_state;
if (ts < s)
return false;
return !!tcpi.tcpi_notsent_bytes;
}
bool socket_wait_notsent(int sfd, unsigned int delay_ms, unsigned int *wasted_ms)
{
struct timespec tres;
unsigned int mtick;
if (wasted_ms) *wasted_ms=0;
if (!socket_has_notsent(sfd)) return true;
if (clock_getres(CLOCK_MONOTONIC,&tres))
{
tres.tv_nsec = 10000000;
tres.tv_sec = 0;
}
mtick = (unsigned int)(tres.tv_sec*1000) + (unsigned int)(tres.tv_nsec/1000000);
if (mtick<1) mtick=1;
for(;;)
{
msleep(mtick);
if (wasted_ms) *wasted_ms+=mtick;
if (!socket_has_notsent(sfd)) return true;
if (delay_ms<=mtick) break;
delay_ms-=mtick;
}
return false;
}
#endif

View File

@ -117,3 +117,9 @@ static inline const struct in6_addr *mask_from_preflen6(uint8_t preflen)
{ {
return ip6_mask+preflen; return ip6_mask+preflen;
} }
void msleep(unsigned int ms);
#ifdef __linux__
bool socket_has_notsent(int sfd);
bool socket_wait_notsent(int sfd, unsigned int delay_ms, unsigned int *wasted_ms);
#endif

View File

@ -104,6 +104,7 @@ struct params_s
uint8_t proxy_type; uint8_t proxy_type;
bool no_resolve; bool no_resolve;
bool skip_nodelay; bool skip_nodelay;
bool fix_seg;
bool droproot; bool droproot;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;

View File

@ -169,6 +169,9 @@ static void exithelp(void)
" --uid=uid[:gid]\t\t\t; drop root privs\n" " --uid=uid[:gid]\t\t\t; drop root privs\n"
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
" --enable-pf\t\t\t\t; enable PF redirector support. required in FreeBSD when used with PF firewall.\n" " --enable-pf\t\t\t\t; enable PF redirector support. required in FreeBSD when used with PF firewall.\n"
#endif
#if defined(__linux__)
" --fix-seg\t\t\t\t; fix segmentation failures at the cost of possible slowdown\n"
#endif #endif
" --debug=0|1|2|syslog|@<filename>\t; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n" " --debug=0|1|2|syslog|@<filename>\t; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n"
" --debug-level=0|1|2\t\t\t; specify debug level\n" " --debug-level=0|1|2\t\t\t; specify debug level\n"
@ -635,8 +638,9 @@ void parse_params(int argc, char *argv[])
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=62 { "local-tcp-user-timeout",required_argument,0,0 }, // optidx=62
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=63 { "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=63
{ "mss",required_argument,0,0 }, // optidx=64 { "mss",required_argument,0,0 }, // optidx=64
{ "fix-seg",no_argument,0,0 }, // optidx=65
#ifdef SPLICE_PRESENT #ifdef SPLICE_PRESENT
{ "nosplice",no_argument,0,0 }, // optidx=65 { "nosplice",no_argument,0,0 }, // optidx=66
#endif #endif
#endif #endif
{ "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility { "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility
@ -1228,8 +1232,11 @@ void parse_params(int argc, char *argv[])
exit_clean(1); exit_clean(1);
} }
break; break;
case 65: /* fix-seg */
params.fix_seg = true;
break;
#ifdef SPLICE_PRESENT #ifdef SPLICE_PRESENT
case 65: /* nosplice */ case 66: /* nosplice */
params.nosplice = true; params.nosplice = true;
break; break;
#endif #endif

View File

@ -1244,7 +1244,21 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
if (wr>0) conn->partner->twr += wr; if (wr>0) conn->partner->twr += wr;
break; break;
} }
#ifdef __linux__
if (params.fix_seg)
{
unsigned int wasted;
if (!socket_wait_notsent(conn->partner->fd, 20, &wasted))
DLOG_ERR("WARNING ! segmentation failed\n");
if (wasted)
VPRINT("WARNING ! wasted %u ms to fix segmenation\n", wasted);
}
else
{
if (socket_has_notsent(conn->partner->fd))
DLOG_ERR("WARNING ! segmentation failed\n");
}
#endif
from = to; from = to;
} }
} }