mirror of
https://github.com/bol-van/zapret.git
synced 2024-11-30 05:50:53 +03:00
tpws: multi-strategy
This commit is contained in:
parent
9684e647ab
commit
d4a7eef17e
@ -164,6 +164,21 @@ bool saconvmapped(struct sockaddr_storage *a)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sacopy(struct sockaddr_storage *sa_dest, const struct sockaddr *sa)
|
||||||
|
{
|
||||||
|
switch(sa->sa_family)
|
||||||
|
{
|
||||||
|
case AF_INET:
|
||||||
|
memcpy(sa_dest,sa,sizeof(struct sockaddr_in));
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
memcpy(sa_dest,sa,sizeof(struct sockaddr_in6));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sa_dest->ss_family = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
@ -243,7 +258,7 @@ bool pf_parse(const char *s, port_filter *pf)
|
|||||||
unsigned int v1,v2;
|
unsigned int v1,v2;
|
||||||
|
|
||||||
if (!s) return false;
|
if (!s) return false;
|
||||||
if (*s=='~')
|
if (*s=='~')
|
||||||
{
|
{
|
||||||
pf->neg=true;
|
pf->neg=true;
|
||||||
s++;
|
s++;
|
||||||
@ -252,16 +267,22 @@ bool pf_parse(const char *s, port_filter *pf)
|
|||||||
pf->neg=false;
|
pf->neg=false;
|
||||||
if (sscanf(s,"%u-%u",&v1,&v2)==2)
|
if (sscanf(s,"%u-%u",&v1,&v2)==2)
|
||||||
{
|
{
|
||||||
if (!v1 || 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",&v1)==1)
|
else if (sscanf(s,"%u",&v1)==1)
|
||||||
{
|
{
|
||||||
if (!v1 || 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
|
||||||
|
if (!pf->from && !pf->to) pf->neg=true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
bool pf_is_empty(const port_filter *pf)
|
||||||
|
{
|
||||||
|
return !pf->neg && !pf->from && !pf->to;
|
||||||
|
}
|
||||||
|
@ -25,6 +25,8 @@ uint16_t saport(const struct sockaddr *sa);
|
|||||||
// true = was converted
|
// true = was converted
|
||||||
bool saconvmapped(struct sockaddr_storage *a);
|
bool saconvmapped(struct sockaddr_storage *a);
|
||||||
|
|
||||||
|
void sacopy(struct sockaddr_storage *sa_dest, const struct sockaddr *sa);
|
||||||
|
|
||||||
bool is_localnet(const struct sockaddr *a);
|
bool is_localnet(const struct sockaddr *a);
|
||||||
bool is_linklocal(const struct sockaddr_in6* a);
|
bool is_linklocal(const struct sockaddr_in6* a);
|
||||||
bool is_private6(const struct sockaddr_in6* a);
|
bool is_private6(const struct sockaddr_in6* a);
|
||||||
@ -55,6 +57,7 @@ typedef struct
|
|||||||
} port_filter;
|
} port_filter;
|
||||||
bool pf_in_range(uint16_t port, const port_filter *pf);
|
bool pf_in_range(uint16_t port, const port_filter *pf);
|
||||||
bool pf_parse(const char *s, port_filter *pf);
|
bool pf_parse(const char *s, port_filter *pf);
|
||||||
|
bool pf_is_empty(const port_filter *pf);
|
||||||
|
|
||||||
#ifndef IN_LOOPBACK
|
#ifndef IN_LOOPBACK
|
||||||
#define IN_LOOPBACK(a) ((((uint32_t) (a)) & 0xff000000) == 0x7f000000)
|
#define IN_LOOPBACK(a) ((((uint32_t) (a)) & 0xff000000) == 0x7f000000)
|
||||||
|
@ -154,35 +154,53 @@ static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const c
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return : true = apply fooling, false = do not apply
|
static bool LoadIncludeHostListsForProfile(struct desync_profile *dp)
|
||||||
bool HostlistCheck(const char *host, bool *excluded)
|
|
||||||
{
|
{
|
||||||
if (*params.hostlist_auto_filename)
|
if (!LoadHostLists(&dp->hostlist, &dp->hostlist_files))
|
||||||
|
return false;
|
||||||
|
if (*dp->hostlist_auto_filename)
|
||||||
{
|
{
|
||||||
time_t t = file_mod_time(params.hostlist_auto_filename);
|
dp->hostlist_auto_mod_time = file_mod_time(dp->hostlist_auto_filename);
|
||||||
if (t!=params.hostlist_auto_mod_time)
|
NonEmptyHostlist(&dp->hostlist);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return : true = apply fooling, false = do not apply
|
||||||
|
bool HostlistCheck(struct desync_profile *dp, const char *host, bool *excluded)
|
||||||
|
{
|
||||||
|
VPRINT("* Hostlist check for profile %d\n",dp->n);
|
||||||
|
if (*dp->hostlist_auto_filename)
|
||||||
|
{
|
||||||
|
time_t t = file_mod_time(dp->hostlist_auto_filename);
|
||||||
|
if (t!=dp->hostlist_auto_mod_time)
|
||||||
{
|
{
|
||||||
DLOG_CONDUP("Autohostlist was modified by another process. Reloading include hostslist.\n");
|
DLOG_CONDUP("Autohostlist '%s' from profile %d was modified. Reloading include hostlists for this profile.\n",dp->hostlist_auto_filename, dp->n);
|
||||||
if (!LoadIncludeHostLists())
|
if (!LoadIncludeHostListsForProfile(dp))
|
||||||
{
|
{
|
||||||
// what will we do without hostlist ?? sure, gonna die
|
// what will we do without hostlist ?? sure, gonna die
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
params.hostlist_auto_mod_time = t;
|
dp->hostlist_auto_mod_time = t;
|
||||||
|
NonEmptyHostlist(&dp->hostlist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return HostlistCheck_(params.hostlist, params.hostlist_exclude, host, excluded);
|
return HostlistCheck_(dp->hostlist, dp->hostlist_exclude, host, excluded);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadIncludeHostLists()
|
bool LoadIncludeHostLists()
|
||||||
{
|
{
|
||||||
if (!LoadHostLists(¶ms.hostlist, ¶ms.hostlist_files))
|
struct desync_profile_list *dpl;
|
||||||
return false;
|
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||||
if (*params.hostlist_auto_filename)
|
if (!LoadIncludeHostListsForProfile(&dpl->dp))
|
||||||
params.hostlist_auto_mod_time = file_mod_time(params.hostlist_auto_filename);
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool LoadExcludeHostLists()
|
bool LoadExcludeHostLists()
|
||||||
{
|
{
|
||||||
return LoadHostLists(¶ms.hostlist_exclude, ¶ms.hostlist_exclude_files);
|
struct desync_profile_list *dpl;
|
||||||
|
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||||
|
if (!LoadHostLists(&dpl->dp.hostlist_exclude, &dpl->dp.hostlist_exclude_files))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "pools.h"
|
#include "pools.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
bool AppendHostList(strpool **hostlist, char *filename);
|
bool AppendHostList(strpool **hostlist, char *filename);
|
||||||
bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list);
|
bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list);
|
||||||
@ -10,4 +11,4 @@ bool LoadExcludeHostLists();
|
|||||||
bool NonEmptyHostlist(strpool **hostlist);
|
bool NonEmptyHostlist(strpool **hostlist);
|
||||||
bool SearchHostList(strpool *hostlist, const char *host);
|
bool SearchHostList(strpool *hostlist, const char *host);
|
||||||
// return : true = apply fooling, false = do not apply
|
// return : true = apply fooling, false = do not apply
|
||||||
bool HostlistCheck(const char *host, bool *excluded);
|
bool HostlistCheck(struct desync_profile *dp,const char *host, bool *excluded);
|
@ -138,3 +138,56 @@ int HOSTLIST_DEBUGLOG_APPEND(const char *format, ...)
|
|||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
|
||||||
|
{
|
||||||
|
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
|
||||||
|
if (!entry) return NULL;
|
||||||
|
|
||||||
|
LIST_INIT(&entry->dp.hostlist_files);
|
||||||
|
LIST_INIT(&entry->dp.hostlist_exclude_files);
|
||||||
|
entry->dp.filter_ipv4 = entry->dp.filter_ipv6 = true;
|
||||||
|
|
||||||
|
memcpy(entry->dp.hostspell, "host", 4); // default hostspell
|
||||||
|
entry->dp.hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
|
||||||
|
entry->dp.hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
|
||||||
|
|
||||||
|
// add to the tail
|
||||||
|
struct desync_profile_list *dpn,*dpl=LIST_FIRST(¶ms.desync_profiles);
|
||||||
|
if (dpl)
|
||||||
|
{
|
||||||
|
while ((dpn=LIST_NEXT(dpl,next))) dpl = dpn;
|
||||||
|
LIST_INSERT_AFTER(dpl, entry, next);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LIST_INSERT_HEAD(¶ms.desync_profiles, entry, next);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
static void dp_entry_destroy(struct desync_profile_list *entry)
|
||||||
|
{
|
||||||
|
strlist_destroy(&entry->dp.hostlist_files);
|
||||||
|
strlist_destroy(&entry->dp.hostlist_exclude_files);
|
||||||
|
StrPoolDestroy(&entry->dp.hostlist_exclude);
|
||||||
|
StrPoolDestroy(&entry->dp.hostlist);
|
||||||
|
HostFailPoolDestroy(&entry->dp.hostlist_auto_fail_counters);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
void dp_list_destroy(struct desync_profile_list_head *head)
|
||||||
|
{
|
||||||
|
struct desync_profile_list *entry;
|
||||||
|
while ((entry = LIST_FIRST(head)))
|
||||||
|
{
|
||||||
|
LIST_REMOVE(entry, next);
|
||||||
|
dp_entry_destroy(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool dp_list_have_autohostlist(struct desync_profile_list_head *head)
|
||||||
|
{
|
||||||
|
struct desync_profile_list *dpl;
|
||||||
|
LIST_FOREACH(dpl, head, next)
|
||||||
|
if (*dpl->dp.hostlist_auto_filename)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -27,27 +27,10 @@ struct bind_s
|
|||||||
|
|
||||||
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
||||||
|
|
||||||
struct params_s
|
struct desync_profile
|
||||||
{
|
{
|
||||||
struct bind_s binds[MAX_BINDS];
|
int n; // number of the profile
|
||||||
int binds_last;
|
|
||||||
bool bind_wait_only;
|
|
||||||
uint16_t port;
|
|
||||||
|
|
||||||
uint8_t proxy_type;
|
|
||||||
bool no_resolve;
|
|
||||||
bool skip_nodelay;
|
|
||||||
bool droproot;
|
|
||||||
uid_t uid;
|
|
||||||
gid_t gid;
|
|
||||||
bool daemon;
|
|
||||||
int maxconn,resolver_threads,maxfiles,max_orphan_time;
|
|
||||||
int local_rcvbuf,local_sndbuf,remote_rcvbuf,remote_sndbuf;
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
|
||||||
int tcp_user_timeout_local,tcp_user_timeout_remote;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool tamper; // any tamper option is set
|
|
||||||
bool hostcase, hostdot, hosttab, hostnospace, methodspace, methodeol, unixeol, domcase;
|
bool hostcase, hostdot, hosttab, hostnospace, methodspace, methodeol, unixeol, domcase;
|
||||||
int hostpad;
|
int hostpad;
|
||||||
char hostspell[4];
|
char hostspell[4];
|
||||||
@ -60,30 +43,59 @@ struct params_s
|
|||||||
bool disorder, disorder_http, disorder_tls;
|
bool disorder, disorder_http, disorder_tls;
|
||||||
bool oob, oob_http, oob_tls;
|
bool oob, oob_http, oob_tls;
|
||||||
uint8_t oob_byte;
|
uint8_t oob_byte;
|
||||||
int ttl_default;
|
|
||||||
|
|
||||||
int mss;
|
int mss;
|
||||||
port_filter mss_pf;
|
|
||||||
|
|
||||||
char pidfile[256];
|
|
||||||
|
|
||||||
strpool *hostlist, *hostlist_exclude;
|
|
||||||
struct str_list_head hostlist_files, hostlist_exclude_files;
|
|
||||||
char hostlist_auto_filename[PATH_MAX], hostlist_auto_debuglog[PATH_MAX];
|
|
||||||
int hostlist_auto_fail_threshold, hostlist_auto_fail_time;
|
|
||||||
time_t hostlist_auto_mod_time;
|
|
||||||
hostfail_pool *hostlist_auto_fail_counters;
|
|
||||||
|
|
||||||
bool tamper_start_n,tamper_cutoff_n;
|
bool tamper_start_n,tamper_cutoff_n;
|
||||||
unsigned int tamper_start,tamper_cutoff;
|
unsigned int tamper_start,tamper_cutoff;
|
||||||
|
|
||||||
|
bool filter_ipv4,filter_ipv6;
|
||||||
|
port_filter pf_tcp;
|
||||||
|
|
||||||
|
strpool *hostlist, *hostlist_exclude;
|
||||||
|
struct str_list_head hostlist_files, hostlist_exclude_files;
|
||||||
|
char hostlist_auto_filename[PATH_MAX];
|
||||||
|
int hostlist_auto_fail_threshold, hostlist_auto_fail_time;
|
||||||
|
time_t hostlist_auto_mod_time;
|
||||||
|
hostfail_pool *hostlist_auto_fail_counters;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct desync_profile_list {
|
||||||
|
struct desync_profile dp;
|
||||||
|
LIST_ENTRY(desync_profile_list) next;
|
||||||
|
};
|
||||||
|
LIST_HEAD(desync_profile_list_head, desync_profile_list);
|
||||||
|
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head);
|
||||||
|
void dp_list_destroy(struct desync_profile_list_head *head);
|
||||||
|
bool dp_list_have_autohostlist(struct desync_profile_list_head *head);
|
||||||
|
|
||||||
|
struct params_s
|
||||||
|
{
|
||||||
|
int debug;
|
||||||
|
enum log_target debug_target;
|
||||||
|
char debug_logfile[PATH_MAX];
|
||||||
|
|
||||||
|
struct bind_s binds[MAX_BINDS];
|
||||||
|
int binds_last;
|
||||||
|
bool bind_wait_only;
|
||||||
|
uint16_t port;
|
||||||
struct sockaddr_in connect_bind4;
|
struct sockaddr_in connect_bind4;
|
||||||
struct sockaddr_in6 connect_bind6;
|
struct sockaddr_in6 connect_bind6;
|
||||||
char connect_bind6_ifname[IF_NAMESIZE];
|
char connect_bind6_ifname[IF_NAMESIZE];
|
||||||
|
|
||||||
int debug;
|
uint8_t proxy_type;
|
||||||
enum log_target debug_target;
|
bool no_resolve;
|
||||||
char debug_logfile[PATH_MAX];
|
bool skip_nodelay;
|
||||||
|
bool droproot;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
bool daemon;
|
||||||
|
char pidfile[256];
|
||||||
|
int maxconn,resolver_threads,maxfiles,max_orphan_time;
|
||||||
|
int local_rcvbuf,local_sndbuf,remote_rcvbuf,remote_sndbuf;
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
int tcp_user_timeout_local,tcp_user_timeout_remote;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(BSD)
|
#if defined(BSD)
|
||||||
bool pf_enable;
|
bool pf_enable;
|
||||||
@ -91,6 +103,13 @@ struct params_s
|
|||||||
#ifdef SPLICE_PRESENT
|
#ifdef SPLICE_PRESENT
|
||||||
bool nosplice;
|
bool nosplice;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int ttl_default;
|
||||||
|
char hostlist_auto_debuglog[PATH_MAX];
|
||||||
|
|
||||||
|
bool tamper; // any tamper option is set
|
||||||
|
bool tamper_lim; // tamper-start or tamper-cutoff set in any profile
|
||||||
|
struct desync_profile_list_head desync_profiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct params_s params;
|
extern struct params_s params;
|
||||||
|
@ -25,12 +25,45 @@ bool IsHttp(const uint8_t *data, size_t len)
|
|||||||
{
|
{
|
||||||
return !!HttpMethod(data,len);
|
return !!HttpMethod(data,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsHostAt(const uint8_t *p)
|
||||||
|
{
|
||||||
|
return \
|
||||||
|
p[0]=='\n' &&
|
||||||
|
(p[1]=='H' || p[1]=='h') &&
|
||||||
|
(p[2]=='o' || p[2]=='O') &&
|
||||||
|
(p[3]=='s' || p[3]=='S') &&
|
||||||
|
(p[4]=='t' || p[4]=='T') &&
|
||||||
|
p[5]==':';
|
||||||
|
}
|
||||||
|
static uint8_t *FindHostIn(uint8_t *buf, size_t bs)
|
||||||
|
{
|
||||||
|
size_t pos;
|
||||||
|
if (bs<6) return NULL;
|
||||||
|
bs-=6;
|
||||||
|
for(pos=0;pos<=bs;pos++)
|
||||||
|
if (IsHostAt(buf+pos))
|
||||||
|
return buf+pos;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static const uint8_t *FindHostInConst(const uint8_t *buf, size_t bs)
|
||||||
|
{
|
||||||
|
size_t pos;
|
||||||
|
if (bs<6) return NULL;
|
||||||
|
bs-=6;
|
||||||
|
for(pos=0;pos<=bs;pos++)
|
||||||
|
if (IsHostAt(buf+pos))
|
||||||
|
return buf+pos;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
// pHost points to "Host: ..."
|
// pHost points to "Host: ..."
|
||||||
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs)
|
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs)
|
||||||
{
|
{
|
||||||
if (!*pHost)
|
if (!*pHost)
|
||||||
{
|
{
|
||||||
*pHost = memmem(buf, bs, "\nHost:", 6);
|
*pHost = FindHostIn(buf, bs);
|
||||||
if (*pHost) (*pHost)++;
|
if (*pHost) (*pHost)++;
|
||||||
}
|
}
|
||||||
return !!*pHost;
|
return !!*pHost;
|
||||||
@ -39,7 +72,7 @@ bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs)
|
|||||||
{
|
{
|
||||||
if (!*pHost)
|
if (!*pHost)
|
||||||
{
|
{
|
||||||
*pHost = memmem(buf, bs, "\nHost:", 6);
|
*pHost = FindHostInConst(buf, bs);
|
||||||
if (*pHost) (*pHost)++;
|
if (*pHost) (*pHost)++;
|
||||||
}
|
}
|
||||||
return !!*pHost;
|
return !!*pHost;
|
||||||
@ -132,7 +165,7 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
|||||||
}
|
}
|
||||||
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
|
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
|
||||||
{
|
{
|
||||||
const uint8_t *method, *host;
|
const uint8_t *method, *host=NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
switch(tpos_type)
|
switch(tpos_type)
|
||||||
|
316
tpws/tamper.c
316
tpws/tamper.c
@ -1,24 +1,87 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include "tamper.h"
|
#include "tamper.h"
|
||||||
#include "params.h"
|
|
||||||
#include "hostlist.h"
|
#include "hostlist.h"
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static bool dp_match_l3l4(struct desync_profile *dp, bool ipv6, uint16_t tcp_port)
|
||||||
|
{
|
||||||
|
return \
|
||||||
|
((!ipv6 && dp->filter_ipv4) || (ipv6 && dp->filter_ipv6)) &&
|
||||||
|
(!tcp_port || pf_in_range(tcp_port,&dp->pf_tcp));
|
||||||
|
}
|
||||||
|
static bool dp_match(struct desync_profile *dp, bool ipv6, uint16_t tcp_port, const char *hostname)
|
||||||
|
{
|
||||||
|
if (dp_match_l3l4(dp,ipv6,tcp_port))
|
||||||
|
{
|
||||||
|
// autohostlist profile matching l3/l4 filter always win
|
||||||
|
if (*dp->hostlist_auto_filename) return true;
|
||||||
|
|
||||||
|
if (dp->hostlist || dp->hostlist_exclude)
|
||||||
|
{
|
||||||
|
// without known hostname first profile matching l3/l4 filter and without hostlist filter wins
|
||||||
|
if (hostname)
|
||||||
|
return HostlistCheck(dp, hostname, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// profile without hostlist filter wins
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static struct desync_profile *dp_find(struct desync_profile_list_head *head, bool ipv6, uint16_t tcp_port, const char *hostname)
|
||||||
|
{
|
||||||
|
struct desync_profile_list *dpl;
|
||||||
|
VPRINT("desync profile search for hostname='%s' ipv6=%u tcp_port=%u\n", hostname ? hostname : "", ipv6, tcp_port);
|
||||||
|
LIST_FOREACH(dpl, head, next)
|
||||||
|
{
|
||||||
|
if (dp_match(&dpl->dp,ipv6,tcp_port,hostname))
|
||||||
|
{
|
||||||
|
VPRINT("desync profile %d matches\n",dpl->dp.n);
|
||||||
|
return &dpl->dp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VPRINT("desync profile not found\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
|
||||||
|
{
|
||||||
|
ctrack->dp = dp_find(¶ms.desync_profiles, dest->sa_family==AF_INET6, saport(dest), ctrack->hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// segment buffer has at least 5 extra bytes to extend data block
|
// segment buffer has at least 5 extra bytes to extend data block
|
||||||
void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags)
|
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags)
|
||||||
{
|
{
|
||||||
uint8_t *p, *pp, *pHost = NULL;
|
uint8_t *p, *pp, *pHost = NULL;
|
||||||
size_t method_len = 0, pos;
|
size_t method_len = 0, pos;
|
||||||
|
size_t tpos, spos;
|
||||||
const char *method;
|
const char *method;
|
||||||
bool bBypass = false, bHaveHost = false, bHostExcluded = false;
|
bool bHaveHost = false;
|
||||||
char *pc, Host[256];
|
char *pc, Host[256];
|
||||||
|
t_l7proto l7proto;
|
||||||
|
|
||||||
DBGPRINT("tamper_out\n");
|
DBGPRINT("tamper_out\n");
|
||||||
|
|
||||||
|
if (params.debug)
|
||||||
|
{
|
||||||
|
char ip_port[48];
|
||||||
|
ntop46_port(dest,ip_port,sizeof(ip_port));
|
||||||
|
VPRINT("tampering tcp segment with size %zu to %s\n", *size, ip_port);
|
||||||
|
if (ctrack->dp) VPRINT("using cached desync profile %d\n",ctrack->dp->n);
|
||||||
|
if (ctrack->hostname) VPRINT("connection hostname: %s\n", ctrack->hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest->sa_family!=AF_INET && dest->sa_family!=AF_INET6)
|
||||||
|
{
|
||||||
|
DLOG_ERR("tamper_out dest family unknown\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
*split_pos=0;
|
*split_pos=0;
|
||||||
*split_flags=0;
|
*split_flags=0;
|
||||||
|
|
||||||
@ -26,9 +89,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
{
|
{
|
||||||
method_len = strlen(method)-2;
|
method_len = strlen(method)-2;
|
||||||
VPRINT("Data block looks like http request start : %s\n", method);
|
VPRINT("Data block looks like http request start : %s\n", method);
|
||||||
if (!ctrack->l7proto) ctrack->l7proto=HTTP;
|
l7proto=HTTP;
|
||||||
// cpu saving : we search host only if and when required. we do not research host every time we need its position
|
if (HttpFindHost(&pHost,segment,*size))
|
||||||
if ((params.hostlist || params.hostlist_exclude) && HttpFindHost(&pHost,segment,*size))
|
|
||||||
{
|
{
|
||||||
p = pHost + 5;
|
p = pHost + 5;
|
||||||
while (p < (segment + *size) && (*p == ' ' || *p == '\t')) p++;
|
while (p < (segment + *size) && (*p == ' ' || *p == '\t')) p++;
|
||||||
@ -37,13 +99,57 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
memcpy(Host, p, pp - p);
|
memcpy(Host, p, pp - p);
|
||||||
Host[pp - p] = '\0';
|
Host[pp - p] = '\0';
|
||||||
bHaveHost = true;
|
bHaveHost = true;
|
||||||
VPRINT("Requested Host is : %s\n", Host);
|
|
||||||
for(pc = Host; *pc; pc++) *pc=tolower(*pc);
|
for(pc = Host; *pc; pc++) *pc=tolower(*pc);
|
||||||
bBypass = !HostlistCheck(Host, &bHostExcluded);
|
|
||||||
}
|
}
|
||||||
if (!bBypass)
|
}
|
||||||
|
else if (IsTLSClientHello(segment,*size,false))
|
||||||
|
{
|
||||||
|
VPRINT("Data block contains TLS ClientHello\n");
|
||||||
|
l7proto=TLS;
|
||||||
|
bHaveHost=TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VPRINT("Data block contains unknown payload\n");
|
||||||
|
l7proto = UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctrack->l7proto==UNKNOWN) ctrack->l7proto=l7proto;
|
||||||
|
|
||||||
|
if (bHaveHost)
|
||||||
|
{
|
||||||
|
VPRINT("request hostname: %s\n", Host);
|
||||||
|
if (!ctrack->hostname)
|
||||||
{
|
{
|
||||||
if (params.unixeol)
|
if (!(ctrack->hostname=strdup(Host)))
|
||||||
|
{
|
||||||
|
DLOG_ERR("strdup hostname : out of memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct desync_profile *dp_prev = ctrack->dp;
|
||||||
|
apply_desync_profile(ctrack, dest);
|
||||||
|
if (ctrack->dp!=dp_prev)
|
||||||
|
VPRINT("desync profile changed by revealed hostname !\n");
|
||||||
|
else if (*ctrack->dp->hostlist_auto_filename)
|
||||||
|
{
|
||||||
|
bool bHostExcluded;
|
||||||
|
if (!HostlistCheck(ctrack->dp, Host, &bHostExcluded))
|
||||||
|
{
|
||||||
|
ctrack->b_ah_check = !bHostExcluded;
|
||||||
|
VPRINT("Not acting on this request\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctrack->dp) return;
|
||||||
|
|
||||||
|
switch(l7proto)
|
||||||
|
{
|
||||||
|
case HTTP:
|
||||||
|
if (ctrack->dp->unixeol)
|
||||||
{
|
{
|
||||||
p = pp = segment;
|
p = pp = segment;
|
||||||
while ((p = memmem(p, segment + *size - p, "\r\n", 2)))
|
while ((p = memmem(p, segment + *size - p, "\r\n", 2)))
|
||||||
@ -61,10 +167,10 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
}
|
}
|
||||||
pHost = NULL; // invalidate
|
pHost = NULL; // invalidate
|
||||||
}
|
}
|
||||||
if (params.methodeol && (*size+1+!params.unixeol)<=segment_buffer_size)
|
if (ctrack->dp->methodeol && (*size+1+!ctrack->dp->unixeol)<=segment_buffer_size)
|
||||||
{
|
{
|
||||||
VPRINT("Adding EOL before method\n");
|
VPRINT("Adding EOL before method\n");
|
||||||
if (params.unixeol)
|
if (ctrack->dp->unixeol)
|
||||||
{
|
{
|
||||||
memmove(segment + 1, segment, *size);
|
memmove(segment + 1, segment, *size);
|
||||||
(*size)++;;
|
(*size)++;;
|
||||||
@ -79,7 +185,7 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
}
|
}
|
||||||
pHost = NULL; // invalidate
|
pHost = NULL; // invalidate
|
||||||
}
|
}
|
||||||
if (params.methodspace && *size<segment_buffer_size)
|
if (ctrack->dp->methodspace && *size<segment_buffer_size)
|
||||||
{
|
{
|
||||||
// we only work with data blocks looking as HTTP query, so method is at the beginning
|
// we only work with data blocks looking as HTTP query, so method is at the beginning
|
||||||
VPRINT("Adding extra space after method\n");
|
VPRINT("Adding extra space after method\n");
|
||||||
@ -90,20 +196,20 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
(*size)++; // block will grow by 1 byte
|
(*size)++; // block will grow by 1 byte
|
||||||
if (pHost) pHost++; // Host: position will move by 1 byte
|
if (pHost) pHost++; // Host: position will move by 1 byte
|
||||||
}
|
}
|
||||||
if ((params.hostdot || params.hosttab) && *size<segment_buffer_size && HttpFindHost(&pHost,segment,*size))
|
if ((ctrack->dp->hostdot || ctrack->dp->hosttab) && *size<segment_buffer_size && HttpFindHost(&pHost,segment,*size))
|
||||||
{
|
{
|
||||||
p = pHost + 5;
|
p = pHost + 5;
|
||||||
while (p < (segment + *size) && *p != '\r' && *p != '\n') p++;
|
while (p < (segment + *size) && *p != '\r' && *p != '\n') p++;
|
||||||
if (p < (segment + *size))
|
if (p < (segment + *size))
|
||||||
{
|
{
|
||||||
pos = p - segment;
|
pos = p - segment;
|
||||||
VPRINT("Adding %s to host name at pos %zu\n", params.hostdot ? "dot" : "tab", pos);
|
VPRINT("Adding %s to host name at pos %zu\n", ctrack->dp->hostdot ? "dot" : "tab", pos);
|
||||||
memmove(p + 1, p, *size - pos);
|
memmove(p + 1, p, *size - pos);
|
||||||
*p = params.hostdot ? '.' : '\t'; // insert dot or tab
|
*p = ctrack->dp->hostdot ? '.' : '\t'; // insert dot or tab
|
||||||
(*size)++; // block will grow by 1 byte
|
(*size)++; // block will grow by 1 byte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (params.domcase && HttpFindHost(&pHost,segment,*size))
|
if (ctrack->dp->domcase && HttpFindHost(&pHost,segment,*size))
|
||||||
{
|
{
|
||||||
p = pHost + 5;
|
p = pHost + 5;
|
||||||
pos = p - segment;
|
pos = p - segment;
|
||||||
@ -111,7 +217,7 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
for (; p < (segment + *size) && *p != '\r' && *p != '\n'; p++)
|
for (; p < (segment + *size) && *p != '\r' && *p != '\n'; p++)
|
||||||
*p = (((size_t)p) & 1) ? tolower(*p) : toupper(*p);
|
*p = (((size_t)p) & 1) ? tolower(*p) : toupper(*p);
|
||||||
}
|
}
|
||||||
if (params.hostnospace && HttpFindHost(&pHost,segment,*size) && (pHost+5)<(segment+*size) && pHost[5] == ' ')
|
if (ctrack->dp->hostnospace && HttpFindHost(&pHost,segment,*size) && (pHost+5)<(segment+*size) && pHost[5] == ' ')
|
||||||
{
|
{
|
||||||
p = pHost + 6;
|
p = pHost + 6;
|
||||||
pos = p - segment;
|
pos = p - segment;
|
||||||
@ -119,17 +225,17 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
memmove(p - 1, p, *size - pos);
|
memmove(p - 1, p, *size - pos);
|
||||||
(*size)--; // block will shrink by 1 byte
|
(*size)--; // block will shrink by 1 byte
|
||||||
}
|
}
|
||||||
if (params.hostcase && HttpFindHost(&pHost,segment,*size))
|
if (ctrack->dp->hostcase && HttpFindHost(&pHost,segment,*size))
|
||||||
{
|
{
|
||||||
VPRINT("Changing 'Host:' => '%c%c%c%c:' at pos %td\n", params.hostspell[0], params.hostspell[1], params.hostspell[2], params.hostspell[3], pHost - segment);
|
VPRINT("Changing 'Host:' => '%c%c%c%c:' at pos %td\n", ctrack->dp->hostspell[0], ctrack->dp->hostspell[1], ctrack->dp->hostspell[2], ctrack->dp->hostspell[3], pHost - segment);
|
||||||
memcpy(pHost, params.hostspell, 4);
|
memcpy(pHost, ctrack->dp->hostspell, 4);
|
||||||
}
|
}
|
||||||
if (params.hostpad && HttpFindHost(&pHost,segment,*size))
|
if (ctrack->dp->hostpad && HttpFindHost(&pHost,segment,*size))
|
||||||
{
|
{
|
||||||
// add : XXXXX: <padding?[\r\n|\n]
|
// add : XXXXX: <padding?[\r\n|\n]
|
||||||
char s[8];
|
char s[8];
|
||||||
size_t hsize = params.unixeol ? 8 : 9;
|
size_t hsize = ctrack->dp->unixeol ? 8 : 9;
|
||||||
size_t hostpad = params.hostpad<hsize ? hsize : params.hostpad;
|
size_t hostpad = ctrack->dp->hostpad<hsize ? hsize : ctrack->dp->hostpad;
|
||||||
|
|
||||||
if ((hsize+*size)>segment_buffer_size)
|
if ((hsize+*size)>segment_buffer_size)
|
||||||
VPRINT("could not add host padding : buffer too small\n");
|
VPRINT("could not add host padding : buffer too small\n");
|
||||||
@ -159,7 +265,7 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
p+=7;
|
p+=7;
|
||||||
memset(p,'a'+rand()%('z'-'a'+1),padsize);
|
memset(p,'a'+rand()%('z'-'a'+1),padsize);
|
||||||
p+=padsize;
|
p+=padsize;
|
||||||
if (params.unixeol)
|
if (ctrack->dp->unixeol)
|
||||||
*p++='\n';
|
*p++='\n';
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -171,40 +277,16 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
pHost = NULL; // invalidate
|
pHost = NULL; // invalidate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*split_pos = HttpPos(params.split_http_req, params.split_pos, segment, *size);
|
*split_pos = HttpPos(ctrack->dp->split_http_req, ctrack->dp->split_pos, segment, *size);
|
||||||
if (params.disorder_http) *split_flags |= SPLIT_FLAG_DISORDER;
|
if (ctrack->dp->disorder_http) *split_flags |= SPLIT_FLAG_DISORDER;
|
||||||
if (params.oob_http) *split_flags |= SPLIT_FLAG_OOB;
|
if (ctrack->dp->oob_http) *split_flags |= SPLIT_FLAG_OOB;
|
||||||
}
|
break;
|
||||||
else
|
|
||||||
{
|
|
||||||
VPRINT("Not acting on this request\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IsTLSClientHello(segment,*size,false))
|
|
||||||
{
|
|
||||||
size_t tpos=0,spos=0;
|
|
||||||
|
|
||||||
if (!ctrack->l7proto) ctrack->l7proto=TLS;
|
|
||||||
|
|
||||||
VPRINT("packet contains TLS ClientHello\n");
|
|
||||||
// we need host only if hostlist is present
|
|
||||||
if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false))
|
|
||||||
{
|
|
||||||
VPRINT("hostname: %s\n",Host);
|
|
||||||
bHaveHost = true;
|
|
||||||
bBypass = !HostlistCheck(Host, &bHostExcluded);
|
|
||||||
}
|
|
||||||
if (bBypass)
|
|
||||||
{
|
|
||||||
VPRINT("Not acting on this request\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spos = TLSPos(params.split_tls, params.split_pos, segment, *size, 0);
|
|
||||||
|
|
||||||
|
case TLS:
|
||||||
|
spos = TLSPos(ctrack->dp->split_tls, ctrack->dp->split_pos, segment, *size, 0);
|
||||||
if ((5+*size)<=segment_buffer_size)
|
if ((5+*size)<=segment_buffer_size)
|
||||||
{
|
{
|
||||||
tpos = TLSPos(params.tlsrec, params.tlsrec_pos+5, segment, *size, 0);
|
tpos = TLSPos(ctrack->dp->tlsrec, ctrack->dp->tlsrec_pos+5, segment, *size, 0);
|
||||||
if (tpos>5)
|
if (tpos>5)
|
||||||
{
|
{
|
||||||
// construct 2 TLS records from one
|
// construct 2 TLS records from one
|
||||||
@ -228,52 +310,46 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (spos && spos < *size)
|
if (spos && spos < *size)
|
||||||
{
|
|
||||||
VPRINT("split pos %zu\n",spos);
|
|
||||||
*split_pos = spos;
|
*split_pos = spos;
|
||||||
}
|
|
||||||
|
|
||||||
if (params.disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER;
|
if (ctrack->dp->disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER;
|
||||||
if (params.oob_tls) *split_flags |= SPLIT_FLAG_OOB;
|
if (ctrack->dp->oob_tls) *split_flags |= SPLIT_FLAG_OOB;
|
||||||
}
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (ctrack->dp->split_any_protocol && ctrack->dp->split_pos < *size)
|
||||||
|
*split_pos = ctrack->dp->split_pos;
|
||||||
}
|
}
|
||||||
else if (params.split_any_protocol && params.split_pos < *size)
|
|
||||||
*split_pos = params.split_pos;
|
|
||||||
|
|
||||||
if (bHaveHost && bBypass && !bHostExcluded && *params.hostlist_auto_filename)
|
if (ctrack->dp->disorder) *split_flags |= SPLIT_FLAG_DISORDER;
|
||||||
{
|
if (ctrack->dp->oob) *split_flags |= SPLIT_FLAG_OOB;
|
||||||
DBGPRINT("tamper_out put hostname : %s\n", Host);
|
|
||||||
if (ctrack->hostname) free(ctrack->hostname);
|
|
||||||
ctrack->hostname=strdup(Host);
|
|
||||||
}
|
|
||||||
if (params.disorder) *split_flags |= SPLIT_FLAG_DISORDER;
|
|
||||||
if (params.oob) *split_flags |= SPLIT_FLAG_OOB;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void auto_hostlist_reset_fail_counter(const char *hostname)
|
static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const char *hostname)
|
||||||
{
|
{
|
||||||
if (hostname)
|
if (hostname)
|
||||||
{
|
{
|
||||||
hostfail_pool *fail_counter;
|
hostfail_pool *fail_counter;
|
||||||
|
|
||||||
fail_counter = HostFailPoolFind(params.hostlist_auto_fail_counters, hostname);
|
fail_counter = HostFailPoolFind(dp->hostlist_auto_fail_counters, hostname);
|
||||||
if (fail_counter)
|
if (fail_counter)
|
||||||
{
|
{
|
||||||
HostFailPoolDel(¶ms.hostlist_auto_fail_counters, fail_counter);
|
HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter);
|
||||||
VPRINT("auto hostlist : %s : fail counter reset. website is working.\n", hostname);
|
VPRINT("auto hostlist (profile %d) : %s : fail counter reset. website is working.\n", dp->n, hostname);
|
||||||
HOSTLIST_DEBUGLOG_APPEND("%s : fail counter reset. website is working.", hostname);
|
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : fail counter reset. website is working.", hostname, dp->n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void auto_hostlist_failed(const char *hostname)
|
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname)
|
||||||
{
|
{
|
||||||
hostfail_pool *fail_counter;
|
hostfail_pool *fail_counter;
|
||||||
|
|
||||||
fail_counter = HostFailPoolFind(params.hostlist_auto_fail_counters, hostname);
|
fail_counter = HostFailPoolFind(dp->hostlist_auto_fail_counters, hostname);
|
||||||
if (!fail_counter)
|
if (!fail_counter)
|
||||||
{
|
{
|
||||||
fail_counter = HostFailPoolAdd(¶ms.hostlist_auto_fail_counters, hostname, params.hostlist_auto_fail_time);
|
fail_counter = HostFailPoolAdd(&dp->hostlist_auto_fail_counters, hostname, dp->hostlist_auto_fail_time);
|
||||||
if (!fail_counter)
|
if (!fail_counter)
|
||||||
{
|
{
|
||||||
DLOG_ERR("HostFailPoolAdd: out of memory\n");
|
DLOG_ERR("HostFailPoolAdd: out of memory\n");
|
||||||
@ -281,35 +357,35 @@ static void auto_hostlist_failed(const char *hostname)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fail_counter->counter++;
|
fail_counter->counter++;
|
||||||
VPRINT("auto hostlist : %s : fail counter %d/%d\n", hostname, fail_counter->counter, params.hostlist_auto_fail_threshold);
|
VPRINT("auto hostlist (profile %d) : %s : fail counter %d/%d\n", dp->n , hostname, fail_counter->counter, dp->hostlist_auto_fail_threshold);
|
||||||
HOSTLIST_DEBUGLOG_APPEND("%s : fail counter %d/%d", hostname, fail_counter->counter, params.hostlist_auto_fail_threshold);
|
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : fail counter %d/%d", hostname, dp->n, fail_counter->counter, dp->hostlist_auto_fail_threshold);
|
||||||
if (fail_counter->counter >= params.hostlist_auto_fail_threshold)
|
if (fail_counter->counter >= dp->hostlist_auto_fail_threshold)
|
||||||
{
|
{
|
||||||
VPRINT("auto hostlist : fail threshold reached. adding %s to auto hostlist\n", hostname);
|
VPRINT("auto hostlist (profile %d) : fail threshold reached. adding %s to auto hostlist\n", dp->n , hostname);
|
||||||
HostFailPoolDel(¶ms.hostlist_auto_fail_counters, fail_counter);
|
HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter);
|
||||||
|
|
||||||
VPRINT("auto hostlist : rechecking %s to avoid duplicates\n", hostname);
|
VPRINT("auto hostlist (profile %d) : rechecking %s to avoid duplicates\n", dp->n, hostname);
|
||||||
bool bExcluded=false;
|
bool bExcluded=false;
|
||||||
if (!HostlistCheck(hostname, &bExcluded) && !bExcluded)
|
if (!HostlistCheck(dp, hostname, &bExcluded) && !bExcluded)
|
||||||
{
|
{
|
||||||
VPRINT("auto hostlist : adding %s\n", hostname);
|
VPRINT("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto_filename);
|
||||||
HOSTLIST_DEBUGLOG_APPEND("%s : adding", hostname);
|
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : adding to %s", hostname, dp->n, dp->hostlist_auto_filename);
|
||||||
if (!StrPoolAddStr(¶ms.hostlist, hostname))
|
if (!StrPoolAddStr(&dp->hostlist, hostname))
|
||||||
{
|
{
|
||||||
DLOG_ERR("StrPoolAddStr out of memory\n");
|
DLOG_ERR("StrPoolAddStr out of memory\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!append_to_list_file(params.hostlist_auto_filename, hostname))
|
if (!append_to_list_file(dp->hostlist_auto_filename, hostname))
|
||||||
{
|
{
|
||||||
DLOG_PERROR("write to auto hostlist:");
|
DLOG_PERROR("write to auto hostlist:");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
params.hostlist_auto_mod_time = file_mod_time(params.hostlist_auto_filename);
|
dp->hostlist_auto_mod_time = file_mod_time(dp->hostlist_auto_filename);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VPRINT("auto hostlist : NOT adding %s\n", hostname);
|
VPRINT("auto hostlist (profile %d) : NOT adding %s\n", dp->n, hostname);
|
||||||
HOSTLIST_DEBUGLOG_APPEND("%s : NOT adding, duplicate detected", hostname);
|
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : NOT adding, duplicate detected", hostname, dp->n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,9 +396,9 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
|
|||||||
|
|
||||||
DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname);
|
DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname);
|
||||||
|
|
||||||
if (*params.hostlist_auto_filename)
|
if (ctrack->dp && ctrack->b_ah_check)
|
||||||
{
|
{
|
||||||
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
HostFailPoolPurgeRateLimited(&ctrack->dp->hostlist_auto_fail_counters);
|
||||||
|
|
||||||
if (ctrack->l7proto==HTTP && ctrack->hostname)
|
if (ctrack->l7proto==HTTP && ctrack->hostname)
|
||||||
{
|
{
|
||||||
@ -333,7 +409,7 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
|
|||||||
if (bFail)
|
if (bFail)
|
||||||
{
|
{
|
||||||
VPRINT("redirect to another domain detected. possibly DPI redirect.\n");
|
VPRINT("redirect to another domain detected. possibly DPI redirect.\n");
|
||||||
HOSTLIST_DEBUGLOG_APPEND("%s : redirect to another domain", ctrack->hostname);
|
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : redirect to another domain", ctrack->hostname, ctrack->dp->n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
VPRINT("local or in-domain redirect detected. it's not a DPI redirect.\n");
|
VPRINT("local or in-domain redirect detected. it's not a DPI redirect.\n");
|
||||||
@ -343,11 +419,9 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
|
|||||||
// received not http reply. do not monitor this connection anymore
|
// received not http reply. do not monitor this connection anymore
|
||||||
VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname);
|
VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname);
|
||||||
}
|
}
|
||||||
if (bFail) auto_hostlist_failed(ctrack->hostname);
|
if (bFail) auto_hostlist_failed(ctrack->dp, ctrack->hostname);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->hostname);
|
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname);
|
||||||
|
|
||||||
}
|
}
|
||||||
ctrack->bTamperInCutoff = true;
|
ctrack->bTamperInCutoff = true;
|
||||||
}
|
}
|
||||||
@ -356,30 +430,32 @@ void rst_in(t_ctrack *ctrack)
|
|||||||
{
|
{
|
||||||
DBGPRINT("rst_in hostname=%s\n", ctrack->hostname);
|
DBGPRINT("rst_in hostname=%s\n", ctrack->hostname);
|
||||||
|
|
||||||
if (!*params.hostlist_auto_filename) return;
|
if (ctrack->dp && ctrack->b_ah_check)
|
||||||
|
|
||||||
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
|
||||||
|
|
||||||
if (!ctrack->bTamperInCutoff && ctrack->hostname)
|
|
||||||
{
|
{
|
||||||
VPRINT("incoming RST detected for hostname %s\n", ctrack->hostname);
|
HostFailPoolPurgeRateLimited(&ctrack->dp->hostlist_auto_fail_counters);
|
||||||
HOSTLIST_DEBUGLOG_APPEND("%s : incoming RST", ctrack->hostname);
|
|
||||||
auto_hostlist_failed(ctrack->hostname);
|
if (!ctrack->bTamperInCutoff && ctrack->hostname)
|
||||||
|
{
|
||||||
|
VPRINT("incoming RST detected for hostname %s\n", ctrack->hostname);
|
||||||
|
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : incoming RST", ctrack->hostname, ctrack->dp->n);
|
||||||
|
auto_hostlist_failed(ctrack->dp, ctrack->hostname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void hup_out(t_ctrack *ctrack)
|
void hup_out(t_ctrack *ctrack)
|
||||||
{
|
{
|
||||||
DBGPRINT("hup_out hostname=%s\n", ctrack->hostname);
|
DBGPRINT("hup_out hostname=%s\n", ctrack->hostname);
|
||||||
|
|
||||||
if (!*params.hostlist_auto_filename) return;
|
if (ctrack->dp && ctrack->b_ah_check)
|
||||||
|
|
||||||
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
|
||||||
|
|
||||||
if (!ctrack->bTamperInCutoff && ctrack->hostname)
|
|
||||||
{
|
{
|
||||||
// local leg dropped connection after first request. probably due to timeout.
|
HostFailPoolPurgeRateLimited(&ctrack->dp->hostlist_auto_fail_counters);
|
||||||
VPRINT("local leg closed connection after first request (timeout ?). hostname: %s\n", ctrack->hostname);
|
|
||||||
HOSTLIST_DEBUGLOG_APPEND("%s : client closed connection without server reply", ctrack->hostname);
|
if (!ctrack->bTamperInCutoff && ctrack->hostname)
|
||||||
auto_hostlist_failed(ctrack->hostname);
|
{
|
||||||
|
// local leg dropped connection after first request. probably due to timeout.
|
||||||
|
VPRINT("local leg closed connection after first request (timeout ?). hostname: %s\n", ctrack->hostname);
|
||||||
|
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client closed connection without server reply", ctrack->hostname, ctrack->dp->n);
|
||||||
|
auto_hostlist_failed(ctrack->dp, ctrack->hostname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
#define SPLIT_FLAG_DISORDER 0x01
|
#define SPLIT_FLAG_DISORDER 0x01
|
||||||
#define SPLIT_FLAG_OOB 0x02
|
#define SPLIT_FLAG_OOB 0x02
|
||||||
|
|
||||||
@ -14,10 +16,14 @@ typedef struct
|
|||||||
t_l7proto l7proto;
|
t_l7proto l7proto;
|
||||||
bool bFirstReplyChecked;
|
bool bFirstReplyChecked;
|
||||||
bool bTamperInCutoff;
|
bool bTamperInCutoff;
|
||||||
|
bool b_ah_check;
|
||||||
char *hostname;
|
char *hostname;
|
||||||
|
struct desync_profile *dp; // desync profile cache
|
||||||
} t_ctrack;
|
} t_ctrack;
|
||||||
|
|
||||||
void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags);
|
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest);
|
||||||
|
|
||||||
|
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags);
|
||||||
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size);
|
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size);
|
||||||
// connection reset by remote leg
|
// connection reset by remote leg
|
||||||
void rst_in(t_ctrack *ctrack);
|
void rst_in(t_ctrack *ctrack);
|
||||||
|
251
tpws/tpws.c
251
tpws/tpws.c
@ -46,8 +46,7 @@ bool bHup = false;
|
|||||||
static void onhup(int sig)
|
static void onhup(int sig)
|
||||||
{
|
{
|
||||||
printf("HUP received !\n");
|
printf("HUP received !\n");
|
||||||
if (params.hostlist || params.hostlist_exclude)
|
printf("Will reload hostlist on next request (if any)\n");
|
||||||
printf("Will reload hostlists on next request\n");
|
|
||||||
bHup = true;
|
bHup = true;
|
||||||
}
|
}
|
||||||
// should be called in normal execution
|
// should be called in normal execution
|
||||||
@ -67,7 +66,14 @@ void dohup(void)
|
|||||||
static void onusr2(int sig)
|
static void onusr2(int sig)
|
||||||
{
|
{
|
||||||
printf("\nHOSTFAIL POOL DUMP\n");
|
printf("\nHOSTFAIL POOL DUMP\n");
|
||||||
HostFailPoolDump(params.hostlist_auto_fail_counters);
|
|
||||||
|
struct desync_profile_list *dpl;
|
||||||
|
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||||
|
{
|
||||||
|
printf("\nDESYNC PROFILE %d\n",dpl->dp.n);
|
||||||
|
HostFailPoolDump(dpl->dp.hostlist_auto_fail_counters);
|
||||||
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +176,11 @@ static void exithelp(void)
|
|||||||
#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"
|
||||||
"\nFILTER:\n"
|
"\nMULTI-STRATEGY:\n"
|
||||||
|
" --new\t\t\t\t\t; begin new strategy\n"
|
||||||
|
" --filter-l3=ipv4|ipv6\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
|
||||||
|
" --filter-tcp=[~]port1[-port2]\t\t; TCP port filter. ~ means negation\n"
|
||||||
|
"\nHOSTLIST FILTER:\n"
|
||||||
" --hostlist=<filename>\t\t\t; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
|
" --hostlist=<filename>\t\t\t; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
|
||||||
" --hostlist-exclude=<filename>\t\t; do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
|
" --hostlist-exclude=<filename>\t\t; do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
|
||||||
" --hostlist-auto=<filename>\t\t; detect DPI blocks and build hostlist automatically\n"
|
" --hostlist-auto=<filename>\t\t; detect DPI blocks and build hostlist automatically\n"
|
||||||
@ -203,7 +213,6 @@ static void exithelp(void)
|
|||||||
" --tlsrec-pos=<pos>\t\t\t; make 2 TLS records. split at specified pos\n"
|
" --tlsrec-pos=<pos>\t\t\t; make 2 TLS records. split at specified pos\n"
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
" --mss=<int>\t\t\t\t; set client MSS. forces server to split messages but significantly decreases speed !\n"
|
" --mss=<int>\t\t\t\t; set client MSS. forces server to split messages but significantly decreases speed !\n"
|
||||||
" --mss-pf=[~]port1[-port2]\t\t; MSS port filter. ~ means negation\n"
|
|
||||||
#endif
|
#endif
|
||||||
" --tamper-start=[n]<pos>\t\t; start tampering only from specified outbound stream position. default is 0. 'n' means data block number.\n"
|
" --tamper-start=[n]<pos>\t\t; start tampering only from specified outbound stream position. default is 0. 'n' means data block number.\n"
|
||||||
" --tamper-cutoff=[n]<pos>\t\t; do not tamper anymore after specified outbound stream position. default is unlimited.\n",
|
" --tamper-cutoff=[n]<pos>\t\t; do not tamper anymore after specified outbound stream position. default is unlimited.\n",
|
||||||
@ -216,11 +225,7 @@ static void exithelp(void)
|
|||||||
}
|
}
|
||||||
static void cleanup_params(void)
|
static void cleanup_params(void)
|
||||||
{
|
{
|
||||||
strlist_destroy(¶ms.hostlist_files);
|
dp_list_destroy(¶ms.desync_profiles);
|
||||||
strlist_destroy(¶ms.hostlist_exclude_files);
|
|
||||||
StrPoolDestroy(¶ms.hostlist_exclude);
|
|
||||||
StrPoolDestroy(¶ms.hostlist);
|
|
||||||
HostFailPoolDestroy(¶ms.hostlist_auto_fail_counters);
|
|
||||||
}
|
}
|
||||||
static void exithelp_clean(void)
|
static void exithelp_clean(void)
|
||||||
{
|
{
|
||||||
@ -285,6 +290,32 @@ bool parse_tlspos(const char *s, enum tlspos *pos)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
|
||||||
|
{
|
||||||
|
char *e,*p,c;
|
||||||
|
|
||||||
|
for (p=opt,*ipv4=*ipv6=false ; p ; )
|
||||||
|
{
|
||||||
|
if ((e = strchr(p,',')))
|
||||||
|
{
|
||||||
|
c=*e;
|
||||||
|
*e=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(p,"ipv4"))
|
||||||
|
*ipv4 = true;
|
||||||
|
else if (!strcmp(p,"ipv6"))
|
||||||
|
*ipv6 = true;
|
||||||
|
else return false;
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
*e++=c;
|
||||||
|
}
|
||||||
|
p = e;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void parse_params(int argc, char *argv[])
|
void parse_params(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -292,18 +323,13 @@ void parse_params(int argc, char *argv[])
|
|||||||
int v, i;
|
int v, i;
|
||||||
|
|
||||||
memset(¶ms, 0, sizeof(params));
|
memset(¶ms, 0, sizeof(params));
|
||||||
memcpy(params.hostspell, "host", 4); // default hostspell
|
|
||||||
params.maxconn = DEFAULT_MAX_CONN;
|
params.maxconn = DEFAULT_MAX_CONN;
|
||||||
params.max_orphan_time = DEFAULT_MAX_ORPHAN_TIME;
|
params.max_orphan_time = DEFAULT_MAX_ORPHAN_TIME;
|
||||||
params.binds_last = -1;
|
params.binds_last = -1;
|
||||||
params.hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
|
|
||||||
params.hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
params.tcp_user_timeout_local = DEFAULT_TCP_USER_TIMEOUT_LOCAL;
|
params.tcp_user_timeout_local = DEFAULT_TCP_USER_TIMEOUT_LOCAL;
|
||||||
params.tcp_user_timeout_remote = DEFAULT_TCP_USER_TIMEOUT_REMOTE;
|
params.tcp_user_timeout_remote = DEFAULT_TCP_USER_TIMEOUT_REMOTE;
|
||||||
#endif
|
#endif
|
||||||
LIST_INIT(¶ms.hostlist_files);
|
|
||||||
LIST_INIT(¶ms.hostlist_exclude_files);
|
|
||||||
|
|
||||||
#if defined(__OpenBSD__) || defined(__APPLE__)
|
#if defined(__OpenBSD__) || defined(__APPLE__)
|
||||||
params.pf_enable = true; // OpenBSD and MacOS have no other choice
|
params.pf_enable = true; // OpenBSD and MacOS have no other choice
|
||||||
@ -314,6 +340,17 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.droproot = true;
|
params.droproot = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct desync_profile_list *dpl;
|
||||||
|
struct desync_profile *dp;
|
||||||
|
int desync_profile_count=0;
|
||||||
|
if (!(dpl = dp_list_add(¶ms.desync_profiles)))
|
||||||
|
{
|
||||||
|
DLOG_ERR("desync_profile_add: out of memory\n");
|
||||||
|
exit_clean(1);
|
||||||
|
}
|
||||||
|
dp = &dpl->dp;
|
||||||
|
dp->n = ++desync_profile_count;
|
||||||
|
|
||||||
const struct option long_options[] = {
|
const struct option long_options[] = {
|
||||||
{ "help",no_argument,0,0 },// optidx=0
|
{ "help",no_argument,0,0 },// optidx=0
|
||||||
{ "h",no_argument,0,0 },// optidx=1
|
{ "h",no_argument,0,0 },// optidx=1
|
||||||
@ -371,18 +408,22 @@ void parse_params(int argc, char *argv[])
|
|||||||
{ "tamper-start",required_argument,0,0 },// optidx=53
|
{ "tamper-start",required_argument,0,0 },// optidx=53
|
||||||
{ "tamper-cutoff",required_argument,0,0 },// optidx=54
|
{ "tamper-cutoff",required_argument,0,0 },// optidx=54
|
||||||
{ "connect-bind-addr",required_argument,0,0 },// optidx=55
|
{ "connect-bind-addr",required_argument,0,0 },// optidx=55
|
||||||
|
|
||||||
|
{ "new",no_argument,0,0 }, // optidx=56
|
||||||
|
{ "filter-l3",required_argument,0,0 }, // optidx=57
|
||||||
|
{ "filter-tcp",required_argument,0,0 }, // optidx=58
|
||||||
|
|
||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
{ "enable-pf",no_argument,0,0 },// optidx=56
|
{ "enable-pf",no_argument,0,0 },// optidx=59
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
{ "local-tcp-user-timeout",required_argument,0,0 },// optidx=56
|
{ "local-tcp-user-timeout",required_argument,0,0 },// optidx=59
|
||||||
{ "remote-tcp-user-timeout",required_argument,0,0 },// optidx=57
|
{ "remote-tcp-user-timeout",required_argument,0,0 },// optidx=60
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
{ "local-tcp-user-timeout",required_argument,0,0 },// optidx=56
|
{ "local-tcp-user-timeout",required_argument,0,0 },// optidx=59
|
||||||
{ "remote-tcp-user-timeout",required_argument,0,0 },// optidx=57
|
{ "remote-tcp-user-timeout",required_argument,0,0 },// optidx=60
|
||||||
{ "mss",required_argument,0,0 },// optidx=58
|
{ "mss",required_argument,0,0 },// optidx=61
|
||||||
{ "mss-pf",required_argument,0,0 },// optidx=59
|
|
||||||
#ifdef SPLICE_PRESENT
|
#ifdef SPLICE_PRESENT
|
||||||
{ "nosplice",no_argument,0,0 },// optidx=60
|
{ "nosplice",no_argument,0,0 },// optidx=62
|
||||||
#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
|
||||||
@ -513,7 +554,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 17: /* hostcase */
|
case 17: /* hostcase */
|
||||||
params.hostcase = true;
|
dp->hostcase = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 18: /* hostspell */
|
case 18: /* hostspell */
|
||||||
@ -522,28 +563,28 @@ void parse_params(int argc, char *argv[])
|
|||||||
DLOG_ERR("hostspell must be exactly 4 chars long\n");
|
DLOG_ERR("hostspell must be exactly 4 chars long\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
params.hostcase = true;
|
dp->hostcase = true;
|
||||||
memcpy(params.hostspell, optarg, 4);
|
memcpy(dp->hostspell, optarg, 4);
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 19: /* hostdot */
|
case 19: /* hostdot */
|
||||||
params.hostdot = true;
|
dp->hostdot = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 20: /* hostnospace */
|
case 20: /* hostnospace */
|
||||||
params.hostnospace = true;
|
dp->hostnospace = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 21: /* hostpad */
|
case 21: /* hostpad */
|
||||||
params.hostpad = atoi(optarg);
|
dp->hostpad = atoi(optarg);
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 22: /* domcase */
|
case 22: /* domcase */
|
||||||
params.domcase = true;
|
dp->domcase = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 23: /* split-http-req */
|
case 23: /* split-http-req */
|
||||||
if (!parse_httpreqpos(optarg, ¶ms.split_http_req))
|
if (!parse_httpreqpos(optarg, &dp->split_http_req))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for split-http-req\n");
|
DLOG_ERR("Invalid argument for split-http-req\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
@ -551,7 +592,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 24: /* split-tls */
|
case 24: /* split-tls */
|
||||||
if (!parse_tlspos(optarg, ¶ms.split_tls))
|
if (!parse_tlspos(optarg, &dp->split_tls))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for split-tls\n");
|
DLOG_ERR("Invalid argument for split-tls\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
@ -561,7 +602,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
case 25: /* split-pos */
|
case 25: /* split-pos */
|
||||||
i = atoi(optarg);
|
i = atoi(optarg);
|
||||||
if (i>0)
|
if (i>0)
|
||||||
params.split_pos = i;
|
dp->split_pos = i;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for split-pos\n");
|
DLOG_ERR("Invalid argument for split-pos\n");
|
||||||
@ -570,13 +611,13 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 26: /* split-any-protocol */
|
case 26: /* split-any-protocol */
|
||||||
params.split_any_protocol = true;
|
dp->split_any_protocol = true;
|
||||||
break;
|
break;
|
||||||
case 27: /* disorder */
|
case 27: /* disorder */
|
||||||
if (optarg)
|
if (optarg)
|
||||||
{
|
{
|
||||||
if (!strcmp(optarg,"http")) params.disorder_http=true;
|
if (!strcmp(optarg,"http")) dp->disorder_http=true;
|
||||||
else if (!strcmp(optarg,"tls")) params.disorder_tls=true;
|
else if (!strcmp(optarg,"tls")) dp->disorder_tls=true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for disorder\n");
|
DLOG_ERR("Invalid argument for disorder\n");
|
||||||
@ -584,14 +625,14 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
params.disorder = true;
|
dp->disorder = true;
|
||||||
save_default_ttl();
|
save_default_ttl();
|
||||||
break;
|
break;
|
||||||
case 28: /* oob */
|
case 28: /* oob */
|
||||||
if (optarg)
|
if (optarg)
|
||||||
{
|
{
|
||||||
if (!strcmp(optarg,"http")) params.oob_http=true;
|
if (!strcmp(optarg,"http")) dp->oob_http=true;
|
||||||
else if (!strcmp(optarg,"tls")) params.oob_tls=true;
|
else if (!strcmp(optarg,"tls")) dp->oob_tls=true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for oob\n");
|
DLOG_ERR("Invalid argument for oob\n");
|
||||||
@ -599,39 +640,39 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
params.oob = true;
|
dp->oob = true;
|
||||||
break;
|
break;
|
||||||
case 29: /* oob-data */
|
case 29: /* oob-data */
|
||||||
{
|
{
|
||||||
size_t l = strlen(optarg);
|
size_t l = strlen(optarg);
|
||||||
unsigned int bt;
|
unsigned int bt;
|
||||||
if (l==1) params.oob_byte = (uint8_t)*optarg;
|
if (l==1) dp->oob_byte = (uint8_t)*optarg;
|
||||||
else if (l!=4 || sscanf(optarg,"0x%02X",&bt)!=1)
|
else if (l!=4 || sscanf(optarg,"0x%02X",&bt)!=1)
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for oob-data\n");
|
DLOG_ERR("Invalid argument for oob-data\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
else params.oob_byte = (uint8_t)bt;
|
else dp->oob_byte = (uint8_t)bt;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 30: /* methodspace */
|
case 30: /* methodspace */
|
||||||
params.methodspace = true;
|
dp->methodspace = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 31: /* methodeol */
|
case 31: /* methodeol */
|
||||||
params.methodeol = true;
|
dp->methodeol = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 32: /* hosttab */
|
case 32: /* hosttab */
|
||||||
params.hosttab = true;
|
dp->hosttab = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 33: /* unixeol */
|
case 33: /* unixeol */
|
||||||
params.unixeol = true;
|
dp->unixeol = true;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 34: /* tlsrec */
|
case 34: /* tlsrec */
|
||||||
if (!parse_tlspos(optarg, ¶ms.tlsrec))
|
if (!parse_tlspos(optarg, &dp->tlsrec))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for tlsrec\n");
|
DLOG_ERR("Invalid argument for tlsrec\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
@ -639,8 +680,8 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 35: /* tlsrec-pos */
|
case 35: /* tlsrec-pos */
|
||||||
if ((params.tlsrec_pos = atoi(optarg))>0)
|
if ((dp->tlsrec_pos = atoi(optarg))>0)
|
||||||
params.tlsrec = tlspos_pos;
|
dp->tlsrec = tlspos_pos;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for tlsrec-pos\n");
|
DLOG_ERR("Invalid argument for tlsrec-pos\n");
|
||||||
@ -649,7 +690,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 36: /* hostlist */
|
case 36: /* hostlist */
|
||||||
if (!strlist_add(¶ms.hostlist_files, optarg))
|
if (!strlist_add(&dp->hostlist_files, optarg))
|
||||||
{
|
{
|
||||||
DLOG_ERR("strlist_add failed\n");
|
DLOG_ERR("strlist_add failed\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
@ -657,7 +698,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 37: /* hostlist-exclude */
|
case 37: /* hostlist-exclude */
|
||||||
if (!strlist_add(¶ms.hostlist_exclude_files, optarg))
|
if (!strlist_add(&dp->hostlist_exclude_files, optarg))
|
||||||
{
|
{
|
||||||
DLOG_ERR("strlist_add failed\n");
|
DLOG_ERR("strlist_add failed\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
@ -665,9 +706,9 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 38: /* hostlist-auto */
|
case 38: /* hostlist-auto */
|
||||||
if (*params.hostlist_auto_filename)
|
if (*dp->hostlist_auto_filename)
|
||||||
{
|
{
|
||||||
DLOG_ERR("only one auto hostlist is supported\n");
|
DLOG_ERR("only one auto hostlist per profile is supported\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -687,26 +728,26 @@ void parse_params(int argc, char *argv[])
|
|||||||
if (params.droproot && chown(optarg, params.uid, -1))
|
if (params.droproot && chown(optarg, params.uid, -1))
|
||||||
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", optarg);
|
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", optarg);
|
||||||
}
|
}
|
||||||
if (!strlist_add(¶ms.hostlist_files, optarg))
|
if (!strlist_add(&dp->hostlist_files, optarg))
|
||||||
{
|
{
|
||||||
DLOG_ERR("strlist_add failed\n");
|
DLOG_ERR("strlist_add failed\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
strncpy(params.hostlist_auto_filename, optarg, sizeof(params.hostlist_auto_filename));
|
strncpy(dp->hostlist_auto_filename, optarg, sizeof(dp->hostlist_auto_filename));
|
||||||
params.hostlist_auto_filename[sizeof(params.hostlist_auto_filename) - 1] = '\0';
|
dp->hostlist_auto_filename[sizeof(dp->hostlist_auto_filename) - 1] = '\0';
|
||||||
params.tamper = true; // need to detect blocks and update autohostlist. cannot just slice.
|
params.tamper = true; // need to detect blocks and update autohostlist. cannot just slice.
|
||||||
break;
|
break;
|
||||||
case 39: /* hostlist-auto-fail-threshold */
|
case 39: /* hostlist-auto-fail-threshold */
|
||||||
params.hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
|
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
|
||||||
if (params.hostlist_auto_fail_threshold<1 || params.hostlist_auto_fail_threshold>20)
|
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20)
|
||||||
{
|
{
|
||||||
DLOG_ERR("auto hostlist fail threshold must be within 1..20\n");
|
DLOG_ERR("auto hostlist fail threshold must be within 1..20\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 40: /* hostlist-auto-fail-time */
|
case 40: /* hostlist-auto-fail-time */
|
||||||
params.hostlist_auto_fail_time = (uint8_t)atoi(optarg);
|
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
|
||||||
if (params.hostlist_auto_fail_time<1)
|
if (dp->hostlist_auto_fail_time<1)
|
||||||
{
|
{
|
||||||
DLOG_ERR("auto hostlist fail time is not valid\n");
|
DLOG_ERR("auto hostlist fail time is not valid\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
@ -820,26 +861,28 @@ void parse_params(int argc, char *argv[])
|
|||||||
const char *p=optarg;
|
const char *p=optarg;
|
||||||
if (*p=='n')
|
if (*p=='n')
|
||||||
{
|
{
|
||||||
params.tamper_start_n=true;
|
dp->tamper_start_n=true;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
params.tamper_start_n=false;
|
dp->tamper_start_n=false;
|
||||||
params.tamper_start = atoi(p);
|
dp->tamper_start = atoi(p);
|
||||||
}
|
}
|
||||||
|
params.tamper_lim = true;
|
||||||
break;
|
break;
|
||||||
case 54: /* tamper-cutoff */
|
case 54: /* tamper-cutoff */
|
||||||
{
|
{
|
||||||
const char *p=optarg;
|
const char *p=optarg;
|
||||||
if (*p=='n')
|
if (*p=='n')
|
||||||
{
|
{
|
||||||
params.tamper_cutoff_n=true;
|
dp->tamper_cutoff_n=true;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
params.tamper_cutoff_n=false;
|
dp->tamper_cutoff_n=false;
|
||||||
params.tamper_cutoff = atoi(p);
|
dp->tamper_cutoff = atoi(p);
|
||||||
}
|
}
|
||||||
|
params.tamper_lim = true;
|
||||||
break;
|
break;
|
||||||
case 55: /* connect-bind-addr */
|
case 55: /* connect-bind-addr */
|
||||||
{
|
{
|
||||||
@ -868,12 +911,37 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 56: /* new */
|
||||||
|
if (!(dpl = dp_list_add(¶ms.desync_profiles)))
|
||||||
|
{
|
||||||
|
DLOG_ERR("desync_profile_add: out of memory\n");
|
||||||
|
exit_clean(1);
|
||||||
|
}
|
||||||
|
dp = &dpl->dp;
|
||||||
|
dp->n = ++desync_profile_count;
|
||||||
|
break;
|
||||||
|
case 57: /* filter-l3 */
|
||||||
|
if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6))
|
||||||
|
{
|
||||||
|
DLOG_ERR("bad value for --filter-l3\n");
|
||||||
|
exit_clean(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 58: /* filter-tcp */
|
||||||
|
if (!pf_parse(optarg,&dp->pf_tcp))
|
||||||
|
{
|
||||||
|
DLOG_ERR("Invalid port filter : %s\n",optarg);
|
||||||
|
exit_clean(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
case 56: /* enable-pf */
|
case 59: /* enable-pf */
|
||||||
params.pf_enable = true;
|
params.pf_enable = true;
|
||||||
break;
|
break;
|
||||||
#elif defined(__linux__) || defined(__APPLE__)
|
#elif defined(__linux__) || defined(__APPLE__)
|
||||||
case 56: /* local-tcp-user-timeout */
|
case 59: /* local-tcp-user-timeout */
|
||||||
params.tcp_user_timeout_local = atoi(optarg);
|
params.tcp_user_timeout_local = atoi(optarg);
|
||||||
if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400)
|
if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400)
|
||||||
{
|
{
|
||||||
@ -881,7 +949,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 57: /* remote-tcp-user-timeout */
|
case 60: /* remote-tcp-user-timeout */
|
||||||
params.tcp_user_timeout_remote = atoi(optarg);
|
params.tcp_user_timeout_remote = atoi(optarg);
|
||||||
if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400)
|
if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400)
|
||||||
{
|
{
|
||||||
@ -892,24 +960,17 @@ void parse_params(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
case 58: /* mss */
|
case 61: /* mss */
|
||||||
// this option does not work in any BSD and MacOS. OS may accept but it changes nothing
|
// this option does not work in any BSD and MacOS. OS may accept but it changes nothing
|
||||||
params.mss = atoi(optarg);
|
dp->mss = atoi(optarg);
|
||||||
if (params.mss<88 || params.mss>32767)
|
if (dp->mss<88 || dp->mss>32767)
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid value for MSS. Linux accepts MSS 88-32767.\n");
|
DLOG_ERR("Invalid value for MSS. Linux accepts MSS 88-32767.\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 59: /* mss-pf */
|
|
||||||
if (!pf_parse(optarg,¶ms.mss_pf))
|
|
||||||
{
|
|
||||||
DLOG_ERR("Invalid MSS port filter.\n");
|
|
||||||
exit_clean(1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#ifdef SPLICE_PRESENT
|
#ifdef SPLICE_PRESENT
|
||||||
case 60: /* nosplice */
|
case 62: /* nosplice */
|
||||||
params.nosplice = true;
|
params.nosplice = true;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@ -925,22 +986,36 @@ void parse_params(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
params.binds_last=0; // default bind to all
|
params.binds_last=0; // default bind to all
|
||||||
}
|
}
|
||||||
if (params.skip_nodelay && (params.split_http_req || params.split_pos))
|
if (!params.resolver_threads) params.resolver_threads = 5 + params.maxconn/50;
|
||||||
|
|
||||||
|
VPRINT("adding low-priority default empty desync profile\n");
|
||||||
|
// add default empty profile
|
||||||
|
if (!(dpl = dp_list_add(¶ms.desync_profiles)))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Cannot split with --skip-nodelay\n");
|
DLOG_ERR("desync_profile_add: out of memory\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
if (!params.resolver_threads) params.resolver_threads = 5 + params.maxconn/50;
|
|
||||||
if (params.split_tls==tlspos_none && params.split_pos) params.split_tls=tlspos_pos;
|
|
||||||
if (params.split_http_req==httpreqpos_none && params.split_pos) params.split_http_req=httpreqpos_pos;
|
|
||||||
|
|
||||||
if (*params.hostlist_auto_filename) params.hostlist_auto_mod_time = file_mod_time(params.hostlist_auto_filename);
|
DLOG_CONDUP("we have %d user defined desync profile(s) and default low priority profile 0\n",desync_profile_count);
|
||||||
|
|
||||||
|
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||||
|
{
|
||||||
|
dp = &dpl->dp;
|
||||||
|
if (dp->split_tls==tlspos_none && dp->split_pos) dp->split_tls=tlspos_pos;
|
||||||
|
if (dp->split_http_req==httpreqpos_none && dp->split_pos) dp->split_http_req=httpreqpos_pos;
|
||||||
|
if (*dp->hostlist_auto_filename) dp->hostlist_auto_mod_time = file_mod_time(dp->hostlist_auto_filename);
|
||||||
|
if (params.skip_nodelay && (dp->split_tls || dp->split_http_req || dp->split_pos))
|
||||||
|
{
|
||||||
|
DLOG_ERR("Cannot split with --skip-nodelay\n");
|
||||||
|
exit_clean(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!LoadIncludeHostLists())
|
if (!LoadIncludeHostLists())
|
||||||
{
|
{
|
||||||
DLOG_ERR("Include hostlist load failed\n");
|
DLOG_ERR("Include hostlist load failed\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
if (*params.hostlist_auto_filename) NonEmptyHostlist(¶ms.hostlist);
|
|
||||||
if (!LoadExcludeHostLists())
|
if (!LoadExcludeHostLists())
|
||||||
{
|
{
|
||||||
DLOG_ERR("Exclude hostlist load failed\n");
|
DLOG_ERR("Exclude hostlist load failed\n");
|
||||||
@ -1057,7 +1132,7 @@ static bool set_ulimit(void)
|
|||||||
// additional 1/2 for unpaired remote legs sending buffers
|
// additional 1/2 for unpaired remote legs sending buffers
|
||||||
// 16 for listen_fd, epoll, hostlist, ...
|
// 16 for listen_fd, epoll, hostlist, ...
|
||||||
#ifdef SPLICE_PRESENT
|
#ifdef SPLICE_PRESENT
|
||||||
fdmax = (params.nosplice ? 2 : (params.tamper && !params.tamper_start && !params.tamper_cutoff ? 4 : 6)) * params.maxconn;
|
fdmax = (params.nosplice ? 2 : (params.tamper && !params.tamper_lim ? 4 : 6)) * params.maxconn;
|
||||||
#else
|
#else
|
||||||
fdmax = 2 * params.maxconn;
|
fdmax = 2 * params.maxconn;
|
||||||
#endif
|
#endif
|
||||||
|
115
tpws/tpws_conn.c
115
tpws/tpws_conn.c
@ -368,7 +368,7 @@ static void set_user_timeout(int fd, int timeout)
|
|||||||
//Createas a socket and initiates the connection to the host specified by
|
//Createas a socket and initiates the connection to the host specified by
|
||||||
//remote_addr.
|
//remote_addr.
|
||||||
//Returns -1 if something fails, >0 on success (socket fd).
|
//Returns -1 if something fails, >0 on success (socket fd).
|
||||||
static int connect_remote(const struct sockaddr *remote_addr, bool bApplyConnectionFooling)
|
static int connect_remote(const struct sockaddr *remote_addr, int mss)
|
||||||
{
|
{
|
||||||
int remote_fd = 0, yes = 1, no = 0;
|
int remote_fd = 0, yes = 1, no = 0;
|
||||||
|
|
||||||
@ -406,24 +406,18 @@ static int connect_remote(const struct sockaddr *remote_addr, bool bApplyConnect
|
|||||||
close(remote_fd);
|
close(remote_fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (bApplyConnectionFooling && params.mss)
|
#ifdef __linux__
|
||||||
|
if (mss)
|
||||||
{
|
{
|
||||||
uint16_t port = saport(remote_addr);
|
VPRINT("Setting MSS %d\n", mss);
|
||||||
if (pf_in_range(port,¶ms.mss_pf))
|
if (setsockopt(remote_fd, IPPROTO_TCP, TCP_MAXSEG, &mss, sizeof(int)) <0)
|
||||||
{
|
{
|
||||||
VPRINT("Setting MSS %d\n",params.mss);
|
DLOG_PERROR("setsockopt (TCP_MAXSEG, connect_remote)");
|
||||||
if (setsockopt(remote_fd, IPPROTO_TCP, TCP_MAXSEG, ¶ms.mss, sizeof(int)) <0)
|
close(remote_fd);
|
||||||
{
|
return -1;
|
||||||
DLOG_PERROR("setsockopt (TCP_MAXSEG, connect_remote)");
|
|
||||||
close(remote_fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VPRINT("Not setting MSS. Port %u is out of MSS port range.\n",port);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// if no bind address specified - address family will be 0 in params_connect_bindX
|
// if no bind address specified - address family will be 0 in params_connect_bindX
|
||||||
if(remote_addr->sa_family == params.connect_bind4.sin_family)
|
if(remote_addr->sa_family == params.connect_bind4.sin_family)
|
||||||
@ -494,13 +488,12 @@ static tproxy_conn_t *new_conn(int fd, bool remote)
|
|||||||
tproxy_conn_t *conn;
|
tproxy_conn_t *conn;
|
||||||
|
|
||||||
//Create connection object and fill in information
|
//Create connection object and fill in information
|
||||||
if((conn = (tproxy_conn_t*) malloc(sizeof(tproxy_conn_t))) == NULL)
|
if((conn = (tproxy_conn_t*) calloc(1, sizeof(tproxy_conn_t))) == NULL)
|
||||||
{
|
{
|
||||||
DLOG_ERR("Could not allocate memory for connection\n");
|
DLOG_ERR("Could not allocate memory for connection\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(conn, 0, sizeof(tproxy_conn_t));
|
|
||||||
conn->state = CONN_UNAVAILABLE;
|
conn->state = CONN_UNAVAILABLE;
|
||||||
conn->fd = fd;
|
conn->fd = fd;
|
||||||
conn->remote = remote;
|
conn->remote = remote;
|
||||||
@ -508,7 +501,7 @@ static tproxy_conn_t *new_conn(int fd, bool remote)
|
|||||||
#ifdef SPLICE_PRESENT
|
#ifdef SPLICE_PRESENT
|
||||||
// if dont tamper - both legs are spliced, create 2 pipes
|
// if dont tamper - both legs are spliced, create 2 pipes
|
||||||
// otherwise create pipe only in local leg
|
// otherwise create pipe only in local leg
|
||||||
if (!params.nosplice && ( !remote || !params.tamper || params.tamper_start || params.tamper_cutoff ) && pipe2(conn->splice_pipe, O_NONBLOCK) != 0)
|
if (!params.nosplice && ( !remote || !params.tamper || params.tamper_lim ) && pipe2(conn->splice_pipe, O_NONBLOCK) != 0)
|
||||||
{
|
{
|
||||||
DLOG_ERR("Could not create the splice pipe\n");
|
DLOG_ERR("Could not create the splice pipe\n");
|
||||||
free_conn(conn);
|
free_conn(conn);
|
||||||
@ -606,7 +599,7 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
|
|||||||
|
|
||||||
if (proxy_type==CONN_TYPE_TRANSPARENT)
|
if (proxy_type==CONN_TYPE_TRANSPARENT)
|
||||||
{
|
{
|
||||||
if ((remote_fd = connect_remote((struct sockaddr *)&orig_dst, true)) < 0)
|
if ((remote_fd = connect_remote((struct sockaddr *)&orig_dst, 0)) < 0)
|
||||||
{
|
{
|
||||||
DLOG_ERR("Failed to connect\n");
|
DLOG_ERR("Failed to connect\n");
|
||||||
close(local_fd);
|
close(local_fd);
|
||||||
@ -626,6 +619,8 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
|
|||||||
|
|
||||||
if (proxy_type==CONN_TYPE_TRANSPARENT)
|
if (proxy_type==CONN_TYPE_TRANSPARENT)
|
||||||
{
|
{
|
||||||
|
sacopy(&conn->dest, (struct sockaddr *)&orig_dst);
|
||||||
|
|
||||||
if(!(conn->partner = new_conn(remote_fd, true)))
|
if(!(conn->partner = new_conn(remote_fd, true)))
|
||||||
{
|
{
|
||||||
free_conn(conn);
|
free_conn(conn);
|
||||||
@ -667,6 +662,10 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
|
|||||||
TAILQ_INSERT_HEAD(conn_list, conn->partner, conn_ptrs);
|
TAILQ_INSERT_HEAD(conn_list, conn->partner, conn_ptrs);
|
||||||
legs_remote++;
|
legs_remote++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proxy_type==CONN_TYPE_TRANSPARENT)
|
||||||
|
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -782,32 +781,26 @@ static bool handle_unsent(tproxy_conn_t *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool proxy_mode_connect_remote(const struct sockaddr *sa, tproxy_conn_t *conn, struct tailhead *conn_list)
|
static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn_list)
|
||||||
{
|
{
|
||||||
int remote_fd;
|
int remote_fd;
|
||||||
|
|
||||||
if (params.debug>=1)
|
if (params.debug>=1)
|
||||||
{
|
{
|
||||||
char ip_port[48];
|
char ip_port[48];
|
||||||
ntop46_port(sa,ip_port,sizeof(ip_port));
|
ntop46_port((struct sockaddr *)&conn->dest,ip_port,sizeof(ip_port));
|
||||||
VPRINT("socks target for fd=%d is : %s\n", conn->fd, ip_port);
|
VPRINT("socks target for fd=%d is : %s\n", conn->fd, ip_port);
|
||||||
}
|
}
|
||||||
if (check_local_ip((struct sockaddr *)sa))
|
if (check_local_ip((struct sockaddr *)&conn->dest))
|
||||||
{
|
{
|
||||||
VPRINT("Dropping connection to local address for security reasons\n");
|
VPRINT("Dropping connection to local address for security reasons\n");
|
||||||
socks_send_rep(conn->socks_ver, conn->fd, S5_REP_NOT_ALLOWED_BY_RULESET);
|
socks_send_rep(conn->socks_ver, conn->fd, S5_REP_NOT_ALLOWED_BY_RULESET);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bConnFooling=true;
|
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
|
||||||
if (conn->track.hostname && params.mss)
|
|
||||||
{
|
|
||||||
bConnFooling=HostlistCheck(conn->track.hostname, NULL);
|
|
||||||
if (!bConnFooling)
|
|
||||||
VPRINT("0-phase desync hostlist check negative. not acting on this connection.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((remote_fd = connect_remote(sa, bConnFooling)) < 0)
|
if ((remote_fd = connect_remote((struct sockaddr *)&conn->dest, conn->track.dp ? conn->track.dp->mss : 0)) < 0)
|
||||||
{
|
{
|
||||||
DLOG_ERR("socks failed to connect (1) errno=%d\n", errno);
|
DLOG_ERR("socks failed to connect (1) errno=%d\n", errno);
|
||||||
socks_send_rep_errno(conn->socks_ver, conn->fd, errno);
|
socks_send_rep_errno(conn->socks_ver, conn->fd, errno);
|
||||||
@ -845,7 +838,6 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
|
|||||||
|
|
||||||
ssize_t rd,wr;
|
ssize_t rd,wr;
|
||||||
char buf[sizeof(s5_req)]; // s5_req - the largest possible req
|
char buf[sizeof(s5_req)]; // s5_req - the largest possible req
|
||||||
struct sockaddr_storage ss;
|
|
||||||
|
|
||||||
// receive proxy control message
|
// receive proxy control message
|
||||||
rd=recv(conn->fd, buf, sizeof(buf), MSG_DONTWAIT);
|
rd=recv(conn->fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||||
@ -928,10 +920,10 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
|
|||||||
socks4_send_rep(conn->fd, S4_REP_FAILED);
|
socks4_send_rep(conn->fd, S4_REP_FAILED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ss.ss_family = AF_INET;
|
conn->dest.ss_family = AF_INET;
|
||||||
((struct sockaddr_in*)&ss)->sin_port = m->port;
|
((struct sockaddr_in*)&conn->dest)->sin_port = m->port;
|
||||||
((struct sockaddr_in*)&ss)->sin_addr.s_addr = m->ip;
|
((struct sockaddr_in*)&conn->dest)->sin_addr.s_addr = m->ip;
|
||||||
return proxy_mode_connect_remote((struct sockaddr *)&ss, conn, conn_list);
|
return proxy_mode_connect_remote(conn, conn_list);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case S_WAIT_REQUEST:
|
case S_WAIT_REQUEST:
|
||||||
@ -960,16 +952,16 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
|
|||||||
switch(m->atyp)
|
switch(m->atyp)
|
||||||
{
|
{
|
||||||
case S5_ATYP_IP4:
|
case S5_ATYP_IP4:
|
||||||
ss.ss_family = AF_INET;
|
conn->dest.ss_family = AF_INET;
|
||||||
((struct sockaddr_in*)&ss)->sin_port = m->d4.port;
|
((struct sockaddr_in*)&conn->dest)->sin_port = m->d4.port;
|
||||||
((struct sockaddr_in*)&ss)->sin_addr = m->d4.addr;
|
((struct sockaddr_in*)&conn->dest)->sin_addr = m->d4.addr;
|
||||||
break;
|
break;
|
||||||
case S5_ATYP_IP6:
|
case S5_ATYP_IP6:
|
||||||
ss.ss_family = AF_INET6;
|
conn->dest.ss_family = AF_INET6;
|
||||||
((struct sockaddr_in6*)&ss)->sin6_port = m->d6.port;
|
((struct sockaddr_in6*)&conn->dest)->sin6_port = m->d6.port;
|
||||||
((struct sockaddr_in6*)&ss)->sin6_addr = m->d6.addr;
|
((struct sockaddr_in6*)&conn->dest)->sin6_addr = m->d6.addr;
|
||||||
((struct sockaddr_in6*)&ss)->sin6_flowinfo = 0;
|
((struct sockaddr_in6*)&conn->dest)->sin6_flowinfo = 0;
|
||||||
((struct sockaddr_in6*)&ss)->sin6_scope_id = 0;
|
((struct sockaddr_in6*)&conn->dest)->sin6_scope_id = 0;
|
||||||
break;
|
break;
|
||||||
case S5_ATYP_DOM:
|
case S5_ATYP_DOM:
|
||||||
{
|
{
|
||||||
@ -1006,7 +998,7 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
|
|||||||
return false; // should not be here. S5_REQ_CONNECT_VALID checks for valid atyp
|
return false; // should not be here. S5_REQ_CONNECT_VALID checks for valid atyp
|
||||||
|
|
||||||
}
|
}
|
||||||
return proxy_mode_connect_remote((struct sockaddr *)&ss,conn,conn_list);
|
return proxy_mode_connect_remote(conn,conn_list);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case S_WAIT_RESOLVE:
|
case S_WAIT_RESOLVE:
|
||||||
@ -1045,7 +1037,8 @@ static bool resolve_complete(struct resolve_item *ri, struct tailhead *conn_list
|
|||||||
DBGPRINT("resolve_complete put hostname : %s\n", ri->dom);
|
DBGPRINT("resolve_complete put hostname : %s\n", ri->dom);
|
||||||
conn->track.hostname = strdup(ri->dom);
|
conn->track.hostname = strdup(ri->dom);
|
||||||
}
|
}
|
||||||
return proxy_mode_connect_remote((struct sockaddr *)&ri->ss,conn,conn_list);
|
sacopy(&conn->dest, (struct sockaddr *)&ri->ss);
|
||||||
|
return proxy_mode_connect_remote(conn,conn_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1060,8 +1053,17 @@ static bool resolve_complete(struct resolve_item *ri, struct tailhead *conn_list
|
|||||||
|
|
||||||
static bool in_tamper_out_range(tproxy_conn_t *conn)
|
static bool in_tamper_out_range(tproxy_conn_t *conn)
|
||||||
{
|
{
|
||||||
return (params.tamper_start_n ? (conn->tnrd+1) : conn->trd) >= params.tamper_start &&
|
if (!conn->track.dp) return true;
|
||||||
(!params.tamper_cutoff || (params.tamper_cutoff_n ? (conn->tnrd+1) : conn->trd) < params.tamper_cutoff);
|
bool in_range = \
|
||||||
|
((conn->track.dp->tamper_start_n ? (conn->tnrd+1) : conn->trd) >= conn->track.dp->tamper_start &&
|
||||||
|
(!conn->track.dp->tamper_cutoff || (conn->track.dp->tamper_cutoff_n ? (conn->tnrd+1) : conn->trd) < conn->track.dp->tamper_cutoff));
|
||||||
|
DBGPRINT("tamper_out range check. stream pos %" PRIu64 "(n%" PRIu64 "). tamper range %s%u-%s%u (%s)\n",
|
||||||
|
conn->trd, conn->tnrd+1,
|
||||||
|
conn->track.dp ? conn->track.dp->tamper_start_n ? "n" : "" : "?" , conn->track.dp ? conn->track.dp->tamper_start : 0,
|
||||||
|
conn->track.dp ? conn->track.dp->tamper_cutoff_n ? "n" : "" : "?" , conn->track.dp ? conn->track.dp->tamper_cutoff : 0,
|
||||||
|
in_range ? "IN RANGE" : "OUT OF RANGE");
|
||||||
|
return in_range;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_size, size_t *segment_size, size_t *split_pos, uint8_t *split_flags)
|
static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_size, size_t *segment_size, size_t *split_pos, uint8_t *split_flags)
|
||||||
@ -1072,33 +1074,26 @@ static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_
|
|||||||
if (conn->remote)
|
if (conn->remote)
|
||||||
{
|
{
|
||||||
if (conn_partner_alive(conn) && !conn->partner->track.bTamperInCutoff)
|
if (conn_partner_alive(conn) && !conn->partner->track.bTamperInCutoff)
|
||||||
{
|
|
||||||
tamper_in(&conn->partner->track,segment,segment_buffer_size,segment_size);
|
tamper_in(&conn->partner->track,segment,segment_buffer_size,segment_size);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool in_range = in_tamper_out_range(conn);
|
if (in_tamper_out_range(conn))
|
||||||
DBGPRINT("tamper_out stream pos %" PRIu64 "(n%" PRIu64 "). tamper range %s%u-%s%u (%s)\n",
|
tamper_out(&conn->track,(struct sockaddr*)&conn->dest,segment,segment_buffer_size,segment_size,split_pos,split_flags);
|
||||||
conn->trd, conn->tnrd+1,
|
|
||||||
params.tamper_start_n ? "n" : "" , params.tamper_start,
|
|
||||||
params.tamper_cutoff_n ? "n" : "" , params.tamper_cutoff,
|
|
||||||
in_range ? "IN RANGE" : "OUT OF RANGE");
|
|
||||||
if (in_range) tamper_out(&conn->track,segment,segment_buffer_size,segment_size,split_pos,split_flags);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer must have at least one extra byte for OOB
|
// buffer must have at least one extra byte for OOB
|
||||||
static ssize_t send_or_buffer_oob(send_buffer_t *sb, int fd, uint8_t *buf, size_t len, int ttl, bool oob)
|
static ssize_t send_or_buffer_oob(send_buffer_t *sb, int fd, uint8_t *buf, size_t len, int ttl, bool oob, uint8_t oob_byte)
|
||||||
{
|
{
|
||||||
ssize_t wr;
|
ssize_t wr;
|
||||||
if (oob)
|
if (oob)
|
||||||
{
|
{
|
||||||
VPRINT("Sending OOB byte %02X\n", params.oob_byte);
|
VPRINT("Sending OOB byte %02X\n", oob_byte);
|
||||||
uint8_t oob_save;
|
uint8_t oob_save;
|
||||||
oob_save = buf[len];
|
oob_save = buf[len];
|
||||||
buf[len] = params.oob_byte;
|
buf[len] = oob_byte;
|
||||||
wr = send_or_buffer(sb, fd, buf, len+1, MSG_OOB, ttl);
|
wr = send_or_buffer(sb, fd, buf, len+1, MSG_OOB, ttl);
|
||||||
buf[len] = oob_save;
|
buf[len] = oob_save;
|
||||||
}
|
}
|
||||||
@ -1211,7 +1206,7 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
|||||||
{
|
{
|
||||||
VPRINT("Splitting at pos %zu%s\n", split_pos, (split_flags & SPLIT_FLAG_DISORDER) ? " with disorder" : "");
|
VPRINT("Splitting at pos %zu%s\n", split_pos, (split_flags & SPLIT_FLAG_DISORDER) ? " with disorder" : "");
|
||||||
|
|
||||||
wr = send_or_buffer_oob(conn->partner->wr_buf, conn->partner->fd, buf, split_pos, !!(split_flags & SPLIT_FLAG_DISORDER), !!(split_flags & SPLIT_FLAG_OOB));
|
wr = send_or_buffer_oob(conn->partner->wr_buf, conn->partner->fd, buf, split_pos, !!(split_flags & SPLIT_FLAG_DISORDER), !!(split_flags & SPLIT_FLAG_OOB), conn->track.dp ? conn->track.dp->oob_byte : 0);
|
||||||
DBGPRINT("send_or_buffer(1) fd=%d wr=%zd err=%d\n",conn->partner->fd,wr,errno);
|
DBGPRINT("send_or_buffer(1) fd=%d wr=%zd err=%d\n",conn->partner->fd,wr,errno);
|
||||||
if (wr >= 0)
|
if (wr >= 0)
|
||||||
{
|
{
|
||||||
|
@ -54,6 +54,7 @@ struct tproxy_conn
|
|||||||
int splice_pipe[2];
|
int splice_pipe[2];
|
||||||
conn_state_t state;
|
conn_state_t state;
|
||||||
conn_type_t conn_type;
|
conn_type_t conn_type;
|
||||||
|
struct sockaddr_storage dest;
|
||||||
|
|
||||||
struct tproxy_conn *partner; // other leg
|
struct tproxy_conn *partner; // other leg
|
||||||
time_t orphan_since;
|
time_t orphan_since;
|
||||||
|
Loading…
Reference in New Issue
Block a user