mirror of
https://github.com/bol-van/zapret.git
synced 2025-04-30 10:53:02 +03:00
Linting and formatting of .c
and .h
with C/C++ IntelliSence
This commit is contained in:
parent
8c94e3230e
commit
c1db09b19e
@ -35,7 +35,7 @@
|
|||||||
#define DEFAULT_V4_ZCT_MIN 2 // /30
|
#define DEFAULT_V4_ZCT_MIN 2 // /30
|
||||||
#define DEFAULT_V6_ZCT_MAX 72 // /56
|
#define DEFAULT_V6_ZCT_MAX 72 // /56
|
||||||
#define DEFAULT_V6_ZCT_MIN 64 // /64
|
#define DEFAULT_V6_ZCT_MIN 64 // /64
|
||||||
// must be no less than N ipv6 in subnet
|
// must be no less than N IPv6 in subnet
|
||||||
#define DEFAULT_V6_THRESHOLD 5
|
#define DEFAULT_V6_THRESHOLD 5
|
||||||
|
|
||||||
static int ucmp(const void *a, const void *b, void *arg)
|
static int ucmp(const void *a, const void *b, void *arg)
|
||||||
@ -59,18 +59,18 @@ static uint32_t unique(uint32_t *pu, uint32_t ct)
|
|||||||
for (i = j = 0; j < ct; i++)
|
for (i = j = 0; j < ct; i++)
|
||||||
{
|
{
|
||||||
u = pu[j++];
|
u = pu[j++];
|
||||||
for (; j < ct && pu[j] == u; j++);
|
for (; j < ct && pu[j] == u; j++)
|
||||||
|
;
|
||||||
pu[i] = u;
|
pu[i] = u;
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__llvm__)
|
#if defined(__GNUC__) && !defined(__llvm__)
|
||||||
__attribute__((optimize("no-strict-aliasing")))
|
__attribute__((optimize("no-strict-aliasing")))
|
||||||
#endif
|
#endif
|
||||||
static int cmp6(const void * a, const void * b, void *arg)
|
static int
|
||||||
|
cmp6(const void *a, const void *b, void *arg)
|
||||||
{
|
{
|
||||||
// this function is critical for sort performance
|
// this function is critical for sort performance
|
||||||
// on big endian systems cpu byte order is equal to network byte order
|
// on big endian systems cpu byte order is equal to network byte order
|
||||||
@ -102,7 +102,8 @@ static int cmp6(const void * a, const void * b, void *arg)
|
|||||||
aa = ((uint64_t *)((struct in6_addr *)a)->s6_addr)[1];
|
aa = ((uint64_t *)((struct in6_addr *)a)->s6_addr)[1];
|
||||||
bb = ((uint64_t *)((struct in6_addr *)b)->s6_addr)[1];
|
bb = ((uint64_t *)((struct in6_addr *)b)->s6_addr)[1];
|
||||||
#endif
|
#endif
|
||||||
return aa < bb ? -1 : aa > bb ? 1 : 0;
|
return aa < bb ? -1 : aa > bb ? 1
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -124,7 +125,8 @@ static uint32_t unique6(struct in6_addr *pu, uint32_t ct)
|
|||||||
uint32_t i, j, k;
|
uint32_t i, j, k;
|
||||||
for (i = j = 0; j < ct; i++)
|
for (i = j = 0; j < ct; i++)
|
||||||
{
|
{
|
||||||
for (k = j++; j < ct && !memcmp(pu + j, pu + k, sizeof(struct in6_addr)); j++);
|
for (k = j++; j < ct && !memcmp(pu + j, pu + k, sizeof(struct in6_addr)); j++)
|
||||||
|
;
|
||||||
pu[i] = pu[k];
|
pu[i] = pu[k];
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
@ -144,14 +146,14 @@ static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a)
|
|||||||
static struct in6_addr ip6_mask[129];
|
static struct in6_addr ip6_mask[129];
|
||||||
static void mask_from_bitcount6_prepare(void)
|
static void mask_from_bitcount6_prepare(void)
|
||||||
{
|
{
|
||||||
for (int zct=0;zct<=128;zct++) mask_from_bitcount6_make(zct, ip6_mask+zct);
|
for (int zct = 0; zct <= 128; zct++)
|
||||||
|
mask_from_bitcount6_make(zct, ip6_mask + zct);
|
||||||
}
|
}
|
||||||
static inline const struct in6_addr *mask_from_bitcount6(uint32_t zct)
|
static inline const struct in6_addr *mask_from_bitcount6(uint32_t zct)
|
||||||
{
|
{
|
||||||
return ip6_mask + zct;
|
return ip6_mask + zct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// this is "correct" solution for strict aliasing feature
|
// this is "correct" solution for strict aliasing feature
|
||||||
// but I don't like this style of coding
|
// but I don't like this style of coding
|
||||||
@ -178,7 +180,8 @@ static void ip6_and(const struct in6_addr *a, const struct in6_addr *b, struct i
|
|||||||
#if defined(__GNUC__) && !defined(__llvm__)
|
#if defined(__GNUC__) && !defined(__llvm__)
|
||||||
__attribute__((optimize("no-strict-aliasing")))
|
__attribute__((optimize("no-strict-aliasing")))
|
||||||
#endif
|
#endif
|
||||||
static void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result)
|
static void
|
||||||
|
ip6_and(const struct in6_addr *restrict a, const struct in6_addr *restrict b, struct in6_addr *restrict result)
|
||||||
{
|
{
|
||||||
#ifdef __SIZEOF_INT128__
|
#ifdef __SIZEOF_INT128__
|
||||||
// gcc and clang have 128 bit int types on some 64-bit archs. take some advantage
|
// gcc and clang have 128 bit int types on some 64-bit archs. take some advantage
|
||||||
@ -192,10 +195,10 @@ static void ip6_and(const struct in6_addr * restrict a, const struct in6_addr *
|
|||||||
static void rtrim(char *s)
|
static void rtrim(char *s)
|
||||||
{
|
{
|
||||||
if (s)
|
if (s)
|
||||||
for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0';
|
for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--)
|
||||||
|
*p = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct params_s
|
static struct params_s
|
||||||
{
|
{
|
||||||
bool ipv6;
|
bool ipv6;
|
||||||
@ -204,16 +207,14 @@ static struct params_s
|
|||||||
uint32_t v6_threshold; // for v6
|
uint32_t v6_threshold; // for v6
|
||||||
} params;
|
} params;
|
||||||
|
|
||||||
|
|
||||||
static void exithelp(void)
|
static void exithelp(void)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
" -4\t\t\t\t; ipv4 list (default)\n"
|
" -4\t\t\t\t; IPv4 list (default)\n"
|
||||||
" -6\t\t\t\t; ipv6 list\n"
|
" -6\t\t\t\t; IPv6 list\n"
|
||||||
" --prefix-length=min[-max]\t; consider prefix lengths from 'min' to 'max'. examples : 22-30 (ipv4), 56-64 (ipv6)\n"
|
" --prefix-length=min[-max]\t; consider prefix lengths from 'min' to 'max'. examples : 22-30 (IPv4), 56-64 (IPv6)\n"
|
||||||
" --v4-threshold=mul/div\t\t; ipv4 only : include subnets with more than mul/div ips. example : 3/4\n"
|
" --v4-threshold=mul/div\t\t; IPv4 only : include subnets with more than mul/div ips. example : 3/4\n"
|
||||||
" --v6-threshold=N\t\t; ipv6 only : include subnets with more than N v6 ips. example : 5\n"
|
" --v6-threshold=N\t\t; IPv6 only : include subnets with more than N v6 ips. example : 5\n");
|
||||||
);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,11 +237,11 @@ static void parse_params(int argc, char *argv[])
|
|||||||
{"prefix-length", required_argument, 0, 0}, // optidx=4
|
{"prefix-length", required_argument, 0, 0}, // optidx=4
|
||||||
{"v4-threshold", required_argument, 0, 0}, // optidx=5
|
{"v4-threshold", required_argument, 0, 0}, // optidx=5
|
||||||
{"v6-threshold", required_argument, 0, 0}, // optidx=6
|
{"v6-threshold", required_argument, 0, 0}, // optidx=6
|
||||||
{ NULL,0,NULL,0 }
|
{NULL, 0, NULL, 0}};
|
||||||
};
|
|
||||||
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
||||||
{
|
{
|
||||||
if (v) exithelp();
|
if (v)
|
||||||
|
exithelp();
|
||||||
switch (option_index)
|
switch (option_index)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -255,7 +256,8 @@ static void parse_params(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
i = sscanf(optarg, "%u-%u", &plen1, &plen2);
|
i = sscanf(optarg, "%u-%u", &plen1, &plen2);
|
||||||
if (i == 1) plen2 = plen1;
|
if (i == 1)
|
||||||
|
plen2 = plen1;
|
||||||
if (i <= 0 || plen2 < plen1 || !plen1 || !plen2)
|
if (i <= 0 || plen2 < plen1 || !plen1 || !plen2)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "invalid parameter for prefix-length : %s\n", optarg);
|
fprintf(stderr, "invalid parameter for prefix-length : %s\n", optarg);
|
||||||
@ -285,11 +287,12 @@ static void parse_params(int argc, char *argv[])
|
|||||||
fprintf(stderr, "invalid parameter for prefix-length\n");
|
fprintf(stderr, "invalid parameter for prefix-length\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
params.zct_min = params.ipv6 ? plen2==-1 ? DEFAULT_V6_ZCT_MIN : 128-plen2 : plen2==-1 ? DEFAULT_V4_ZCT_MIN : 32-plen2;
|
params.zct_min = params.ipv6 ? plen2 == -1 ? DEFAULT_V6_ZCT_MIN : 128 - plen2 : plen2 == -1 ? DEFAULT_V4_ZCT_MIN
|
||||||
params.zct_max = params.ipv6 ? plen1==-1 ? DEFAULT_V6_ZCT_MAX : 128-plen1 : plen1==-1 ? DEFAULT_V4_ZCT_MAX : 32-plen1;
|
: 32 - plen2;
|
||||||
|
params.zct_max = params.ipv6 ? plen1 == -1 ? DEFAULT_V6_ZCT_MAX : 128 - plen1 : plen1 == -1 ? DEFAULT_V4_ZCT_MAX
|
||||||
|
: 32 - plen1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char str[256], d;
|
char str[256], d;
|
||||||
@ -319,13 +322,15 @@ int main(int argc, char **argv)
|
|||||||
// output it as is
|
// output it as is
|
||||||
if (sscanf(s + 1, "%u", &zct) == 1 && zct != 128)
|
if (sscanf(s + 1, "%u", &zct) == 1 && zct != 128)
|
||||||
{
|
{
|
||||||
if (zct<128) printf("%s/%u\n", str, zct);
|
if (zct < 128)
|
||||||
|
printf("%s/%u\n", str, zct);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (d == '-')
|
else if (d == '-')
|
||||||
{
|
{
|
||||||
if (inet_pton(AF_INET6, s+1, &a)) printf("%s-%s\n", str, s+1);
|
if (inet_pton(AF_INET6, s + 1, &a))
|
||||||
|
printf("%s-%s\n", str, s + 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ipct >= iplist_size)
|
if (ipct >= iplist_size)
|
||||||
@ -371,7 +376,8 @@ int main(int argc, char **argv)
|
|||||||
if (memcmp(&ip_start, &ip, sizeof(ip)))
|
if (memcmp(&ip_start, &ip, sizeof(ip)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ip_ct == 1) break;
|
if (ip_ct == 1)
|
||||||
|
break;
|
||||||
if (ip_ct >= params.v6_threshold)
|
if (ip_ct >= params.v6_threshold)
|
||||||
{
|
{
|
||||||
// network found. but is there smaller network with the same ip_ct ? dont do carpet bombing if possible, use smaller subnets
|
// network found. but is there smaller network with the same ip_ct ? dont do carpet bombing if possible, use smaller subnets
|
||||||
@ -411,8 +417,7 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
printf("%u.%u.%u.%u-%u.%u.%u.%u\n", u1, u2, u3, u4, u11, u22, u33, u44);
|
printf("%u.%u.%u.%u-%u.%u.%u.%u\n", u1, u2, u3, u4, u11, u22, u33, u44);
|
||||||
}
|
}
|
||||||
else
|
else if ((i = sscanf(str, "%u.%u.%u.%u/%u", &u1, &u2, &u3, &u4, &zct)) >= 4 &&
|
||||||
if ((i = sscanf(str, "%u.%u.%u.%u/%u", &u1, &u2, &u3, &u4, &zct)) >= 4 &&
|
|
||||||
!(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00))
|
!(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00))
|
||||||
{
|
{
|
||||||
if (i == 5 && zct != 32)
|
if (i == 5 && zct != 32)
|
||||||
@ -459,8 +464,10 @@ int main(int argc, char **argv)
|
|||||||
if (iplist[pos] > (ip_start + subnet_ct * (params.pctdiv - params.pctmult) / params.pctdiv))
|
if (iplist[pos] > (ip_start + subnet_ct * (params.pctdiv - params.pctmult) / params.pctdiv))
|
||||||
continue; // ip is higher than (1-PCT). definitely coverage is not enough. skip searching
|
continue; // ip is higher than (1-PCT). definitely coverage is not enough. skip searching
|
||||||
ip_end = ip_start | ~mask;
|
ip_end = ip_start | ~mask;
|
||||||
for (p=pos+1, ip_ct=1; p < ipct && iplist[p] <= ip_end; p++) ip_ct++; // count ips within subnet range
|
for (p = pos + 1, ip_ct = 1; p < ipct && iplist[p] <= ip_end; p++)
|
||||||
if (ip_ct == 1) break;
|
ip_ct++; // count ips within subnet range
|
||||||
|
if (ip_ct == 1)
|
||||||
|
break;
|
||||||
if (ip_ct >= (subnet_ct * params.pctmult / params.pctdiv))
|
if (ip_ct >= (subnet_ct * params.pctmult / params.pctdiv))
|
||||||
{
|
{
|
||||||
// network found. but is there smaller network with the same ip_ct ? dont do carpet bombing if possible, use smaller subnets
|
// network found. but is there smaller network with the same ip_ct ? dont do carpet bombing if possible, use smaller subnets
|
||||||
|
@ -61,7 +61,6 @@ typedef struct
|
|||||||
#define POP(low, high) ((void)(--top, (low = top->lo), (high = top->hi)))
|
#define POP(low, high) ((void)(--top, (low = top->lo), (high = top->hi)))
|
||||||
#define STACK_NOT_EMPTY (stack < top)
|
#define STACK_NOT_EMPTY (stack < top)
|
||||||
|
|
||||||
|
|
||||||
/* Order size using quicksort. This implementation incorporates
|
/* Order size using quicksort. This implementation incorporates
|
||||||
four optimizations discussed in Sedgewick:
|
four optimizations discussed in Sedgewick:
|
||||||
|
|
||||||
@ -86,8 +85,7 @@ typedef struct
|
|||||||
smaller partition. This *guarantees* no more than log (total_elems)
|
smaller partition. This *guarantees* no more than log (total_elems)
|
||||||
stack size is needed (actually O(1) in this case)! */
|
stack size is needed (actually O(1) in this case)! */
|
||||||
|
|
||||||
void
|
void gnu_quicksort(void *const pbase, size_t total_elems, size_t size,
|
||||||
gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
|
|
||||||
__gnu_compar_d_fn_t cmp, void *arg)
|
__gnu_compar_d_fn_t cmp, void *arg)
|
||||||
{
|
{
|
||||||
char *base_ptr = (char *)pbase;
|
char *base_ptr = (char *)pbase;
|
||||||
@ -160,8 +158,7 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
|
|||||||
right_ptr -= size;
|
right_ptr -= size;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} while (left_ptr <= right_ptr);
|
||||||
while (left_ptr <= right_ptr);
|
|
||||||
|
|
||||||
/* Set up pointers for next iteration. First determine whether
|
/* Set up pointers for next iteration. First determine whether
|
||||||
left and right partitions are below the threshold size. If so,
|
left and right partitions are below the threshold size. If so,
|
||||||
|
64
mdig/mdig.c
64
mdig/mdig.c
@ -34,7 +34,8 @@
|
|||||||
static void trimstr(char *s)
|
static void trimstr(char *s)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
for (p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0';
|
for (p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--)
|
||||||
|
*p = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *eai_str(int r)
|
static const char *eai_str(int r)
|
||||||
@ -76,7 +77,8 @@ static const char* eai_str(int r)
|
|||||||
|
|
||||||
static bool dom_valid(char *dom)
|
static bool dom_valid(char *dom)
|
||||||
{
|
{
|
||||||
if (!dom || *dom=='.') return false;
|
if (!dom || *dom == '.')
|
||||||
|
return false;
|
||||||
for (; *dom; dom++)
|
for (; *dom; dom++)
|
||||||
if (*dom < 0x20 || (*dom & 0x80) || !(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z')))
|
if (*dom < 0x20 || (*dom & 0x80) || !(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z')))
|
||||||
return false;
|
return false;
|
||||||
@ -86,8 +88,10 @@ static bool dom_valid(char *dom)
|
|||||||
static void invalid_domain_beautify(char *dom)
|
static void invalid_domain_beautify(char *dom)
|
||||||
{
|
{
|
||||||
for (int i = 0; *dom && i < 64; i++, dom++)
|
for (int i = 0; *dom && i < 64; i++, dom++)
|
||||||
if (*dom < 0x20 || *dom>0x7F) *dom = '?';
|
if (*dom < 0x20 || *dom > 0x7F)
|
||||||
if (*dom) *dom = 0;
|
*dom = '?';
|
||||||
|
if (*dom)
|
||||||
|
*dom = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FAMILY4 1
|
#define FAMILY4 1
|
||||||
@ -111,7 +115,8 @@ static char interlocked_get_dom(char *dom, size_t size)
|
|||||||
pthread_mutex_lock(&glob.flock);
|
pthread_mutex_lock(&glob.flock);
|
||||||
s = fgets(dom, size, stdin);
|
s = fgets(dom, size, stdin);
|
||||||
pthread_mutex_unlock(&glob.flock);
|
pthread_mutex_unlock(&glob.flock);
|
||||||
if (!s) return 0;
|
if (!s)
|
||||||
|
return 0;
|
||||||
trimstr(s);
|
trimstr(s);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -129,7 +134,11 @@ static void interlocked_fprintf(FILE *stream, const char * format, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define ELOG(format, ...) interlocked_fprintf(stderr, "[%d] " format "\n", tid, ##__VA_ARGS__)
|
#define ELOG(format, ...) interlocked_fprintf(stderr, "[%d] " format "\n", tid, ##__VA_ARGS__)
|
||||||
#define VLOG(format, ...) {if (glob.verbose) ELOG(format, ##__VA_ARGS__);}
|
#define VLOG(format, ...) \
|
||||||
|
{ \
|
||||||
|
if (glob.verbose) \
|
||||||
|
ELOG(format, ##__VA_ARGS__); \
|
||||||
|
}
|
||||||
|
|
||||||
static void print_addrinfo(struct addrinfo *ai)
|
static void print_addrinfo(struct addrinfo *ai)
|
||||||
{
|
{
|
||||||
@ -170,7 +179,8 @@ static void stat_plus(bool is_ok)
|
|||||||
ct_ok = glob.stats_ct_ok += is_ok;
|
ct_ok = glob.stats_ct_ok += is_ok;
|
||||||
pthread_mutex_unlock(&glob.slock);
|
pthread_mutex_unlock(&glob.slock);
|
||||||
|
|
||||||
if (!(ct % glob.stats_every)) stat_print(ct, ct_ok);
|
if (!(ct % glob.stats_every))
|
||||||
|
stat_print(ct, ct_ok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +208,8 @@ static void *t_resolver(void *arg)
|
|||||||
VLOG("started");
|
VLOG("started");
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(struct addrinfo));
|
memset(&hints, 0, sizeof(struct addrinfo));
|
||||||
hints.ai_family = (glob.family == FAMILY4) ? AF_INET : (glob.family == FAMILY6) ? AF_INET6 : AF_UNSPEC;
|
hints.ai_family = (glob.family == FAMILY4) ? AF_INET : (glob.family == FAMILY6) ? AF_INET6
|
||||||
|
: AF_UNSPEC;
|
||||||
hints.ai_socktype = SOCK_DGRAM;
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
|
||||||
while (interlocked_get_dom(dom, sizeof(dom)))
|
while (interlocked_get_dom(dom, sizeof(dom)))
|
||||||
@ -211,7 +222,8 @@ static void *t_resolver(void *arg)
|
|||||||
|
|
||||||
strncpy(s_ip, dom, sizeof(s_ip));
|
strncpy(s_ip, dom, sizeof(s_ip));
|
||||||
s_mask = strchr(s_ip, '/');
|
s_mask = strchr(s_ip, '/');
|
||||||
if (s_mask) *s_mask++ = 0;
|
if (s_mask)
|
||||||
|
*s_mask++ = 0;
|
||||||
family = GetAddrFamily(s_ip);
|
family = GetAddrFamily(s_ip);
|
||||||
if (family)
|
if (family)
|
||||||
{
|
{
|
||||||
@ -225,8 +237,14 @@ static void *t_resolver(void *arg)
|
|||||||
{
|
{
|
||||||
switch (family)
|
switch (family)
|
||||||
{
|
{
|
||||||
case AF_INET: is_ok = mask <= 32; mask_needed = mask < 32; break;
|
case AF_INET:
|
||||||
case AF_INET6: is_ok = mask <= 128; mask_needed = mask < 128; break;
|
is_ok = mask <= 32;
|
||||||
|
mask_needed = mask < 32;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
is_ok = mask <= 128;
|
||||||
|
mask_needed = mask < 128;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,7 +266,8 @@ static void *t_resolver(void *arg)
|
|||||||
if ((r = getaddrinfo(dom, NULL, &hints, &result)))
|
if ((r = getaddrinfo(dom, NULL, &hints, &result)))
|
||||||
{
|
{
|
||||||
VLOG("failed to resolve %s : result %d (%s)", dom, r, eai_str(r));
|
VLOG("failed to resolve %s : result %d (%s)", dom, r, eai_str(r));
|
||||||
if (r == EAI_AGAIN) continue; // temporary failure. should retry
|
if (r == EAI_AGAIN)
|
||||||
|
continue; // temporary failure. should retry
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -327,8 +346,7 @@ static void exithelp(void)
|
|||||||
" --verbose\t\t; print query progress to stderr\n"
|
" --verbose\t\t; print query progress to stderr\n"
|
||||||
" --stats=N\t\t; print resolve stats to stderr every N domains\n"
|
" --stats=N\t\t; print resolve stats to stderr every N domains\n"
|
||||||
" --log-resolved=<file>\t; log successfully resolved domains to a file\n"
|
" --log-resolved=<file>\t; log successfully resolved domains to a file\n"
|
||||||
" --log-failed=<file>\t; log failed domains to a file\n"
|
" --log-failed=<file>\t; log failed domains to a file\n");
|
||||||
);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
@ -344,8 +362,7 @@ int main(int argc, char **argv)
|
|||||||
{"stats", required_argument, 0, 0}, // optidx=4
|
{"stats", required_argument, 0, 0}, // optidx=4
|
||||||
{"log-resolved", required_argument, 0, 0}, // optidx=5
|
{"log-resolved", required_argument, 0, 0}, // optidx=5
|
||||||
{"log-failed", required_argument, 0, 0}, // optidx=6
|
{"log-failed", required_argument, 0, 0}, // optidx=6
|
||||||
{NULL,0,NULL,0}
|
{NULL, 0, NULL, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
memset(&glob, 0, sizeof(glob));
|
memset(&glob, 0, sizeof(glob));
|
||||||
*fn1 = *fn2 = 0;
|
*fn1 = *fn2 = 0;
|
||||||
@ -353,7 +370,8 @@ int main(int argc, char **argv)
|
|||||||
glob.threads = 1;
|
glob.threads = 1;
|
||||||
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
||||||
{
|
{
|
||||||
if (v) exithelp();
|
if (v)
|
||||||
|
exithelp();
|
||||||
switch (option_index)
|
switch (option_index)
|
||||||
{
|
{
|
||||||
case 0: /* help */
|
case 0: /* help */
|
||||||
@ -412,7 +430,8 @@ int main(int argc, char **argv)
|
|||||||
if (!glob.F_log_resolved)
|
if (!glob.F_log_resolved)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "failed to create %s\n", fn1);
|
fprintf(stderr, "failed to create %s\n", fn1);
|
||||||
r=5; goto ex;
|
r = 5;
|
||||||
|
goto ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*fn2)
|
if (*fn2)
|
||||||
@ -421,15 +440,18 @@ int main(int argc, char **argv)
|
|||||||
if (!glob.F_log_failed)
|
if (!glob.F_log_failed)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "failed to create %s\n", fn2);
|
fprintf(stderr, "failed to create %s\n", fn2);
|
||||||
r=5; goto ex;
|
r = 5;
|
||||||
|
goto ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = run_threads();
|
r = run_threads();
|
||||||
|
|
||||||
ex:
|
ex:
|
||||||
if (glob.F_log_resolved) fclose(glob.F_log_resolved);
|
if (glob.F_log_resolved)
|
||||||
if (glob.F_log_failed) fclose(glob.F_log_failed);
|
fclose(glob.F_log_resolved);
|
||||||
|
if (glob.F_log_failed)
|
||||||
|
fclose(glob.F_log_failed);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ static uint16_t from64to16(uint64_t x)
|
|||||||
|
|
||||||
// this function preserves data alignment requirements (otherwise it will be damn slow on mips arch)
|
// this function preserves data alignment requirements (otherwise it will be damn slow on mips arch)
|
||||||
// and uses 64-bit arithmetics to improve speed
|
// and uses 64-bit arithmetics to improve speed
|
||||||
// taken from linux source code
|
// taken from Linux source code
|
||||||
static uint16_t do_csum(const uint8_t *buff, size_t len)
|
static uint16_t do_csum(const uint8_t *buff, size_t len)
|
||||||
{
|
{
|
||||||
uint8_t odd;
|
uint8_t odd;
|
||||||
@ -21,7 +21,8 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
|
|||||||
uint64_t result, w, carry = 0;
|
uint64_t result, w, carry = 0;
|
||||||
uint16_t u16;
|
uint16_t u16;
|
||||||
|
|
||||||
if (!len) return 0;
|
if (!len)
|
||||||
|
return 0;
|
||||||
odd = (uint8_t)(1 & (size_t)buff);
|
odd = (uint8_t)(1 & (size_t)buff);
|
||||||
if (odd)
|
if (odd)
|
||||||
{
|
{
|
||||||
@ -89,7 +90,8 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
|
|||||||
result += u16;
|
result += u16;
|
||||||
}
|
}
|
||||||
u16 = from64to16(result);
|
u16 = from64to16(result);
|
||||||
if (odd) u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8);
|
if (odd)
|
||||||
|
u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8);
|
||||||
return u16;
|
return u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +123,6 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8
|
|||||||
return ~from64to16(a);
|
return ~from64to16(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void tcp4_fix_checksum(struct tcphdr *tcp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
|
void tcp4_fix_checksum(struct tcphdr *tcp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
|
||||||
{
|
{
|
||||||
tcp->th_sum = 0;
|
tcp->th_sum = 0;
|
||||||
|
114
nfq/conntrack.c
114
nfq/conntrack.c
@ -49,7 +49,11 @@ static void ConntrackFreeElem(t_conntrack_pool *elem)
|
|||||||
static void ConntrackPoolDestroyPool(t_conntrack_pool **pp)
|
static void ConntrackPoolDestroyPool(t_conntrack_pool **pp)
|
||||||
{
|
{
|
||||||
t_conntrack_pool *elem, *tmp;
|
t_conntrack_pool *elem, *tmp;
|
||||||
HASH_ITER(hh, *pp, elem, tmp) { HASH_DEL(*pp, elem); ConntrackFreeElem(elem); }
|
HASH_ITER(hh, *pp, elem, tmp)
|
||||||
|
{
|
||||||
|
HASH_DEL(*pp, elem);
|
||||||
|
ConntrackFreeElem(elem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void ConntrackPoolDestroy(t_conntrack *p)
|
void ConntrackPoolDestroy(t_conntrack *p)
|
||||||
{
|
{
|
||||||
@ -87,7 +91,6 @@ void ConntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const s
|
|||||||
extract_ports(tcphdr, udphdr, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport);
|
extract_ports(tcphdr, udphdr, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *c)
|
static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *c)
|
||||||
{
|
{
|
||||||
t_conntrack_pool *t;
|
t_conntrack_pool *t;
|
||||||
@ -111,11 +114,16 @@ static void ConntrackReInitTrack(t_ctrack *t)
|
|||||||
static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c)
|
static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c)
|
||||||
{
|
{
|
||||||
t_conntrack_pool *ctnew;
|
t_conntrack_pool *ctnew;
|
||||||
if (!(ctnew = malloc(sizeof(*ctnew)))) return NULL;
|
if (!(ctnew = malloc(sizeof(*ctnew))))
|
||||||
|
return NULL;
|
||||||
ctnew->conn = *c;
|
ctnew->conn = *c;
|
||||||
oom = false;
|
oom = false;
|
||||||
HASH_ADD(hh, *pp, conn, sizeof(*c), ctnew);
|
HASH_ADD(hh, *pp, conn, sizeof(*c), ctnew);
|
||||||
if (oom) { free(ctnew); return NULL; }
|
if (oom)
|
||||||
|
{
|
||||||
|
free(ctnew);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
ConntrackInitTrack(&ctnew->track);
|
ConntrackInitTrack(&ctnew->track);
|
||||||
return ctnew;
|
return ctnew;
|
||||||
}
|
}
|
||||||
@ -129,7 +137,6 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
|
|||||||
{
|
{
|
||||||
t->pcounter_reply++;
|
t->pcounter_reply++;
|
||||||
t->pdcounter_reply += !!len_payload;
|
t->pdcounter_reply += !!len_payload;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -141,13 +148,16 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
|
|||||||
{
|
{
|
||||||
if (tcp_syn_segment(tcphdr))
|
if (tcp_syn_segment(tcphdr))
|
||||||
{
|
{
|
||||||
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry
|
if (t->state != SYN)
|
||||||
|
ConntrackReInitTrack(t); // erase current entry
|
||||||
t->seq0 = ntohl(tcphdr->th_seq);
|
t->seq0 = ntohl(tcphdr->th_seq);
|
||||||
}
|
}
|
||||||
else if (tcp_synack_segment(tcphdr))
|
else if (tcp_synack_segment(tcphdr))
|
||||||
{
|
{
|
||||||
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry
|
if (t->state != SYN)
|
||||||
if (!t->seq0) t->seq0 = ntohl(tcphdr->th_ack)-1;
|
ConntrackReInitTrack(t); // erase current entry
|
||||||
|
if (!t->seq0)
|
||||||
|
t->seq0 = ntohl(tcphdr->th_ack) - 1;
|
||||||
t->ack0 = ntohl(tcphdr->th_seq);
|
t->ack0 = ntohl(tcphdr->th_seq);
|
||||||
}
|
}
|
||||||
else if (tcphdr->th_flags & (TH_FIN | TH_RST))
|
else if (tcphdr->th_flags & (TH_FIN | TH_RST))
|
||||||
@ -159,7 +169,8 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
|
|||||||
if (t->state == SYN)
|
if (t->state == SYN)
|
||||||
{
|
{
|
||||||
t->state = ESTABLISHED;
|
t->state = ESTABLISHED;
|
||||||
if (!bReverse && !t->ack0) t->ack0 = ntohl(tcphdr->th_ack)-1;
|
if (!bReverse && !t->ack0)
|
||||||
|
t->ack0 = ntohl(tcphdr->th_ack) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scale = tcp_find_scale_factor(tcphdr);
|
scale = tcp_find_scale_factor(tcphdr);
|
||||||
@ -169,8 +180,8 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
|
|||||||
t->ack_last = ntohl(tcphdr->th_seq);
|
t->ack_last = ntohl(tcphdr->th_seq);
|
||||||
t->pos_reply = t->ack_last + len_payload;
|
t->pos_reply = t->ack_last + len_payload;
|
||||||
t->winsize_reply = ntohs(tcphdr->th_win);
|
t->winsize_reply = ntohs(tcphdr->th_win);
|
||||||
if (scale!=SCALE_NONE) t->scale_reply = scale;
|
if (scale != SCALE_NONE)
|
||||||
|
t->scale_reply = scale;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -178,7 +189,8 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
|
|||||||
t->pos_orig = t->seq_last + len_payload;
|
t->pos_orig = t->seq_last + len_payload;
|
||||||
t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack);
|
t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack);
|
||||||
t->winsize_orig = ntohs(tcphdr->th_win);
|
t->winsize_orig = ntohs(tcphdr->th_win);
|
||||||
if (scale!=SCALE_NONE) t->scale_orig = scale;
|
if (scale != SCALE_NONE)
|
||||||
|
t->scale_orig = scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -206,8 +218,10 @@ static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct ip
|
|||||||
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
|
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
|
||||||
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
|
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
|
||||||
{
|
{
|
||||||
if (bReverse) *bReverse = false;
|
if (bReverse)
|
||||||
if (ctrack) *ctrack = &ctr->track;
|
*bReverse = false;
|
||||||
|
if (ctrack)
|
||||||
|
*ctrack = &ctr->track;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -215,8 +229,10 @@ static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct ip
|
|||||||
connswap(&conn, &connswp);
|
connswap(&conn, &connswp);
|
||||||
if ((ctr = ConntrackPoolSearch(*pp, &connswp)))
|
if ((ctr = ConntrackPoolSearch(*pp, &connswp)))
|
||||||
{
|
{
|
||||||
if (bReverse) *bReverse = true;
|
if (bReverse)
|
||||||
if (ctrack) *ctrack = &ctr->track;
|
*bReverse = true;
|
||||||
|
if (ctrack)
|
||||||
|
*ctrack = &ctr->track;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,8 +275,10 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
ok:
|
ok:
|
||||||
if (ctrack) *ctrack = &ctr->track;
|
if (ctrack)
|
||||||
if (bReverse) *bReverse = b_rev;
|
*ctrack = &ctr->track;
|
||||||
|
if (bReverse)
|
||||||
|
*bReverse = b_rev;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse)
|
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse)
|
||||||
@ -278,8 +296,10 @@ static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct ip *ip, co
|
|||||||
connswap(&conn, &connswp);
|
connswap(&conn, &connswp);
|
||||||
t = ConntrackPoolSearch(*pp, &connswp);
|
t = ConntrackPoolSearch(*pp, &connswp);
|
||||||
}
|
}
|
||||||
if (!t) return false;
|
if (!t)
|
||||||
HASH_DEL(*pp, t); ConntrackFreeElem(t);
|
return false;
|
||||||
|
HASH_DEL(*pp, t);
|
||||||
|
ConntrackFreeElem(t);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
|
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
|
||||||
@ -294,17 +314,17 @@ void ConntrackPoolPurge(t_conntrack *p)
|
|||||||
|
|
||||||
if ((tnow - p->t_last_purge) >= p->t_purge_interval)
|
if ((tnow - p->t_last_purge) >= p->t_purge_interval)
|
||||||
{
|
{
|
||||||
HASH_ITER(hh, p->pool , t, tmp) {
|
HASH_ITER(hh, p->pool, t, tmp)
|
||||||
|
{
|
||||||
tidle = tnow - t->track.t_last;
|
tidle = tnow - t->track.t_last;
|
||||||
if (t->track.b_cutoff ||
|
if (t->track.b_cutoff ||
|
||||||
(t->conn.l4proto==IPPROTO_TCP && (
|
(t->conn.l4proto == IPPROTO_TCP && ((t->track.state == SYN && tidle >= p->timeout_syn) ||
|
||||||
(t->track.state==SYN && tidle>=p->timeout_syn) ||
|
|
||||||
(t->track.state == ESTABLISHED && tidle >= p->timeout_established) ||
|
(t->track.state == ESTABLISHED && tidle >= p->timeout_established) ||
|
||||||
(t->track.state==FIN && tidle>=p->timeout_fin))
|
(t->track.state == FIN && tidle >= p->timeout_fin))) ||
|
||||||
) || (t->conn.l4proto==IPPROTO_UDP && tidle>=p->timeout_udp)
|
(t->conn.l4proto == IPPROTO_UDP && tidle >= p->timeout_udp))
|
||||||
)
|
|
||||||
{
|
{
|
||||||
HASH_DEL(p->pool, t); ConntrackFreeElem(t);
|
HASH_DEL(p->pool, t);
|
||||||
|
ConntrackFreeElem(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p->t_last_purge = tnow;
|
p->t_last_purge = tnow;
|
||||||
@ -313,19 +333,26 @@ void ConntrackPoolPurge(t_conntrack *p)
|
|||||||
|
|
||||||
static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsize)
|
static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize) *buf=0;
|
if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize)
|
||||||
|
*buf = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *ConntrackProtoName(t_l7proto proto)
|
static const char *ConntrackProtoName(t_l7proto proto)
|
||||||
{
|
{
|
||||||
switch (proto)
|
switch (proto)
|
||||||
{
|
{
|
||||||
case HTTP: return "HTTP";
|
case HTTP:
|
||||||
case TLS: return "TLS";
|
return "HTTP";
|
||||||
case QUIC: return "QUIC";
|
case TLS:
|
||||||
case WIREGUARD: return "WIREGUARD";
|
return "TLS";
|
||||||
case DHT: return "DHT";
|
case QUIC:
|
||||||
default: return "UNKNOWN";
|
return "QUIC";
|
||||||
|
case WIREGUARD:
|
||||||
|
return "WIREGUARD";
|
||||||
|
case DHT:
|
||||||
|
return "DHT";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ConntrackPoolDump(const t_conntrack *p)
|
void ConntrackPoolDump(const t_conntrack *p)
|
||||||
@ -333,7 +360,8 @@ void ConntrackPoolDump(const t_conntrack *p)
|
|||||||
t_conntrack_pool *t, *tmp;
|
t_conntrack_pool *t, *tmp;
|
||||||
char sa1[40], sa2[40];
|
char sa1[40], sa2[40];
|
||||||
time_t tnow = time(NULL);
|
time_t tnow = time(NULL);
|
||||||
HASH_ITER(hh, p->pool, t, tmp) {
|
HASH_ITER(hh, p->pool, t, tmp)
|
||||||
|
{
|
||||||
taddr2str(t->conn.l3proto, &t->conn.src, sa1, sizeof(sa1));
|
taddr2str(t->conn.l3proto, &t->conn.src, sa1, sizeof(sa1));
|
||||||
taddr2str(t->conn.l3proto, &t->conn.dst, sa2, sizeof(sa2));
|
taddr2str(t->conn.l3proto, &t->conn.dst, sa2, sizeof(sa2));
|
||||||
printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu packets_orig=d%llu/n%llu packets_reply=d%llu/n%llu ",
|
printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu packets_orig=d%llu/n%llu packets_reply=d%llu/n%llu ",
|
||||||
@ -358,7 +386,6 @@ void ConntrackPoolDump(const t_conntrack *p)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ReasmClear(t_reassemble *reasm)
|
void ReasmClear(t_reassemble *reasm)
|
||||||
{
|
{
|
||||||
if (reasm->packet)
|
if (reasm->packet)
|
||||||
@ -371,7 +398,8 @@ void ReasmClear(t_reassemble *reasm)
|
|||||||
bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
|
bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
|
||||||
{
|
{
|
||||||
reasm->packet = malloc(size_requested);
|
reasm->packet = malloc(size_requested);
|
||||||
if (!reasm->packet) return false;
|
if (!reasm->packet)
|
||||||
|
return false;
|
||||||
reasm->size = size_requested;
|
reasm->size = size_requested;
|
||||||
reasm->size_present = 0;
|
reasm->size_present = 0;
|
||||||
reasm->seq = seq_start;
|
reasm->seq = seq_start;
|
||||||
@ -380,19 +408,23 @@ bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
|
|||||||
bool ReasmResize(t_reassemble *reasm, size_t new_size)
|
bool ReasmResize(t_reassemble *reasm, size_t new_size)
|
||||||
{
|
{
|
||||||
uint8_t *p = realloc(reasm->packet, new_size);
|
uint8_t *p = realloc(reasm->packet, new_size);
|
||||||
if (!p) return false;
|
if (!p)
|
||||||
|
return false;
|
||||||
reasm->packet = p;
|
reasm->packet = p;
|
||||||
reasm->size = new_size;
|
reasm->size = new_size;
|
||||||
if (reasm->size_present > new_size) reasm->size_present = new_size;
|
if (reasm->size_present > new_size)
|
||||||
|
reasm->size_present = new_size;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len)
|
bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len)
|
||||||
{
|
{
|
||||||
if (reasm->seq!=seq) return false; // fail session if out of sequence
|
if (reasm->seq != seq)
|
||||||
|
return false; // fail session if out of sequence
|
||||||
|
|
||||||
size_t szcopy;
|
size_t szcopy;
|
||||||
szcopy = reasm->size - reasm->size_present;
|
szcopy = reasm->size - reasm->size_present;
|
||||||
if (len<szcopy) szcopy = len;
|
if (len < szcopy)
|
||||||
|
szcopy = len;
|
||||||
memcpy(reasm->packet + reasm->size_present, payload, szcopy);
|
memcpy(reasm->packet + reasm->size_present, payload, szcopy);
|
||||||
reasm->size_present += szcopy;
|
reasm->size_present += szcopy;
|
||||||
reasm->seq += (uint32_t)szcopy;
|
reasm->seq += (uint32_t)szcopy;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
// this conntrack is not bullet-proof
|
// this conntrack is not bullet-proof
|
||||||
// its designed to satisfy dpi desync needs only
|
// its designed to satisfy dpi desync needs only
|
||||||
|
|
||||||
@ -19,7 +18,6 @@
|
|||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netinet/udp.h>
|
#include <netinet/udp.h>
|
||||||
|
|
||||||
|
|
||||||
// #define HASH_BLOOM 20
|
// #define HASH_BLOOM 20
|
||||||
#define HASH_NONFATAL_OOM 1
|
#define HASH_NONFATAL_OOM 1
|
||||||
#undef HASH_FUNCTION
|
#undef HASH_FUNCTION
|
||||||
@ -28,7 +26,8 @@
|
|||||||
|
|
||||||
#define RETRANS_COUNTER_STOP ((uint8_t) - 1)
|
#define RETRANS_COUNTER_STOP ((uint8_t) - 1)
|
||||||
|
|
||||||
typedef union {
|
typedef union
|
||||||
|
{
|
||||||
struct in_addr ip;
|
struct in_addr ip;
|
||||||
struct in6_addr ip6;
|
struct in6_addr ip6;
|
||||||
} t_addr;
|
} t_addr;
|
||||||
@ -41,7 +40,8 @@ typedef struct
|
|||||||
} t_conn;
|
} t_conn;
|
||||||
|
|
||||||
// this structure helps to reassemble continuous packets streams. it does not support out-of-orders
|
// this structure helps to reassemble continuous packets streams. it does not support out-of-orders
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size.
|
uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size.
|
||||||
uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session.
|
uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session.
|
||||||
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
|
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
|
||||||
@ -51,8 +51,21 @@ typedef struct {
|
|||||||
// SYN - SYN or SYN/ACK received
|
// SYN - SYN or SYN/ACK received
|
||||||
// ESTABLISHED - any except SYN or SYN/ACK received
|
// ESTABLISHED - any except SYN or SYN/ACK received
|
||||||
// FIN - FIN or RST received
|
// FIN - FIN or RST received
|
||||||
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
|
typedef enum
|
||||||
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
|
{
|
||||||
|
SYN = 0,
|
||||||
|
ESTABLISHED,
|
||||||
|
FIN
|
||||||
|
} t_connstate;
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
UNKNOWN = 0,
|
||||||
|
HTTP,
|
||||||
|
TLS,
|
||||||
|
QUIC,
|
||||||
|
WIREGUARD,
|
||||||
|
DHT
|
||||||
|
} t_l7proto;
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
// common state
|
// common state
|
||||||
|
110
nfq/crypto/aes.c
110
nfq/crypto/aes.c
@ -58,17 +58,18 @@ static uint32_t RCON[10]; // AES round constants
|
|||||||
* Platform Endianness Neutralizing Load and Store Macro definitions
|
* Platform Endianness Neutralizing Load and Store Macro definitions
|
||||||
* AES wants platform-neutral Little Endian (LE) byte ordering
|
* AES wants platform-neutral Little Endian (LE) byte ordering
|
||||||
*/
|
*/
|
||||||
#define GET_UINT32_LE(n,b,i) { \
|
#define GET_UINT32_LE(n, b, i) \
|
||||||
(n) = ( (uint32_t) (b)[(i) ] ) \
|
{ \
|
||||||
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
|
(n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \
|
||||||
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
|
}
|
||||||
| ( (uint32_t) (b)[(i) + 3] << 24 ); }
|
|
||||||
|
|
||||||
#define PUT_UINT32_LE(n,b,i) { \
|
#define PUT_UINT32_LE(n, b, i) \
|
||||||
|
{ \
|
||||||
(b)[(i)] = (uchar)((n)); \
|
(b)[(i)] = (uchar)((n)); \
|
||||||
(b)[(i) + 1] = (uchar)((n) >> 8); \
|
(b)[(i) + 1] = (uchar)((n) >> 8); \
|
||||||
(b)[(i) + 2] = (uchar)((n) >> 16); \
|
(b)[(i) + 2] = (uchar)((n) >> 16); \
|
||||||
(b)[(i) + 3] = (uchar) ( (n) >> 24 ); }
|
(b)[(i) + 3] = (uchar)((n) >> 24); \
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AES forward and reverse encryption round processing macros
|
* AES forward and reverse encryption round processing macros
|
||||||
@ -127,9 +128,18 @@ static uint32_t RCON[10]; // AES round constants
|
|||||||
#define ROTL8(x) ((x << 8) & 0xFFFFFFFF) | (x >> 24)
|
#define ROTL8(x) ((x << 8) & 0xFFFFFFFF) | (x >> 24)
|
||||||
#define XTIME(x) ((x << 1) ^ ((x & 0x80) ? 0x1B : 0x00))
|
#define XTIME(x) ((x << 1) ^ ((x & 0x80) ? 0x1B : 0x00))
|
||||||
#define MUL(x, y) ((x && y) ? pow[(log[x] + log[y]) % 255] : 0)
|
#define MUL(x, y) ((x && y) ? pow[(log[x] + log[y]) % 255] : 0)
|
||||||
#define MIX(x,y) { y = ( (y << 1) | (y >> 7) ) & 0xFF; x ^= y; }
|
#define MIX(x, y) \
|
||||||
#define CPY128 { *RK++ = *SK++; *RK++ = *SK++; \
|
{ \
|
||||||
*RK++ = *SK++; *RK++ = *SK++; }
|
y = ((y << 1) | (y >> 7)) & 0xFF; \
|
||||||
|
x ^= y; \
|
||||||
|
}
|
||||||
|
#define CPY128 \
|
||||||
|
{ \
|
||||||
|
*RK++ = *SK++; \
|
||||||
|
*RK++ = *SK++; \
|
||||||
|
*RK++ = *SK++; \
|
||||||
|
*RK++ = *SK++; \
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
@ -147,16 +157,19 @@ void aes_init_keygen_tables(void)
|
|||||||
int pow[256];
|
int pow[256];
|
||||||
int log[256];
|
int log[256];
|
||||||
|
|
||||||
if (aes_tables_inited) return;
|
if (aes_tables_inited)
|
||||||
|
return;
|
||||||
|
|
||||||
// fill the 'pow' and 'log' tables over GF(2^8)
|
// fill the 'pow' and 'log' tables over GF(2^8)
|
||||||
for (i = 0, x = 1; i < 256; i++) {
|
for (i = 0, x = 1; i < 256; i++)
|
||||||
|
{
|
||||||
pow[i] = x;
|
pow[i] = x;
|
||||||
log[x] = i;
|
log[x] = i;
|
||||||
x = (x ^ XTIME(x)) & 0xFF;
|
x = (x ^ XTIME(x)) & 0xFF;
|
||||||
}
|
}
|
||||||
// compute the round constants
|
// compute the round constants
|
||||||
for (i = 0, x = 1; i < 10; i++) {
|
for (i = 0, x = 1; i < 10; i++)
|
||||||
|
{
|
||||||
RCON[i] = (uint32_t)x;
|
RCON[i] = (uint32_t)x;
|
||||||
x = XTIME(x) & 0xFF;
|
x = XTIME(x) & 0xFF;
|
||||||
}
|
}
|
||||||
@ -166,7 +179,8 @@ void aes_init_keygen_tables(void)
|
|||||||
RSb[0x63] = 0x00;
|
RSb[0x63] = 0x00;
|
||||||
#endif /* AES_DECRYPTION */
|
#endif /* AES_DECRYPTION */
|
||||||
|
|
||||||
for (i = 1; i < 256; i++) {
|
for (i = 1; i < 256; i++)
|
||||||
|
{
|
||||||
x = y = pow[255 - log[i]];
|
x = y = pow[255 - log[i]];
|
||||||
MIX(x, y);
|
MIX(x, y);
|
||||||
MIX(x, y);
|
MIX(x, y);
|
||||||
@ -176,10 +190,10 @@ void aes_init_keygen_tables(void)
|
|||||||
#if AES_DECRYPTION // whether AES decryption is supported
|
#if AES_DECRYPTION // whether AES decryption is supported
|
||||||
RSb[x] = (uchar)i;
|
RSb[x] = (uchar)i;
|
||||||
#endif /* AES_DECRYPTION */
|
#endif /* AES_DECRYPTION */
|
||||||
|
|
||||||
}
|
}
|
||||||
// generate the forward and reverse key expansion tables
|
// generate the forward and reverse key expansion tables
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
x = FSb[i];
|
x = FSb[i];
|
||||||
y = XTIME(x) & 0xFF;
|
y = XTIME(x) & 0xFF;
|
||||||
z = (y ^ x) & 0xFF;
|
z = (y ^ x) & 0xFF;
|
||||||
@ -224,14 +238,16 @@ int aes_set_encryption_key(aes_context *ctx,
|
|||||||
uint i; // general purpose iteration local
|
uint i; // general purpose iteration local
|
||||||
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
|
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
|
||||||
|
|
||||||
for (i = 0; i < (keysize >> 2); i++) {
|
for (i = 0; i < (keysize >> 2); i++)
|
||||||
|
{
|
||||||
GET_UINT32_LE(RK[i], key, i << 2);
|
GET_UINT32_LE(RK[i], key, i << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ctx->rounds)
|
switch (ctx->rounds)
|
||||||
{
|
{
|
||||||
case 10:
|
case 10:
|
||||||
for (i = 0; i < 10; i++, RK += 4) {
|
for (i = 0; i < 10; i++, RK += 4)
|
||||||
|
{
|
||||||
RK[4] = RK[0] ^ RCON[i] ^
|
RK[4] = RK[0] ^ RCON[i] ^
|
||||||
((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^
|
((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^
|
||||||
((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^
|
((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^
|
||||||
@ -245,7 +261,8 @@ int aes_set_encryption_key(aes_context *ctx,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 12:
|
case 12:
|
||||||
for (i = 0; i < 8; i++, RK += 6) {
|
for (i = 0; i < 8; i++, RK += 6)
|
||||||
|
{
|
||||||
RK[6] = RK[0] ^ RCON[i] ^
|
RK[6] = RK[0] ^ RCON[i] ^
|
||||||
((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^
|
((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^
|
||||||
((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^
|
((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^
|
||||||
@ -261,7 +278,8 @@ int aes_set_encryption_key(aes_context *ctx,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 14:
|
case 14:
|
||||||
for (i = 0; i < 7; i++, RK += 8) {
|
for (i = 0; i < 7; i++, RK += 8)
|
||||||
|
{
|
||||||
RK[8] = RK[0] ^ RCON[i] ^
|
RK[8] = RK[0] ^ RCON[i] ^
|
||||||
((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^
|
((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^
|
||||||
((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^
|
((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^
|
||||||
@ -322,8 +340,10 @@ int aes_set_decryption_key(aes_context *ctx,
|
|||||||
|
|
||||||
CPY128 // copy a 128-bit block from *SK to *RK
|
CPY128 // copy a 128-bit block from *SK to *RK
|
||||||
|
|
||||||
for (i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8) {
|
for (i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8)
|
||||||
for (j = 0; j < 4; j++, SK++) {
|
{
|
||||||
|
for (j = 0; j < 4; j++, SK++)
|
||||||
|
{
|
||||||
*RK++ = RT0[FSb[(*SK) & 0xFF]] ^
|
*RK++ = RT0[FSb[(*SK) & 0xFF]] ^
|
||||||
RT1[FSb[(*SK >> 8) & 0xFF]] ^
|
RT1[FSb[(*SK >> 8) & 0xFF]] ^
|
||||||
RT2[FSb[(*SK >> 16) & 0xFF]] ^
|
RT2[FSb[(*SK >> 16) & 0xFF]] ^
|
||||||
@ -353,17 +373,25 @@ int aes_setkey(aes_context *ctx, // AES context provided by our caller
|
|||||||
// system-specific mutexes and init the AES key generation tables on
|
// system-specific mutexes and init the AES key generation tables on
|
||||||
// demand, or ask the developer to simply call "gcm_initialize" once during
|
// demand, or ask the developer to simply call "gcm_initialize" once during
|
||||||
// application startup before threading begins. That's what we choose.
|
// application startup before threading begins. That's what we choose.
|
||||||
if (!aes_tables_inited) return (-1); // fail the call when not inited.
|
if (!aes_tables_inited)
|
||||||
|
return (-1); // fail the call when not inited.
|
||||||
|
|
||||||
ctx->mode = mode; // capture the key type we're creating
|
ctx->mode = mode; // capture the key type we're creating
|
||||||
ctx->rk = ctx->buf; // initialize our round key pointer
|
ctx->rk = ctx->buf; // initialize our round key pointer
|
||||||
|
|
||||||
switch (keysize) // set the rounds count based upon the keysize
|
switch (keysize) // set the rounds count based upon the keysize
|
||||||
{
|
{
|
||||||
case 16: ctx->rounds = 10; break; // 16-byte, 128-bit key
|
case 16:
|
||||||
case 24: ctx->rounds = 12; break; // 24-byte, 192-bit key
|
ctx->rounds = 10;
|
||||||
case 32: ctx->rounds = 14; break; // 32-byte, 256-bit key
|
break; // 16-byte, 128-bit key
|
||||||
default: return(-1);
|
case 24:
|
||||||
|
ctx->rounds = 12;
|
||||||
|
break; // 24-byte, 192-bit key
|
||||||
|
case 32:
|
||||||
|
ctx->rounds = 14;
|
||||||
|
break; // 32-byte, 256-bit key
|
||||||
|
default:
|
||||||
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if AES_DECRYPTION
|
#if AES_DECRYPTION
|
||||||
@ -392,10 +420,14 @@ int aes_cipher(aes_context *ctx,
|
|||||||
|
|
||||||
RK = ctx->rk;
|
RK = ctx->rk;
|
||||||
|
|
||||||
GET_UINT32_LE(X0, input, 0); X0 ^= *RK++; // load our 128-bit
|
GET_UINT32_LE(X0, input, 0);
|
||||||
GET_UINT32_LE(X1, input, 4); X1 ^= *RK++; // input buffer in a storage
|
X0 ^= *RK++; // load our 128-bit
|
||||||
GET_UINT32_LE(X2, input, 8); X2 ^= *RK++; // memory endian-neutral way
|
GET_UINT32_LE(X1, input, 4);
|
||||||
GET_UINT32_LE(X3, input, 12); X3 ^= *RK++;
|
X1 ^= *RK++; // input buffer in a storage
|
||||||
|
GET_UINT32_LE(X2, input, 8);
|
||||||
|
X2 ^= *RK++; // memory endian-neutral way
|
||||||
|
GET_UINT32_LE(X3, input, 12);
|
||||||
|
X3 ^= *RK++;
|
||||||
|
|
||||||
#if AES_DECRYPTION // whether AES decryption is supported
|
#if AES_DECRYPTION // whether AES decryption is supported
|
||||||
|
|
||||||
@ -409,25 +441,25 @@ int aes_cipher(aes_context *ctx,
|
|||||||
|
|
||||||
AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
|
AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
|
||||||
|
|
||||||
X0 = *RK++ ^ \
|
X0 = *RK++ ^
|
||||||
((uint32_t)RSb[(Y0) & 0xFF]) ^
|
((uint32_t)RSb[(Y0) & 0xFF]) ^
|
||||||
((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^
|
((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^
|
||||||
((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^
|
((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^
|
||||||
((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24);
|
((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24);
|
||||||
|
|
||||||
X1 = *RK++ ^ \
|
X1 = *RK++ ^
|
||||||
((uint32_t)RSb[(Y1) & 0xFF]) ^
|
((uint32_t)RSb[(Y1) & 0xFF]) ^
|
||||||
((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^
|
((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^
|
||||||
((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^
|
((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^
|
||||||
((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24);
|
((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24);
|
||||||
|
|
||||||
X2 = *RK++ ^ \
|
X2 = *RK++ ^
|
||||||
((uint32_t)RSb[(Y2) & 0xFF]) ^
|
((uint32_t)RSb[(Y2) & 0xFF]) ^
|
||||||
((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^
|
((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^
|
||||||
((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^
|
((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^
|
||||||
((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24);
|
((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24);
|
||||||
|
|
||||||
X3 = *RK++ ^ \
|
X3 = *RK++ ^
|
||||||
((uint32_t)RSb[(Y3) & 0xFF]) ^
|
((uint32_t)RSb[(Y3) & 0xFF]) ^
|
||||||
((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^
|
((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^
|
||||||
((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^
|
((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^
|
||||||
@ -445,25 +477,25 @@ int aes_cipher(aes_context *ctx,
|
|||||||
|
|
||||||
AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
|
AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
|
||||||
|
|
||||||
X0 = *RK++ ^ \
|
X0 = *RK++ ^
|
||||||
((uint32_t)FSb[(Y0) & 0xFF]) ^
|
((uint32_t)FSb[(Y0) & 0xFF]) ^
|
||||||
((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^
|
((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^
|
||||||
((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^
|
((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^
|
||||||
((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24);
|
((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24);
|
||||||
|
|
||||||
X1 = *RK++ ^ \
|
X1 = *RK++ ^
|
||||||
((uint32_t)FSb[(Y1) & 0xFF]) ^
|
((uint32_t)FSb[(Y1) & 0xFF]) ^
|
||||||
((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^
|
((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^
|
||||||
((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^
|
((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^
|
||||||
((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24);
|
((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24);
|
||||||
|
|
||||||
X2 = *RK++ ^ \
|
X2 = *RK++ ^
|
||||||
((uint32_t)FSb[(Y2) & 0xFF]) ^
|
((uint32_t)FSb[(Y2) & 0xFF]) ^
|
||||||
((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^
|
((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^
|
||||||
((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^
|
((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^
|
||||||
((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24);
|
((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24);
|
||||||
|
|
||||||
X3 = *RK++ ^ \
|
X3 = *RK++ ^
|
||||||
((uint32_t)FSb[(Y3) & 0xFF]) ^
|
((uint32_t)FSb[(Y3) & 0xFF]) ^
|
||||||
((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^
|
((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^
|
||||||
((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^
|
((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^
|
||||||
|
@ -41,24 +41,22 @@ typedef UINT32 uint32_t;
|
|||||||
typedef unsigned char uchar; // add some convienent shorter types
|
typedef unsigned char uchar; // add some convienent shorter types
|
||||||
typedef unsigned int uint;
|
typedef unsigned int uint;
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
|
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void aes_init_keygen_tables(void);
|
void aes_init_keygen_tables(void);
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* AES_CONTEXT : cipher context / holds inter-call data
|
* AES_CONTEXT : cipher context / holds inter-call data
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int mode; // 1 for Encryption, 0 for Decryption
|
int mode; // 1 for Encryption, 0 for Decryption
|
||||||
int rounds; // keysize-based rounds count
|
int rounds; // keysize-based rounds count
|
||||||
uint32_t *rk; // pointer to current round key
|
uint32_t *rk; // pointer to current round key
|
||||||
uint32_t buf[68]; // key expansion buffer
|
uint32_t buf[68]; // key expansion buffer
|
||||||
} aes_context;
|
} aes_context;
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* AES_SETKEY : called to expand the key for encryption or decryption
|
* AES_SETKEY : called to expand the key for encryption or decryption
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@ -83,18 +83,18 @@ static const uint64_t last4[16] = {
|
|||||||
* Platform Endianness Neutralizing Load and Store Macro definitions
|
* Platform Endianness Neutralizing Load and Store Macro definitions
|
||||||
* GCM wants platform-neutral Big Endian (BE) byte ordering
|
* GCM wants platform-neutral Big Endian (BE) byte ordering
|
||||||
*/
|
*/
|
||||||
#define GET_UINT32_BE(n,b,i) { \
|
#define GET_UINT32_BE(n, b, i) \
|
||||||
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
|
{ \
|
||||||
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
|
(n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); \
|
||||||
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
|
}
|
||||||
| ( (uint32_t) (b)[(i) + 3] ); }
|
|
||||||
|
|
||||||
#define PUT_UINT32_BE(n,b,i) { \
|
#define PUT_UINT32_BE(n, b, i) \
|
||||||
|
{ \
|
||||||
(b)[(i)] = (uchar)((n) >> 24); \
|
(b)[(i)] = (uchar)((n) >> 24); \
|
||||||
(b)[(i) + 1] = (uchar)((n) >> 16); \
|
(b)[(i) + 1] = (uchar)((n) >> 16); \
|
||||||
(b)[(i) + 2] = (uchar)((n) >> 8); \
|
(b)[(i) + 2] = (uchar)((n) >> 8); \
|
||||||
(b)[(i) + 3] = (uchar) ( (n) ); }
|
(b)[(i) + 3] = (uchar)((n)); \
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
@ -114,7 +114,6 @@ int gcm_initialize(void)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_MULT
|
* GCM_MULT
|
||||||
@ -137,11 +136,13 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
|
|||||||
zh = ctx->HH[lo];
|
zh = ctx->HH[lo];
|
||||||
zl = ctx->HL[lo];
|
zl = ctx->HL[lo];
|
||||||
|
|
||||||
for (i = 15; i >= 0; i--) {
|
for (i = 15; i >= 0; i--)
|
||||||
|
{
|
||||||
lo = (uchar)(x[i] & 0x0f);
|
lo = (uchar)(x[i] & 0x0f);
|
||||||
hi = (uchar)(x[i] >> 4);
|
hi = (uchar)(x[i] >> 4);
|
||||||
|
|
||||||
if (i != 15) {
|
if (i != 15)
|
||||||
|
{
|
||||||
rem = (uchar)(zl & 0x0f);
|
rem = (uchar)(zl & 0x0f);
|
||||||
zl = (zh << 60) | (zl >> 4);
|
zl = (zh << 60) | (zl >> 4);
|
||||||
zh = (zh >> 4);
|
zh = (zh >> 4);
|
||||||
@ -162,7 +163,6 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
|
|||||||
PUT_UINT32_BE(zl, output, 12);
|
PUT_UINT32_BE(zl, output, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_SETKEY
|
* GCM_SETKEY
|
||||||
@ -204,18 +204,21 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
|
|||||||
ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128)
|
ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128)
|
||||||
ctx->HL[0] = 0;
|
ctx->HL[0] = 0;
|
||||||
|
|
||||||
for (i = 4; i > 0; i >>= 1) {
|
for (i = 4; i > 0; i >>= 1)
|
||||||
|
{
|
||||||
uint32_t T = (uint32_t)(vl & 1) * 0xe1000000U;
|
uint32_t T = (uint32_t)(vl & 1) * 0xe1000000U;
|
||||||
vl = (vh << 63) | (vl >> 1);
|
vl = (vh << 63) | (vl >> 1);
|
||||||
vh = (vh >> 1) ^ ((uint64_t)T << 32);
|
vh = (vh >> 1) ^ ((uint64_t)T << 32);
|
||||||
ctx->HL[i] = vl;
|
ctx->HL[i] = vl;
|
||||||
ctx->HH[i] = vh;
|
ctx->HH[i] = vh;
|
||||||
}
|
}
|
||||||
for (i = 2; i < 16; i <<= 1) {
|
for (i = 2; i < 16; i <<= 1)
|
||||||
|
{
|
||||||
uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i;
|
uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i;
|
||||||
vh = *HiH;
|
vh = *HiH;
|
||||||
vl = *HiL;
|
vl = *HiL;
|
||||||
for (j = 1; j < i; j++) {
|
for (j = 1; j < i; j++)
|
||||||
|
{
|
||||||
HiH[j] = vh ^ ctx->HH[j];
|
HiH[j] = vh ^ ctx->HH[j];
|
||||||
HiL[j] = vl ^ ctx->HL[j];
|
HiL[j] = vl ^ ctx->HL[j];
|
||||||
}
|
}
|
||||||
@ -223,7 +226,6 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH.
|
* GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH.
|
||||||
@ -268,7 +270,8 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
ctx->mode = mode; // set the GCM encryption/decryption mode
|
ctx->mode = mode; // set the GCM encryption/decryption mode
|
||||||
ctx->aes_ctx.mode = AES_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode
|
ctx->aes_ctx.mode = AES_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode
|
||||||
|
|
||||||
if (iv_len == 12) { // GCM natively uses a 12-byte, 96-bit IV
|
if (iv_len == 12)
|
||||||
|
{ // GCM natively uses a 12-byte, 96-bit IV
|
||||||
memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff
|
memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff
|
||||||
ctx->y[15] = 1; // start "counting" from 1 (not 0)
|
ctx->y[15] = 1; // start "counting" from 1 (not 0)
|
||||||
}
|
}
|
||||||
@ -278,14 +281,17 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer
|
PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer
|
||||||
|
|
||||||
p = iv;
|
p = iv;
|
||||||
while (iv_len > 0) {
|
while (iv_len > 0)
|
||||||
|
{
|
||||||
use_len = (iv_len < 16) ? iv_len : 16;
|
use_len = (iv_len < 16) ? iv_len : 16;
|
||||||
for (i = 0; i < use_len; i++) ctx->y[i] ^= p[i];
|
for (i = 0; i < use_len; i++)
|
||||||
|
ctx->y[i] ^= p[i];
|
||||||
gcm_mult(ctx, ctx->y, ctx->y);
|
gcm_mult(ctx, ctx->y, ctx->y);
|
||||||
iv_len -= use_len;
|
iv_len -= use_len;
|
||||||
p += use_len;
|
p += use_len;
|
||||||
}
|
}
|
||||||
for (i = 0; i < 16; i++) ctx->y[i] ^= work_buf[i];
|
for (i = 0; i < 16; i++)
|
||||||
|
ctx->y[i] ^= work_buf[i];
|
||||||
gcm_mult(ctx, ctx->y, ctx->y);
|
gcm_mult(ctx, ctx->y, ctx->y);
|
||||||
}
|
}
|
||||||
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0)
|
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0)
|
||||||
@ -293,9 +299,11 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
|
|
||||||
ctx->add_len = add_len;
|
ctx->add_len = add_len;
|
||||||
p = add;
|
p = add;
|
||||||
while (add_len > 0) {
|
while (add_len > 0)
|
||||||
|
{
|
||||||
use_len = (add_len < 16) ? add_len : 16;
|
use_len = (add_len < 16) ? add_len : 16;
|
||||||
for (i = 0; i < use_len; i++) ctx->buf[i] ^= p[i];
|
for (i = 0; i < use_len; i++)
|
||||||
|
ctx->buf[i] ^= p[i];
|
||||||
gcm_mult(ctx, ctx->buf, ctx->buf);
|
gcm_mult(ctx, ctx->buf, ctx->buf);
|
||||||
add_len -= use_len;
|
add_len -= use_len;
|
||||||
p += use_len;
|
p += use_len;
|
||||||
@ -326,12 +334,15 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
|
|
||||||
ctx->len += length; // bump the GCM context's running length count
|
ctx->len += length; // bump the GCM context's running length count
|
||||||
|
|
||||||
while (length > 0) {
|
while (length > 0)
|
||||||
|
{
|
||||||
// clamp the length to process at 16 bytes
|
// clamp the length to process at 16 bytes
|
||||||
use_len = (length < 16) ? length : 16;
|
use_len = (length < 16) ? length : 16;
|
||||||
|
|
||||||
// increment the context's 128-bit IV||Counter 'y' vector
|
// increment the context's 128-bit IV||Counter 'y' vector
|
||||||
for (i = 16; i > 12; i--) if (++ctx->y[i - 1] != 0) break;
|
for (i = 16; i > 12; i--)
|
||||||
|
if (++ctx->y[i - 1] != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
// encrypt the context's 'y' vector under the established key
|
// encrypt the context's 'y' vector under the established key
|
||||||
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ectr)) != 0)
|
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ectr)) != 0)
|
||||||
@ -340,7 +351,8 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
// encrypt or decrypt the input to the output
|
// encrypt or decrypt the input to the output
|
||||||
if (ctx->mode == AES_ENCRYPT)
|
if (ctx->mode == AES_ENCRYPT)
|
||||||
{
|
{
|
||||||
for (i = 0; i < use_len; i++) {
|
for (i = 0; i < use_len; i++)
|
||||||
|
{
|
||||||
// XOR the cipher's ouptut vector (ectr) with our input
|
// XOR the cipher's ouptut vector (ectr) with our input
|
||||||
output[i] = (uchar)(ectr[i] ^ input[i]);
|
output[i] = (uchar)(ectr[i] ^ input[i]);
|
||||||
// now we mix in our data into the authentication hash.
|
// now we mix in our data into the authentication hash.
|
||||||
@ -352,7 +364,8 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (i = 0; i < use_len; i++) {
|
for (i = 0; i < use_len; i++)
|
||||||
|
{
|
||||||
// but if we're DEcrypting we XOR in the input data first,
|
// but if we're DEcrypting we XOR in the input data first,
|
||||||
// i.e. before saving to ouput data, otherwise if the input
|
// i.e. before saving to ouput data, otherwise if the input
|
||||||
// and output buffer are the same (inplace decryption) we
|
// and output buffer are the same (inplace decryption) we
|
||||||
@ -390,9 +403,11 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
uint64_t orig_add_len = ctx->add_len * 8;
|
uint64_t orig_add_len = ctx->add_len * 8;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (tag_len != 0) memcpy(tag, ctx->base_ectr, tag_len);
|
if (tag_len != 0)
|
||||||
|
memcpy(tag, ctx->base_ectr, tag_len);
|
||||||
|
|
||||||
if (orig_len || orig_add_len) {
|
if (orig_len || orig_add_len)
|
||||||
|
{
|
||||||
memset(work_buf, 0x00, 16);
|
memset(work_buf, 0x00, 16);
|
||||||
|
|
||||||
PUT_UINT32_BE((orig_add_len >> 32), work_buf, 0);
|
PUT_UINT32_BE((orig_add_len >> 32), work_buf, 0);
|
||||||
@ -400,14 +415,15 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
PUT_UINT32_BE((orig_len >> 32), work_buf, 8);
|
PUT_UINT32_BE((orig_len >> 32), work_buf, 8);
|
||||||
PUT_UINT32_BE((orig_len), work_buf, 12);
|
PUT_UINT32_BE((orig_len), work_buf, 12);
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) ctx->buf[i] ^= work_buf[i];
|
for (i = 0; i < 16; i++)
|
||||||
|
ctx->buf[i] ^= work_buf[i];
|
||||||
gcm_mult(ctx, ctx->buf, ctx->buf);
|
gcm_mult(ctx, ctx->buf, ctx->buf);
|
||||||
for (i = 0; i < tag_len; i++) tag[i] ^= ctx->buf[i];
|
for (i = 0; i < tag_len; i++)
|
||||||
|
tag[i] ^= ctx->buf[i];
|
||||||
}
|
}
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_CRYPT_AND_TAG
|
* GCM_CRYPT_AND_TAG
|
||||||
@ -448,7 +464,6 @@ int gcm_crypt_and_tag(
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_AUTH_DECRYPT
|
* GCM_AUTH_DECRYPT
|
||||||
@ -488,7 +503,8 @@ int gcm_auth_decrypt(
|
|||||||
for (diff = 0, i = 0; i < tag_len; i++)
|
for (diff = 0, i = 0; i < tag_len; i++)
|
||||||
diff |= tag[i] ^ check_tag[i];
|
diff |= tag[i] ^ check_tag[i];
|
||||||
|
|
||||||
if (diff != 0) { // see whether any bits differed?
|
if (diff != 0)
|
||||||
|
{ // see whether any bits differed?
|
||||||
memset(output, 0, length); // if so... wipe the output data
|
memset(output, 0, length); // if so... wipe the output data
|
||||||
return (GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
|
return (GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
|
||||||
}
|
}
|
||||||
|
@ -36,11 +36,11 @@ typedef UINT64 uint64_t;
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
|
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int mode; // cipher direction: encrypt/decrypt
|
int mode; // cipher direction: encrypt/decrypt
|
||||||
uint64_t len; // cipher data length processed so far
|
uint64_t len; // cipher data length processed so far
|
||||||
uint64_t add_len; // total add data length
|
uint64_t add_len; // total add data length
|
||||||
@ -52,13 +52,11 @@ typedef struct {
|
|||||||
aes_context aes_ctx; // cipher context used
|
aes_context aes_ctx; // cipher context used
|
||||||
} gcm_context;
|
} gcm_context;
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* GCM_CONTEXT : MUST be called once before ANY use of this library
|
* GCM_CONTEXT : MUST be called once before ANY use of this library
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
int gcm_initialize(void);
|
int gcm_initialize(void);
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* GCM_SETKEY : sets the GCM (and AES) keying material for use
|
* GCM_SETKEY : sets the GCM (and AES) keying material for use
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@ -68,7 +66,6 @@ int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
|
|||||||
// 128, 192 or 256-bit keys respectively)
|
// 128, 192 or 256-bit keys respectively)
|
||||||
); // returns 0 for success
|
); // returns 0 for success
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_CRYPT_AND_TAG
|
* GCM_CRYPT_AND_TAG
|
||||||
@ -99,7 +96,6 @@ int gcm_crypt_and_tag(
|
|||||||
uchar *tag, // pointer to the tag to be generated
|
uchar *tag, // pointer to the tag to be generated
|
||||||
size_t tag_len); // byte length of the tag to be generated
|
size_t tag_len); // byte length of the tag to be generated
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_AUTH_DECRYPT
|
* GCM_AUTH_DECRYPT
|
||||||
@ -124,7 +120,6 @@ int gcm_auth_decrypt(
|
|||||||
const uchar *tag, // pointer to the tag to be authenticated
|
const uchar *tag, // pointer to the tag to be authenticated
|
||||||
size_t tag_len); // byte length of the tag <= 16
|
size_t tag_len); // byte length of the tag <= 16
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_START
|
* GCM_START
|
||||||
@ -140,7 +135,6 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
const uchar *add, // pointer to additional AEAD data (NULL if none)
|
const uchar *add, // pointer to additional AEAD data (NULL if none)
|
||||||
size_t add_len); // length of additional AEAD data (bytes)
|
size_t add_len); // length of additional AEAD data (bytes)
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_UPDATE
|
* GCM_UPDATE
|
||||||
@ -157,7 +151,6 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
const uchar *input, // pointer to source data
|
const uchar *input, // pointer to source data
|
||||||
uchar *output); // pointer to destination data
|
uchar *output); // pointer to destination data
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_FINISH
|
* GCM_FINISH
|
||||||
@ -170,7 +163,6 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
|||||||
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
|
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
|
||||||
size_t tag_len); // length, in bytes, of the tag-receiving buf
|
size_t tag_len); // length, in bytes, of the tag-receiving buf
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* GCM_ZERO_CTX
|
* GCM_ZERO_CTX
|
||||||
|
@ -98,12 +98,14 @@ int hkdfExtract(SHAversion whichSha,
|
|||||||
uint8_t prk[USHAMaxHashSize])
|
uint8_t prk[USHAMaxHashSize])
|
||||||
{
|
{
|
||||||
unsigned char nullSalt[USHAMaxHashSize];
|
unsigned char nullSalt[USHAMaxHashSize];
|
||||||
if (salt == 0) {
|
if (salt == 0)
|
||||||
|
{
|
||||||
salt = nullSalt;
|
salt = nullSalt;
|
||||||
salt_len = USHAHashSize(whichSha);
|
salt_len = USHAHashSize(whichSha);
|
||||||
memset(nullSalt, '\0', salt_len);
|
memset(nullSalt, '\0', salt_len);
|
||||||
}
|
}
|
||||||
else if (salt_len < 0) {
|
else if (salt_len < 0)
|
||||||
|
{
|
||||||
return shaBadParam;
|
return shaBadParam;
|
||||||
}
|
}
|
||||||
return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
|
return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
|
||||||
@ -150,25 +152,33 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
|
|||||||
unsigned char T[USHAMaxHashSize];
|
unsigned char T[USHAMaxHashSize];
|
||||||
size_t Tlen, where, i;
|
size_t Tlen, where, i;
|
||||||
|
|
||||||
if (info == 0) {
|
if (info == 0)
|
||||||
|
{
|
||||||
info = (const unsigned char *)"";
|
info = (const unsigned char *)"";
|
||||||
info_len = 0;
|
info_len = 0;
|
||||||
}
|
}
|
||||||
else if (info_len < 0) {
|
else if (info_len < 0)
|
||||||
|
{
|
||||||
return shaBadParam;
|
return shaBadParam;
|
||||||
}
|
}
|
||||||
if (okm_len <= 0) return shaBadParam;
|
if (okm_len <= 0)
|
||||||
if (!okm) return shaBadParam;
|
return shaBadParam;
|
||||||
|
if (!okm)
|
||||||
|
return shaBadParam;
|
||||||
|
|
||||||
hash_len = USHAHashSize(whichSha);
|
hash_len = USHAHashSize(whichSha);
|
||||||
if (prk_len < hash_len) return shaBadParam;
|
if (prk_len < hash_len)
|
||||||
|
return shaBadParam;
|
||||||
N = okm_len / hash_len;
|
N = okm_len / hash_len;
|
||||||
if ((okm_len % hash_len) != 0) N++;
|
if ((okm_len % hash_len) != 0)
|
||||||
if (N > 255) return shaBadParam;
|
N++;
|
||||||
|
if (N > 255)
|
||||||
|
return shaBadParam;
|
||||||
|
|
||||||
Tlen = 0;
|
Tlen = 0;
|
||||||
where = 0;
|
where = 0;
|
||||||
for (i = 1; i <= N; i++) {
|
for (i = 1; i <= N; i++)
|
||||||
|
{
|
||||||
HMACContext context;
|
HMACContext context;
|
||||||
unsigned char c = i;
|
unsigned char c = i;
|
||||||
int ret = hmacReset(&context, whichSha, prk, prk_len) ||
|
int ret = hmacReset(&context, whichSha, prk, prk_len) ||
|
||||||
@ -176,7 +186,8 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
|
|||||||
hmacInput(&context, info, info_len) ||
|
hmacInput(&context, info, info_len) ||
|
||||||
hmacInput(&context, &c, 1) ||
|
hmacInput(&context, &c, 1) ||
|
||||||
hmacResult(&context, T);
|
hmacResult(&context, T);
|
||||||
if (ret != shaSuccess) return ret;
|
if (ret != shaSuccess)
|
||||||
|
return ret;
|
||||||
memcpy(okm + where, T,
|
memcpy(okm + where, T,
|
||||||
(i != N) ? hash_len : (okm_len - where));
|
(i != N) ? hash_len : (okm_len - where));
|
||||||
where += hash_len;
|
where += hash_len;
|
||||||
@ -213,11 +224,13 @@ int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
|
|||||||
const unsigned char *salt, size_t salt_len)
|
const unsigned char *salt, size_t salt_len)
|
||||||
{
|
{
|
||||||
unsigned char nullSalt[USHAMaxHashSize];
|
unsigned char nullSalt[USHAMaxHashSize];
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
|
return shaNull;
|
||||||
|
|
||||||
context->whichSha = whichSha;
|
context->whichSha = whichSha;
|
||||||
context->hashSize = USHAHashSize(whichSha);
|
context->hashSize = USHAHashSize(whichSha);
|
||||||
if (salt == 0) {
|
if (salt == 0)
|
||||||
|
{
|
||||||
salt = nullSalt;
|
salt = nullSalt;
|
||||||
salt_len = context->hashSize;
|
salt_len = context->hashSize;
|
||||||
memset(nullSalt, '\0', salt_len);
|
memset(nullSalt, '\0', salt_len);
|
||||||
@ -249,9 +262,12 @@ int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
|
|||||||
int hkdfInput(HKDFContext *context, const unsigned char *ikm,
|
int hkdfInput(HKDFContext *context, const unsigned char *ikm,
|
||||||
size_t ikm_len)
|
size_t ikm_len)
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
if (context->Corrupted) return context->Corrupted;
|
return shaNull;
|
||||||
if (context->Computed) return context->Corrupted = shaStateError;
|
if (context->Corrupted)
|
||||||
|
return context->Corrupted;
|
||||||
|
if (context->Computed)
|
||||||
|
return context->Corrupted = shaStateError;
|
||||||
return hmacInput(&context->hmacContext, ikm, ikm_len);
|
return hmacInput(&context->hmacContext, ikm, ikm_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,9 +294,12 @@ int hkdfInput(HKDFContext *context, const unsigned char *ikm,
|
|||||||
int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
|
int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
|
||||||
unsigned int ikm_bit_count)
|
unsigned int ikm_bit_count)
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
if (context->Corrupted) return context->Corrupted;
|
return shaNull;
|
||||||
if (context->Computed) return context->Corrupted = shaStateError;
|
if (context->Corrupted)
|
||||||
|
return context->Corrupted;
|
||||||
|
if (context->Computed)
|
||||||
|
return context->Corrupted = shaStateError;
|
||||||
return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count);
|
return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,11 +341,16 @@ int hkdfResult(HKDFContext *context,
|
|||||||
uint8_t prkbuf[USHAMaxHashSize];
|
uint8_t prkbuf[USHAMaxHashSize];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
if (context->Corrupted) return context->Corrupted;
|
return shaNull;
|
||||||
if (context->Computed) return context->Corrupted = shaStateError;
|
if (context->Corrupted)
|
||||||
if (!okm) return context->Corrupted = shaBadParam;
|
return context->Corrupted;
|
||||||
if (!prk) prk = prkbuf;
|
if (context->Computed)
|
||||||
|
return context->Corrupted = shaStateError;
|
||||||
|
if (!okm)
|
||||||
|
return context->Corrupted = shaBadParam;
|
||||||
|
if (!prk)
|
||||||
|
prk = prkbuf;
|
||||||
|
|
||||||
ret = hmacResult(&context->hmacContext, prk) ||
|
ret = hmacResult(&context->hmacContext, prk) ||
|
||||||
hkdfExpand(context->whichSha, prk, context->hashSize, info,
|
hkdfExpand(context->whichSha, prk, context->hashSize, info,
|
||||||
@ -334,4 +358,3 @@ int hkdfResult(HKDFContext *context,
|
|||||||
context->Computed = 1;
|
context->Computed = 1;
|
||||||
return context->Corrupted = ret;
|
return context->Corrupted = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
|
|||||||
/* temporary buffer when keylen > blocksize */
|
/* temporary buffer when keylen > blocksize */
|
||||||
unsigned char tempkey[USHAMaxHashSize];
|
unsigned char tempkey[USHAMaxHashSize];
|
||||||
|
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
|
return shaNull;
|
||||||
context->Computed = 0;
|
context->Computed = 0;
|
||||||
context->Corrupted = shaSuccess;
|
context->Corrupted = shaSuccess;
|
||||||
|
|
||||||
@ -99,12 +100,14 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
|
|||||||
* If key is longer than the hash blocksize,
|
* If key is longer than the hash blocksize,
|
||||||
* reset it to key = HASH(key).
|
* reset it to key = HASH(key).
|
||||||
*/
|
*/
|
||||||
if (key_len > blocksize) {
|
if (key_len > blocksize)
|
||||||
|
{
|
||||||
USHAContext tcontext;
|
USHAContext tcontext;
|
||||||
int err = USHAReset(&tcontext, whichSha) ||
|
int err = USHAReset(&tcontext, whichSha) ||
|
||||||
USHAInput(&tcontext, key, key_len) ||
|
USHAInput(&tcontext, key, key_len) ||
|
||||||
USHAResult(&tcontext, tempkey);
|
USHAResult(&tcontext, tempkey);
|
||||||
if (err != shaSuccess) return err;
|
if (err != shaSuccess)
|
||||||
|
return err;
|
||||||
|
|
||||||
key = tempkey;
|
key = tempkey;
|
||||||
key_len = hashsize;
|
key_len = hashsize;
|
||||||
@ -122,12 +125,14 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* store key into the pads, XOR'd with ipad and opad values */
|
/* store key into the pads, XOR'd with ipad and opad values */
|
||||||
for (i = 0; i < key_len; i++) {
|
for (i = 0; i < key_len; i++)
|
||||||
|
{
|
||||||
k_ipad[i] = key[i] ^ 0x36;
|
k_ipad[i] = key[i] ^ 0x36;
|
||||||
context->k_opad[i] = key[i] ^ 0x5c;
|
context->k_opad[i] = key[i] ^ 0x5c;
|
||||||
}
|
}
|
||||||
/* remaining pad bytes are '\0' XOR'd with ipad and opad values */
|
/* remaining pad bytes are '\0' XOR'd with ipad and opad values */
|
||||||
for (; i < blocksize; i++) {
|
for (; i < blocksize; i++)
|
||||||
|
{
|
||||||
k_ipad[i] = 0x36;
|
k_ipad[i] = 0x36;
|
||||||
context->k_opad[i] = 0x5c;
|
context->k_opad[i] = 0x5c;
|
||||||
}
|
}
|
||||||
@ -163,9 +168,12 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
|
|||||||
int hmacInput(HMACContext *context, const unsigned char *text,
|
int hmacInput(HMACContext *context, const unsigned char *text,
|
||||||
size_t text_len)
|
size_t text_len)
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
if (context->Corrupted) return context->Corrupted;
|
return shaNull;
|
||||||
if (context->Computed) return context->Corrupted = shaStateError;
|
if (context->Corrupted)
|
||||||
|
return context->Corrupted;
|
||||||
|
if (context->Computed)
|
||||||
|
return context->Corrupted = shaStateError;
|
||||||
/* then text of datagram */
|
/* then text of datagram */
|
||||||
return context->Corrupted =
|
return context->Corrupted =
|
||||||
USHAInput(&context->shaContext, text, text_len);
|
USHAInput(&context->shaContext, text, text_len);
|
||||||
@ -193,9 +201,12 @@ int hmacInput(HMACContext *context, const unsigned char *text,
|
|||||||
int hmacFinalBits(HMACContext *context,
|
int hmacFinalBits(HMACContext *context,
|
||||||
uint8_t bits, unsigned int bit_count)
|
uint8_t bits, unsigned int bit_count)
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
if (context->Corrupted) return context->Corrupted;
|
return shaNull;
|
||||||
if (context->Computed) return context->Corrupted = shaStateError;
|
if (context->Corrupted)
|
||||||
|
return context->Corrupted;
|
||||||
|
if (context->Computed)
|
||||||
|
return context->Corrupted = shaStateError;
|
||||||
/* then final bits of datagram */
|
/* then final bits of datagram */
|
||||||
return context->Corrupted =
|
return context->Corrupted =
|
||||||
USHAFinalBits(&context->shaContext, bits, bit_count);
|
USHAFinalBits(&context->shaContext, bits, bit_count);
|
||||||
@ -223,9 +234,12 @@ int hmacFinalBits(HMACContext *context,
|
|||||||
int hmacResult(HMACContext *context, uint8_t *digest)
|
int hmacResult(HMACContext *context, uint8_t *digest)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
if (context->Corrupted) return context->Corrupted;
|
return shaNull;
|
||||||
if (context->Computed) return context->Corrupted = shaStateError;
|
if (context->Corrupted)
|
||||||
|
return context->Corrupted;
|
||||||
|
if (context->Computed)
|
||||||
|
return context->Corrupted = shaStateError;
|
||||||
|
|
||||||
/* finish up 1st pass */
|
/* finish up 1st pass */
|
||||||
/* (Use digest here as a temporary buffer.) */
|
/* (Use digest here as a temporary buffer.) */
|
||||||
|
@ -85,7 +85,8 @@
|
|||||||
/*
|
/*
|
||||||
* All SHA functions return one of these values.
|
* All SHA functions return one of these values.
|
||||||
*/
|
*/
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
shaSuccess = 0,
|
shaSuccess = 0,
|
||||||
shaNull, /* Null pointer parameter */
|
shaNull, /* Null pointer parameter */
|
||||||
shaInputTooLong, /* input data too long */
|
shaInputTooLong, /* input data too long */
|
||||||
@ -98,30 +99,39 @@ enum {
|
|||||||
* These constants hold size information for each of the SHA
|
* These constants hold size information for each of the SHA
|
||||||
* hashing operations
|
* hashing operations
|
||||||
*/
|
*/
|
||||||
enum {
|
enum
|
||||||
SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64,
|
{
|
||||||
|
SHA1_Message_Block_Size = 64,
|
||||||
|
SHA224_Message_Block_Size = 64,
|
||||||
SHA256_Message_Block_Size = 64,
|
SHA256_Message_Block_Size = 64,
|
||||||
USHA_Max_Message_Block_Size = SHA256_Message_Block_Size,
|
USHA_Max_Message_Block_Size = SHA256_Message_Block_Size,
|
||||||
|
|
||||||
SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32,
|
SHA1HashSize = 20,
|
||||||
|
SHA224HashSize = 28,
|
||||||
|
SHA256HashSize = 32,
|
||||||
USHAMaxHashSize = SHA256HashSize,
|
USHAMaxHashSize = SHA256HashSize,
|
||||||
|
|
||||||
SHA1HashSizeBits = 160, SHA224HashSizeBits = 224,
|
SHA1HashSizeBits = 160,
|
||||||
SHA256HashSizeBits = 256, USHAMaxHashSizeBits = SHA256HashSizeBits
|
SHA224HashSizeBits = 224,
|
||||||
|
SHA256HashSizeBits = 256,
|
||||||
|
USHAMaxHashSizeBits = SHA256HashSizeBits
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These constants are used in the USHA (Unified SHA) functions.
|
* These constants are used in the USHA (Unified SHA) functions.
|
||||||
*/
|
*/
|
||||||
typedef enum SHAversion {
|
typedef enum SHAversion
|
||||||
SHA224, SHA256
|
{
|
||||||
|
SHA224,
|
||||||
|
SHA256
|
||||||
} SHAversion;
|
} SHAversion;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This structure will hold context information for the SHA-256
|
* This structure will hold context information for the SHA-256
|
||||||
* hashing operation.
|
* hashing operation.
|
||||||
*/
|
*/
|
||||||
typedef struct SHA256Context {
|
typedef struct SHA256Context
|
||||||
|
{
|
||||||
uint32_t Intermediate_Hash[SHA256HashSize / 4]; /* Message Digest */
|
uint32_t Intermediate_Hash[SHA256HashSize / 4]; /* Message Digest */
|
||||||
|
|
||||||
uint32_t Length_High; /* Message length in bits */
|
uint32_t Length_High; /* Message length in bits */
|
||||||
@ -145,10 +155,13 @@ typedef struct SHA256Context SHA224Context;
|
|||||||
* This structure holds context information for all SHA
|
* This structure holds context information for all SHA
|
||||||
* hashing operations.
|
* hashing operations.
|
||||||
*/
|
*/
|
||||||
typedef struct USHAContext {
|
typedef struct USHAContext
|
||||||
|
{
|
||||||
int whichSha; /* which SHA is being used */
|
int whichSha; /* which SHA is being used */
|
||||||
union {
|
union
|
||||||
SHA224Context sha224Context; SHA256Context sha256Context;
|
{
|
||||||
|
SHA224Context sha224Context;
|
||||||
|
SHA256Context sha256Context;
|
||||||
} ctx;
|
} ctx;
|
||||||
|
|
||||||
} USHAContext;
|
} USHAContext;
|
||||||
@ -157,7 +170,8 @@ typedef struct USHAContext {
|
|||||||
* This structure will hold context information for the HMAC
|
* This structure will hold context information for the HMAC
|
||||||
* keyed-hashing operation.
|
* keyed-hashing operation.
|
||||||
*/
|
*/
|
||||||
typedef struct HMACContext {
|
typedef struct HMACContext
|
||||||
|
{
|
||||||
int whichSha; /* which SHA is being used */
|
int whichSha; /* which SHA is being used */
|
||||||
int hashSize; /* hash size of SHA being used */
|
int hashSize; /* hash size of SHA being used */
|
||||||
int blockSize; /* block size of SHA being used */
|
int blockSize; /* block size of SHA being used */
|
||||||
@ -173,7 +187,8 @@ typedef struct HMACContext {
|
|||||||
* This structure will hold context information for the HKDF
|
* This structure will hold context information for the HKDF
|
||||||
* extract-and-expand Key Derivation Functions.
|
* extract-and-expand Key Derivation Functions.
|
||||||
*/
|
*/
|
||||||
typedef struct HKDFContext {
|
typedef struct HKDFContext
|
||||||
|
{
|
||||||
int whichSha; /* which SHA is being used */
|
int whichSha; /* which SHA is being used */
|
||||||
HMACContext hmacContext;
|
HMACContext hmacContext;
|
||||||
int hashSize; /* hash size of SHA being used */
|
int hashSize; /* hash size of SHA being used */
|
||||||
@ -187,7 +202,6 @@ typedef struct HKDFContext {
|
|||||||
* Function Prototypes
|
* Function Prototypes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* SHA-224 */
|
/* SHA-224 */
|
||||||
int SHA224Reset(SHA224Context *);
|
int SHA224Reset(SHA224Context *);
|
||||||
int SHA224Input(SHA224Context *, const uint8_t *bytes,
|
int SHA224Input(SHA224Context *, const uint8_t *bytes,
|
||||||
@ -243,7 +257,6 @@ int hmacFinalBits(HMACContext *context, uint8_t bits,
|
|||||||
int hmacResult(HMACContext *context,
|
int hmacResult(HMACContext *context,
|
||||||
uint8_t digest[USHAMaxHashSize]);
|
uint8_t digest[USHAMaxHashSize]);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
|
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
|
||||||
* RFC 5869, for all SHAs.
|
* RFC 5869, for all SHAs.
|
||||||
|
@ -68,8 +68,9 @@ static uint32_t addTemp;
|
|||||||
#define SHA224_256AddLength(context, length) \
|
#define SHA224_256AddLength(context, length) \
|
||||||
(addTemp = (context)->Length_Low, (context)->Corrupted = \
|
(addTemp = (context)->Length_Low, (context)->Corrupted = \
|
||||||
(((context)->Length_Low += (length)) < addTemp) && \
|
(((context)->Length_Low += (length)) < addTemp) && \
|
||||||
(++(context)->Length_High == 0) ? shaInputTooLong : \
|
(++(context)->Length_High == 0) \
|
||||||
(context)->Corrupted )
|
? shaInputTooLong \
|
||||||
|
: (context)->Corrupted)
|
||||||
|
|
||||||
/* Local Function Prototypes */
|
/* Local Function Prototypes */
|
||||||
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0);
|
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0);
|
||||||
@ -84,14 +85,12 @@ static int SHA224_256ResultN(SHA256Context *context,
|
|||||||
/* Initial Hash Values: FIPS 180-3 section 5.3.2 */
|
/* Initial Hash Values: FIPS 180-3 section 5.3.2 */
|
||||||
static uint32_t SHA224_H0[SHA256HashSize / 4] = {
|
static uint32_t SHA224_H0[SHA256HashSize / 4] = {
|
||||||
0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939,
|
0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939,
|
||||||
0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4
|
0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4};
|
||||||
};
|
|
||||||
|
|
||||||
/* Initial Hash Values: FIPS 180-3 section 5.3.3 */
|
/* Initial Hash Values: FIPS 180-3 section 5.3.3 */
|
||||||
static uint32_t SHA256_H0[SHA256HashSize / 4] = {
|
static uint32_t SHA256_H0[SHA256HashSize / 4] = {
|
||||||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19};
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SHA224Reset
|
* SHA224Reset
|
||||||
@ -229,13 +228,19 @@ int SHA256Reset(SHA256Context *context)
|
|||||||
int SHA256Input(SHA256Context *context, const uint8_t *message_array,
|
int SHA256Input(SHA256Context *context, const uint8_t *message_array,
|
||||||
unsigned int length)
|
unsigned int length)
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
if (!length) return shaSuccess;
|
return shaNull;
|
||||||
if (!message_array) return shaNull;
|
if (!length)
|
||||||
if (context->Computed) return context->Corrupted = shaStateError;
|
return shaSuccess;
|
||||||
if (context->Corrupted) return context->Corrupted;
|
if (!message_array)
|
||||||
|
return shaNull;
|
||||||
|
if (context->Computed)
|
||||||
|
return context->Corrupted = shaStateError;
|
||||||
|
if (context->Corrupted)
|
||||||
|
return context->Corrupted;
|
||||||
|
|
||||||
while (length--) {
|
while (length--)
|
||||||
|
{
|
||||||
context->Message_Block[context->Message_Block_Index++] =
|
context->Message_Block[context->Message_Block_Index++] =
|
||||||
*message_array;
|
*message_array;
|
||||||
|
|
||||||
@ -247,7 +252,6 @@ int SHA256Input(SHA256Context *context, const uint8_t *message_array,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return context->Corrupted;
|
return context->Corrupted;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -276,24 +280,26 @@ int SHA256FinalBits(SHA256Context *context,
|
|||||||
/* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80,
|
/* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80,
|
||||||
/* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0,
|
/* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0,
|
||||||
/* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8,
|
/* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8,
|
||||||
/* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE
|
/* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE};
|
||||||
};
|
|
||||||
static uint8_t markbit[8] = {
|
static uint8_t markbit[8] = {
|
||||||
/* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40,
|
/* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40,
|
||||||
/* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10,
|
/* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10,
|
||||||
/* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04,
|
/* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04,
|
||||||
/* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01
|
/* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01};
|
||||||
};
|
|
||||||
|
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
if (!length) return shaSuccess;
|
return shaNull;
|
||||||
if (context->Corrupted) return context->Corrupted;
|
if (!length)
|
||||||
if (context->Computed) return context->Corrupted = shaStateError;
|
return shaSuccess;
|
||||||
if (length >= 8) return context->Corrupted = shaBadParam;
|
if (context->Corrupted)
|
||||||
|
return context->Corrupted;
|
||||||
|
if (context->Computed)
|
||||||
|
return context->Corrupted = shaStateError;
|
||||||
|
if (length >= 8)
|
||||||
|
return context->Corrupted = shaBadParam;
|
||||||
|
|
||||||
SHA224_256AddLength(context, length);
|
SHA224_256AddLength(context, length);
|
||||||
SHA224_256Finalize(context, (uint8_t)
|
SHA224_256Finalize(context, (uint8_t)((message_bits & masks[length]) | markbit[length]));
|
||||||
((message_bits & masks[length]) | markbit[length]));
|
|
||||||
|
|
||||||
return context->Corrupted;
|
return context->Corrupted;
|
||||||
}
|
}
|
||||||
@ -341,7 +347,8 @@ int SHA256Result(SHA256Context *context,
|
|||||||
*/
|
*/
|
||||||
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0)
|
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0)
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
|
return shaNull;
|
||||||
|
|
||||||
context->Length_High = context->Length_Low = 0;
|
context->Length_High = context->Length_Low = 0;
|
||||||
context->Message_Block_Index = 0;
|
context->Message_Block_Index = 0;
|
||||||
@ -396,8 +403,7 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
|
|||||||
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
|
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
|
||||||
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
|
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
|
||||||
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
|
||||||
};
|
|
||||||
int t, t4; /* Loop counter */
|
int t, t4; /* Loop counter */
|
||||||
uint32_t temp1, temp2; /* Temporary word value */
|
uint32_t temp1, temp2; /* Temporary word value */
|
||||||
uint32_t W[64]; /* Word sequence */
|
uint32_t W[64]; /* Word sequence */
|
||||||
@ -424,7 +430,8 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
|
|||||||
G = context->Intermediate_Hash[6];
|
G = context->Intermediate_Hash[6];
|
||||||
H = context->Intermediate_Hash[7];
|
H = context->Intermediate_Hash[7];
|
||||||
|
|
||||||
for (t = 0; t < 64; t++) {
|
for (t = 0; t < 64; t++)
|
||||||
|
{
|
||||||
temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E, F, G) + K[t] + W[t];
|
temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E, F, G) + K[t] + W[t];
|
||||||
temp2 = SHA256_SIGMA0(A) + SHA_Maj(A, B, C);
|
temp2 = SHA256_SIGMA0(A) + SHA_Maj(A, B, C);
|
||||||
H = G;
|
H = G;
|
||||||
@ -513,12 +520,14 @@ static void SHA224_256PadMessage(SHA256Context *context,
|
|||||||
* block, process it, and then continue padding into a second
|
* block, process it, and then continue padding into a second
|
||||||
* block.
|
* block.
|
||||||
*/
|
*/
|
||||||
if (context->Message_Block_Index >= (SHA256_Message_Block_Size-8)) {
|
if (context->Message_Block_Index >= (SHA256_Message_Block_Size - 8))
|
||||||
|
{
|
||||||
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
|
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
|
||||||
while (context->Message_Block_Index < SHA256_Message_Block_Size)
|
while (context->Message_Block_Index < SHA256_Message_Block_Size)
|
||||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||||
SHA224_256ProcessMessageBlock(context);
|
SHA224_256ProcessMessageBlock(context);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
|
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
|
||||||
|
|
||||||
while (context->Message_Block_Index < (SHA256_Message_Block_Size - 8))
|
while (context->Message_Block_Index < (SHA256_Message_Block_Size - 8))
|
||||||
@ -565,17 +574,18 @@ static int SHA224_256ResultN(SHA256Context *context,
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
if (!Message_Digest) return shaNull;
|
return shaNull;
|
||||||
if (context->Corrupted) return context->Corrupted;
|
if (!Message_Digest)
|
||||||
|
return shaNull;
|
||||||
|
if (context->Corrupted)
|
||||||
|
return context->Corrupted;
|
||||||
|
|
||||||
if (!context->Computed)
|
if (!context->Computed)
|
||||||
SHA224_256Finalize(context, 0x80);
|
SHA224_256Finalize(context, 0x80);
|
||||||
|
|
||||||
for (i = 0; i < HashSize; ++i)
|
for (i = 0; i < HashSize; ++i)
|
||||||
Message_Digest[i] = (uint8_t)
|
Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03)));
|
||||||
(context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ));
|
|
||||||
|
|
||||||
return shaSuccess;
|
return shaSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,12 +30,17 @@
|
|||||||
*/
|
*/
|
||||||
int USHAReset(USHAContext *context, enum SHAversion whichSha)
|
int USHAReset(USHAContext *context, enum SHAversion whichSha)
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
|
return shaNull;
|
||||||
context->whichSha = whichSha;
|
context->whichSha = whichSha;
|
||||||
switch (whichSha) {
|
switch (whichSha)
|
||||||
case SHA224: return SHA224Reset((SHA224Context*)&context->ctx);
|
{
|
||||||
case SHA256: return SHA256Reset((SHA256Context*)&context->ctx);
|
case SHA224:
|
||||||
default: return shaBadParam;
|
return SHA224Reset((SHA224Context *)&context->ctx);
|
||||||
|
case SHA256:
|
||||||
|
return SHA256Reset((SHA256Context *)&context->ctx);
|
||||||
|
default:
|
||||||
|
return shaBadParam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,15 +67,18 @@ int USHAReset(USHAContext *context, enum SHAversion whichSha)
|
|||||||
int USHAInput(USHAContext *context,
|
int USHAInput(USHAContext *context,
|
||||||
const uint8_t *bytes, unsigned int bytecount)
|
const uint8_t *bytes, unsigned int bytecount)
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
switch (context->whichSha) {
|
return shaNull;
|
||||||
|
switch (context->whichSha)
|
||||||
|
{
|
||||||
case SHA224:
|
case SHA224:
|
||||||
return SHA224Input((SHA224Context *)&context->ctx, bytes,
|
return SHA224Input((SHA224Context *)&context->ctx, bytes,
|
||||||
bytecount);
|
bytecount);
|
||||||
case SHA256:
|
case SHA256:
|
||||||
return SHA256Input((SHA256Context *)&context->ctx, bytes,
|
return SHA256Input((SHA256Context *)&context->ctx, bytes,
|
||||||
bytecount);
|
bytecount);
|
||||||
default: return shaBadParam;
|
default:
|
||||||
|
return shaBadParam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,15 +104,18 @@ int USHAInput(USHAContext *context,
|
|||||||
int USHAFinalBits(USHAContext *context,
|
int USHAFinalBits(USHAContext *context,
|
||||||
uint8_t bits, unsigned int bit_count)
|
uint8_t bits, unsigned int bit_count)
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
switch (context->whichSha) {
|
return shaNull;
|
||||||
|
switch (context->whichSha)
|
||||||
|
{
|
||||||
case SHA224:
|
case SHA224:
|
||||||
return SHA224FinalBits((SHA224Context *)&context->ctx, bits,
|
return SHA224FinalBits((SHA224Context *)&context->ctx, bits,
|
||||||
bit_count);
|
bit_count);
|
||||||
case SHA256:
|
case SHA256:
|
||||||
return SHA256FinalBits((SHA256Context *)&context->ctx, bits,
|
return SHA256FinalBits((SHA256Context *)&context->ctx, bits,
|
||||||
bit_count);
|
bit_count);
|
||||||
default: return shaBadParam;
|
default:
|
||||||
|
return shaBadParam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,15 +141,18 @@ int USHAFinalBits(USHAContext *context,
|
|||||||
int USHAResult(USHAContext *context,
|
int USHAResult(USHAContext *context,
|
||||||
uint8_t Message_Digest[USHAMaxHashSize])
|
uint8_t Message_Digest[USHAMaxHashSize])
|
||||||
{
|
{
|
||||||
if (!context) return shaNull;
|
if (!context)
|
||||||
switch (context->whichSha) {
|
return shaNull;
|
||||||
|
switch (context->whichSha)
|
||||||
|
{
|
||||||
case SHA224:
|
case SHA224:
|
||||||
return SHA224Result((SHA224Context *)&context->ctx,
|
return SHA224Result((SHA224Context *)&context->ctx,
|
||||||
Message_Digest);
|
Message_Digest);
|
||||||
case SHA256:
|
case SHA256:
|
||||||
return SHA256Result((SHA256Context *)&context->ctx,
|
return SHA256Result((SHA256Context *)&context->ctx,
|
||||||
Message_Digest);
|
Message_Digest);
|
||||||
default: return shaBadParam;
|
default:
|
||||||
|
return shaBadParam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,10 +173,13 @@ int USHAResult(USHAContext *context,
|
|||||||
*/
|
*/
|
||||||
int USHABlockSize(enum SHAversion whichSha)
|
int USHABlockSize(enum SHAversion whichSha)
|
||||||
{
|
{
|
||||||
switch (whichSha) {
|
switch (whichSha)
|
||||||
case SHA224: return SHA224_Message_Block_Size;
|
{
|
||||||
|
case SHA224:
|
||||||
|
return SHA224_Message_Block_Size;
|
||||||
default:
|
default:
|
||||||
case SHA256: return SHA256_Message_Block_Size;
|
case SHA256:
|
||||||
|
return SHA256_Message_Block_Size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,9 +200,12 @@ int USHABlockSize(enum SHAversion whichSha)
|
|||||||
*/
|
*/
|
||||||
int USHAHashSize(enum SHAversion whichSha)
|
int USHAHashSize(enum SHAversion whichSha)
|
||||||
{
|
{
|
||||||
switch (whichSha) {
|
switch (whichSha)
|
||||||
case SHA224: return SHA224HashSize;
|
{
|
||||||
|
case SHA224:
|
||||||
|
return SHA224HashSize;
|
||||||
default:
|
default:
|
||||||
case SHA256: return SHA256HashSize;
|
case SHA256:
|
||||||
|
return SHA256HashSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
297
nfq/darkmagic.c
297
nfq/darkmagic.c
@ -65,7 +65,8 @@ uint32_t *tcp_find_timestamps(struct tcphdr *tcp)
|
|||||||
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp)
|
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp)
|
||||||
{
|
{
|
||||||
uint8_t *scale = tcp_find_option((struct tcphdr *)tcp, 3); // tcp option 3 - scale factor
|
uint8_t *scale = tcp_find_option((struct tcphdr *)tcp, 3); // tcp option 3 - scale factor
|
||||||
if (scale && scale[1]==3) return scale[2];
|
if (scale && scale[1] == 3)
|
||||||
|
return scale[2];
|
||||||
return SCALE_NONE;
|
return SCALE_NONE;
|
||||||
}
|
}
|
||||||
bool tcp_has_fastopen(const struct tcphdr *tcp)
|
bool tcp_has_fastopen(const struct tcphdr *tcp)
|
||||||
@ -73,7 +74,8 @@ bool tcp_has_fastopen(const struct tcphdr *tcp)
|
|||||||
uint8_t *opt;
|
uint8_t *opt;
|
||||||
// new style RFC7413
|
// new style RFC7413
|
||||||
opt = tcp_find_option((struct tcphdr *)tcp, 34);
|
opt = tcp_find_option((struct tcphdr *)tcp, 34);
|
||||||
if (opt) return true;
|
if (opt)
|
||||||
|
return true;
|
||||||
// old style RFC6994
|
// old style RFC6994
|
||||||
opt = tcp_find_option((struct tcphdr *)tcp, 254);
|
opt = tcp_find_option((struct tcphdr *)tcp, 254);
|
||||||
return opt && opt[1] >= 4 && opt[2] == 0xF9 && opt[3] == 0x89;
|
return opt && opt[1] >= 4 && opt[2] == 0xF9 && opt[3] == 0x89;
|
||||||
@ -136,16 +138,20 @@ static void fill_tcphdr(
|
|||||||
tcpopt[t++] = 3;
|
tcpopt[t++] = 3;
|
||||||
tcpopt[t++] = scale_factor;
|
tcpopt[t++] = scale_factor;
|
||||||
}
|
}
|
||||||
while (t&3) tcpopt[t++]=1; // noop
|
while (t & 3)
|
||||||
|
tcpopt[t++] = 1; // noop
|
||||||
tcp->th_off += t >> 2;
|
tcp->th_off += t >> 2;
|
||||||
tcp->th_sum = 0;
|
tcp->th_sum = 0;
|
||||||
}
|
}
|
||||||
static uint16_t tcpopt_len(uint32_t fooling, const uint32_t *timestamps, uint8_t scale_factor)
|
static uint16_t tcpopt_len(uint32_t fooling, const uint32_t *timestamps, uint8_t scale_factor)
|
||||||
{
|
{
|
||||||
uint16_t t = 0;
|
uint16_t t = 0;
|
||||||
if (fooling & FOOL_MD5SIG) t=18;
|
if (fooling & FOOL_MD5SIG)
|
||||||
if ((fooling & FOOL_TS) || timestamps) t+=10;
|
t = 18;
|
||||||
if (scale_factor!=SCALE_NONE) t+=3;
|
if ((fooling & FOOL_TS) || timestamps)
|
||||||
|
t += 10;
|
||||||
|
if (scale_factor != SCALE_NONE)
|
||||||
|
t += 3;
|
||||||
return (t + 3) & ~3;
|
return (t + 3) & ~3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +205,8 @@ bool prepare_tcp_segment4(
|
|||||||
uint16_t tcpoptlen = tcpopt_len(fooling, timestamps, scale_factor);
|
uint16_t tcpoptlen = tcpopt_len(fooling, timestamps, scale_factor);
|
||||||
uint16_t ip_payload_len = sizeof(struct tcphdr) + tcpoptlen + len;
|
uint16_t ip_payload_len = sizeof(struct tcphdr) + tcpoptlen + len;
|
||||||
uint16_t pktlen = sizeof(struct ip) + ip_payload_len;
|
uint16_t pktlen = sizeof(struct ip) + ip_payload_len;
|
||||||
if (pktlen>*buflen) return false;
|
if (pktlen > *buflen)
|
||||||
|
return false;
|
||||||
|
|
||||||
struct ip *ip = (struct ip *)buf;
|
struct ip *ip = (struct ip *)buf;
|
||||||
struct tcphdr *tcp = (struct tcphdr *)(ip + 1);
|
struct tcphdr *tcp = (struct tcphdr *)(ip + 1);
|
||||||
@ -210,7 +217,8 @@ bool prepare_tcp_segment4(
|
|||||||
|
|
||||||
memcpy(payload, data, len);
|
memcpy(payload, data, len);
|
||||||
tcp4_fix_checksum(tcp, ip_payload_len, &ip->ip_src, &ip->ip_dst);
|
tcp4_fix_checksum(tcp, ip_payload_len, &ip->ip_src, &ip->ip_dst);
|
||||||
if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF);
|
if (fooling & FOOL_BADSUM)
|
||||||
|
tcp->th_sum ^= htons(0xBEAF);
|
||||||
|
|
||||||
*buflen = pktlen;
|
*buflen = pktlen;
|
||||||
return true;
|
return true;
|
||||||
@ -238,7 +246,8 @@ bool prepare_tcp_segment6(
|
|||||||
8 * !!(fooling & FOOL_DESTOPT) +
|
8 * !!(fooling & FOOL_DESTOPT) +
|
||||||
8 * !!(fooling & FOOL_IPFRAG1);
|
8 * !!(fooling & FOOL_IPFRAG1);
|
||||||
uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len;
|
uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len;
|
||||||
if (pktlen>*buflen) return false;
|
if (pktlen > *buflen)
|
||||||
|
return false;
|
||||||
|
|
||||||
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
|
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
|
||||||
struct tcphdr *tcp = (struct tcphdr *)(ip6 + 1);
|
struct tcphdr *tcp = (struct tcphdr *)(ip6 + 1);
|
||||||
@ -293,7 +302,8 @@ bool prepare_tcp_segment6(
|
|||||||
|
|
||||||
memcpy(payload, data, len);
|
memcpy(payload, data, len);
|
||||||
tcp6_fix_checksum(tcp, transport_payload_len, &ip6->ip6_src, &ip6->ip6_dst);
|
tcp6_fix_checksum(tcp, transport_payload_len, &ip6->ip6_src, &ip6->ip6_dst);
|
||||||
if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF);
|
if (fooling & FOOL_BADSUM)
|
||||||
|
tcp->th_sum ^= htons(0xBEAF);
|
||||||
|
|
||||||
*buflen = pktlen;
|
*buflen = pktlen;
|
||||||
return true;
|
return true;
|
||||||
@ -313,14 +323,10 @@ bool prepare_tcp_segment(
|
|||||||
const void *data, uint16_t len,
|
const void *data, uint16_t len,
|
||||||
uint8_t *buf, size_t *buflen)
|
uint8_t *buf, size_t *buflen)
|
||||||
{
|
{
|
||||||
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
|
return (src->sa_family == AF_INET && dst->sa_family == AF_INET) ? prepare_tcp_segment4((struct sockaddr_in *)src, (struct sockaddr_in *)dst, tcp_flags, nseq, nack_seq, nwsize, scale_factor, timestamps, ttl, fooling, badseq_increment, badseq_ack_increment, data, len, buf, buflen) : (src->sa_family == AF_INET6 && dst->sa_family == AF_INET6) ? prepare_tcp_segment6((struct sockaddr_in6 *)src, (struct sockaddr_in6 *)dst, tcp_flags, nseq, nack_seq, nwsize, scale_factor, timestamps, ttl, fooling, badseq_increment, badseq_ack_increment, data, len, buf, buflen)
|
||||||
prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
|
: false;
|
||||||
(src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ?
|
|
||||||
prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
|
|
||||||
false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// padlen<0 means payload shrinking
|
// padlen<0 means payload shrinking
|
||||||
bool prepare_udp_segment4(
|
bool prepare_udp_segment4(
|
||||||
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
||||||
@ -331,8 +337,10 @@ bool prepare_udp_segment4(
|
|||||||
const void *data, uint16_t len,
|
const void *data, uint16_t len,
|
||||||
uint8_t *buf, size_t *buflen)
|
uint8_t *buf, size_t *buflen)
|
||||||
{
|
{
|
||||||
if ((len+padlen)<=0) padlen=-(int)len+1; // do not allow payload to be less that 1 byte
|
if ((len + padlen) <= 0)
|
||||||
if ((len+padlen)>0xFFFF) padlen=0xFFFF-len; // do not allow payload size to exceed u16 range
|
padlen = -(int)len + 1; // do not allow payload to be less that 1 byte
|
||||||
|
if ((len + padlen) > 0xFFFF)
|
||||||
|
padlen = 0xFFFF - len; // do not allow payload size to exceed u16 range
|
||||||
if (padlen < 0)
|
if (padlen < 0)
|
||||||
{
|
{
|
||||||
len += padlen;
|
len += padlen;
|
||||||
@ -341,13 +349,13 @@ bool prepare_udp_segment4(
|
|||||||
uint16_t datalen = (uint16_t)(len + padlen);
|
uint16_t datalen = (uint16_t)(len + padlen);
|
||||||
uint16_t ip_payload_len = sizeof(struct udphdr) + datalen;
|
uint16_t ip_payload_len = sizeof(struct udphdr) + datalen;
|
||||||
uint16_t pktlen = sizeof(struct ip) + ip_payload_len;
|
uint16_t pktlen = sizeof(struct ip) + ip_payload_len;
|
||||||
if (pktlen>*buflen) return false;
|
if (pktlen > *buflen)
|
||||||
|
return false;
|
||||||
|
|
||||||
struct ip *ip = (struct ip *)buf;
|
struct ip *ip = (struct ip *)buf;
|
||||||
struct udphdr *udp = (struct udphdr *)(ip + 1);
|
struct udphdr *udp = (struct udphdr *)(ip + 1);
|
||||||
uint8_t *payload = (uint8_t *)(udp + 1);
|
uint8_t *payload = (uint8_t *)(udp + 1);
|
||||||
|
|
||||||
|
|
||||||
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, ttl);
|
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, ttl);
|
||||||
fill_udphdr(udp, src->sin_port, dst->sin_port, datalen);
|
fill_udphdr(udp, src->sin_port, dst->sin_port, datalen);
|
||||||
|
|
||||||
@ -357,7 +365,8 @@ bool prepare_udp_segment4(
|
|||||||
else
|
else
|
||||||
memset(payload + len, 0, padlen);
|
memset(payload + len, 0, padlen);
|
||||||
udp4_fix_checksum(udp, ip_payload_len, &ip->ip_src, &ip->ip_dst);
|
udp4_fix_checksum(udp, ip_payload_len, &ip->ip_src, &ip->ip_dst);
|
||||||
if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF);
|
if (fooling & FOOL_BADSUM)
|
||||||
|
udp->uh_sum ^= htons(0xBEAF);
|
||||||
|
|
||||||
*buflen = pktlen;
|
*buflen = pktlen;
|
||||||
return true;
|
return true;
|
||||||
@ -371,8 +380,10 @@ bool prepare_udp_segment6(
|
|||||||
const void *data, uint16_t len,
|
const void *data, uint16_t len,
|
||||||
uint8_t *buf, size_t *buflen)
|
uint8_t *buf, size_t *buflen)
|
||||||
{
|
{
|
||||||
if ((len+padlen)<=0) padlen=-(int)len+1; // do not allow payload to be less that 1 byte
|
if ((len + padlen) <= 0)
|
||||||
if ((len+padlen)>0xFFFF) padlen=0xFFFF-len; // do not allow payload size to exceed u16 range
|
padlen = -(int)len + 1; // do not allow payload to be less that 1 byte
|
||||||
|
if ((len + padlen) > 0xFFFF)
|
||||||
|
padlen = 0xFFFF - len; // do not allow payload size to exceed u16 range
|
||||||
if (padlen < 0)
|
if (padlen < 0)
|
||||||
{
|
{
|
||||||
len += padlen;
|
len += padlen;
|
||||||
@ -386,7 +397,8 @@ bool prepare_udp_segment6(
|
|||||||
8 * !!(fooling & FOOL_DESTOPT) +
|
8 * !!(fooling & FOOL_DESTOPT) +
|
||||||
8 * !!(fooling & FOOL_IPFRAG1);
|
8 * !!(fooling & FOOL_IPFRAG1);
|
||||||
uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len;
|
uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len;
|
||||||
if (pktlen>*buflen) return false;
|
if (pktlen > *buflen)
|
||||||
|
return false;
|
||||||
|
|
||||||
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
|
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
|
||||||
struct udphdr *udp = (struct udphdr *)(ip6 + 1);
|
struct udphdr *udp = (struct udphdr *)(ip6 + 1);
|
||||||
@ -445,7 +457,8 @@ bool prepare_udp_segment6(
|
|||||||
else
|
else
|
||||||
memset(payload + len, 0, padlen);
|
memset(payload + len, 0, padlen);
|
||||||
udp6_fix_checksum(udp, transport_payload_len, &ip6->ip6_src, &ip6->ip6_dst);
|
udp6_fix_checksum(udp, transport_payload_len, &ip6->ip6_src, &ip6->ip6_dst);
|
||||||
if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF);
|
if (fooling & FOOL_BADSUM)
|
||||||
|
udp->uh_sum ^= htons(0xBEAF);
|
||||||
|
|
||||||
*buflen = pktlen;
|
*buflen = pktlen;
|
||||||
return true;
|
return true;
|
||||||
@ -459,11 +472,8 @@ bool prepare_udp_segment(
|
|||||||
const void *data, uint16_t len,
|
const void *data, uint16_t len,
|
||||||
uint8_t *buf, size_t *buflen)
|
uint8_t *buf, size_t *buflen)
|
||||||
{
|
{
|
||||||
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
|
return (src->sa_family == AF_INET && dst->sa_family == AF_INET) ? prepare_udp_segment4((struct sockaddr_in *)src, (struct sockaddr_in *)dst, ttl, fooling, padding, padding_size, padlen, data, len, buf, buflen) : (src->sa_family == AF_INET6 && dst->sa_family == AF_INET6) ? prepare_udp_segment6((struct sockaddr_in6 *)src, (struct sockaddr_in6 *)dst, ttl, fooling, padding, padding_size, padlen, data, len, buf, buflen)
|
||||||
prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,ttl,fooling,padding,padding_size,padlen,data,len,buf,buflen) :
|
: false;
|
||||||
(src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ?
|
|
||||||
prepare_udp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,ttl,fooling,padding,padding_size,padlen,data,len,buf,buflen) :
|
|
||||||
false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ip6_insert_simple_hdr(uint8_t type, uint8_t *data_pkt, size_t len_pkt, uint8_t *buf, size_t *buflen)
|
bool ip6_insert_simple_hdr(uint8_t type, uint8_t *data_pkt, size_t len_pkt, uint8_t *buf, size_t *buflen)
|
||||||
@ -493,17 +503,21 @@ bool ip_frag4(
|
|||||||
{
|
{
|
||||||
uint16_t hdrlen, payload_len;
|
uint16_t hdrlen, payload_len;
|
||||||
// frag_pos must be 8-byte aligned
|
// frag_pos must be 8-byte aligned
|
||||||
if (frag_pos & 7 || pkt_size < sizeof(struct ip)) return false;
|
if (frag_pos & 7 || pkt_size < sizeof(struct ip))
|
||||||
|
return false;
|
||||||
payload_len = htons(((struct ip *)pkt)->ip_len);
|
payload_len = htons(((struct ip *)pkt)->ip_len);
|
||||||
hdrlen = ((struct ip *)pkt)->ip_hl << 2;
|
hdrlen = ((struct ip *)pkt)->ip_hl << 2;
|
||||||
if (payload_len>pkt_size || hdrlen>pkt_size || hdrlen>payload_len) return false;
|
if (payload_len > pkt_size || hdrlen > pkt_size || hdrlen > payload_len)
|
||||||
|
return false;
|
||||||
payload_len -= hdrlen;
|
payload_len -= hdrlen;
|
||||||
if (frag_pos>=payload_len || *pkt1_size<(hdrlen+frag_pos) || *pkt2_size<(hdrlen+payload_len-frag_pos)) return false;
|
if (frag_pos >= payload_len || *pkt1_size < (hdrlen + frag_pos) || *pkt2_size < (hdrlen + payload_len - frag_pos))
|
||||||
|
return false;
|
||||||
|
|
||||||
memcpy(pkt1, pkt, hdrlen + frag_pos);
|
memcpy(pkt1, pkt, hdrlen + frag_pos);
|
||||||
((struct ip *)pkt1)->ip_off = htons(IP_MF);
|
((struct ip *)pkt1)->ip_off = htons(IP_MF);
|
||||||
((struct ip *)pkt1)->ip_len = htons(hdrlen + frag_pos);
|
((struct ip *)pkt1)->ip_len = htons(hdrlen + frag_pos);
|
||||||
if (ident!=(uint32_t)-1) ((struct ip*)pkt1)->ip_id = (uint16_t)ident;
|
if (ident != (uint32_t)-1)
|
||||||
|
((struct ip *)pkt1)->ip_id = (uint16_t)ident;
|
||||||
*pkt1_size = hdrlen + frag_pos;
|
*pkt1_size = hdrlen + frag_pos;
|
||||||
ip4_fix_checksum((struct ip *)pkt1);
|
ip4_fix_checksum((struct ip *)pkt1);
|
||||||
|
|
||||||
@ -511,7 +525,8 @@ bool ip_frag4(
|
|||||||
memcpy(pkt2 + hdrlen, pkt + hdrlen + frag_pos, payload_len - frag_pos);
|
memcpy(pkt2 + hdrlen, pkt + hdrlen + frag_pos, payload_len - frag_pos);
|
||||||
((struct ip *)pkt2)->ip_off = htons((uint16_t)frag_pos >> 3 & IP_OFFMASK);
|
((struct ip *)pkt2)->ip_off = htons((uint16_t)frag_pos >> 3 & IP_OFFMASK);
|
||||||
((struct ip *)pkt2)->ip_len = htons(hdrlen + payload_len - frag_pos);
|
((struct ip *)pkt2)->ip_len = htons(hdrlen + payload_len - frag_pos);
|
||||||
if (ident!=(uint32_t)-1) ((struct ip*)pkt2)->ip_id = (uint16_t)ident;
|
if (ident != (uint32_t)-1)
|
||||||
|
((struct ip *)pkt2)->ip_id = (uint16_t)ident;
|
||||||
*pkt2_size = hdrlen + payload_len - frag_pos;
|
*pkt2_size = hdrlen + payload_len - frag_pos;
|
||||||
ip4_fix_checksum((struct ip *)pkt2);
|
ip4_fix_checksum((struct ip *)pkt2);
|
||||||
|
|
||||||
@ -529,9 +544,11 @@ bool ip_frag6(
|
|||||||
struct ip6_frag *frag;
|
struct ip6_frag *frag;
|
||||||
const uint8_t *payload;
|
const uint8_t *payload;
|
||||||
|
|
||||||
if (frag_pos & 7 || pkt_size < sizeof(struct ip6_hdr)) return false;
|
if (frag_pos & 7 || pkt_size < sizeof(struct ip6_hdr))
|
||||||
|
return false;
|
||||||
payload_len = sizeof(struct ip6_hdr) + htons(((struct ip6_hdr *)pkt)->ip6_ctlun.ip6_un1.ip6_un1_plen);
|
payload_len = sizeof(struct ip6_hdr) + htons(((struct ip6_hdr *)pkt)->ip6_ctlun.ip6_un1.ip6_un1_plen);
|
||||||
if (pkt_size < payload_len) return false;
|
if (pkt_size < payload_len)
|
||||||
|
return false;
|
||||||
|
|
||||||
payload = pkt;
|
payload = pkt;
|
||||||
proto_skip_ipv6((uint8_t **)&payload, &payload_len, &proto, &last_header_type);
|
proto_skip_ipv6((uint8_t **)&payload, &payload_len, &proto, &last_header_type);
|
||||||
@ -586,16 +603,23 @@ bool ip_frag(
|
|||||||
|
|
||||||
void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl)
|
void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl)
|
||||||
{
|
{
|
||||||
if (ip) ip->ip_ttl = ttl;
|
if (ip)
|
||||||
if (ip6) ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl;
|
ip->ip_ttl = ttl;
|
||||||
|
if (ip6)
|
||||||
|
ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport)
|
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport)
|
||||||
{
|
{
|
||||||
if (sport) *sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0);
|
if (sport)
|
||||||
if (dport) *dport = htons(tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0);
|
*sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport
|
||||||
if (proto) *proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP : -1;
|
: 0);
|
||||||
|
if (dport)
|
||||||
|
*dport = htons(tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport
|
||||||
|
: 0);
|
||||||
|
if (proto)
|
||||||
|
*proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP
|
||||||
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void extract_endpoints(const struct ip *ip, const struct ip6_hdr *ip6hdr, const struct tcphdr *tcphdr, const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst)
|
void extract_endpoints(const struct ip *ip, const struct ip6_hdr *ip6hdr, const struct tcphdr *tcphdr, const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst)
|
||||||
@ -608,7 +632,8 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st
|
|||||||
{
|
{
|
||||||
si = (struct sockaddr_in *)dst;
|
si = (struct sockaddr_in *)dst;
|
||||||
si->sin_family = AF_INET;
|
si->sin_family = AF_INET;
|
||||||
si->sin_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0;
|
si->sin_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport
|
||||||
|
: 0;
|
||||||
si->sin_addr = ip->ip_dst;
|
si->sin_addr = ip->ip_dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +641,8 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st
|
|||||||
{
|
{
|
||||||
si = (struct sockaddr_in *)src;
|
si = (struct sockaddr_in *)src;
|
||||||
si->sin_family = AF_INET;
|
si->sin_family = AF_INET;
|
||||||
si->sin_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0;
|
si->sin_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport
|
||||||
|
: 0;
|
||||||
si->sin_addr = ip->ip_src;
|
si->sin_addr = ip->ip_src;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -628,7 +654,8 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st
|
|||||||
{
|
{
|
||||||
si = (struct sockaddr_in6 *)dst;
|
si = (struct sockaddr_in6 *)dst;
|
||||||
si->sin6_family = AF_INET6;
|
si->sin6_family = AF_INET6;
|
||||||
si->sin6_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0;
|
si->sin6_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport
|
||||||
|
: 0;
|
||||||
si->sin6_addr = ip6hdr->ip6_dst;
|
si->sin6_addr = ip6hdr->ip6_dst;
|
||||||
si->sin6_flowinfo = 0;
|
si->sin6_flowinfo = 0;
|
||||||
si->sin6_scope_id = 0;
|
si->sin6_scope_id = 0;
|
||||||
@ -638,7 +665,8 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st
|
|||||||
{
|
{
|
||||||
si = (struct sockaddr_in6 *)src;
|
si = (struct sockaddr_in6 *)src;
|
||||||
si->sin6_family = AF_INET6;
|
si->sin6_family = AF_INET6;
|
||||||
si->sin6_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0;
|
si->sin6_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport
|
||||||
|
: 0;
|
||||||
si->sin6_addr = ip6hdr->ip6_src;
|
si->sin6_addr = ip6hdr->ip6_src;
|
||||||
si->sin6_flowinfo = 0;
|
si->sin6_flowinfo = 0;
|
||||||
si->sin6_scope_id = 0;
|
si->sin6_scope_id = 0;
|
||||||
@ -692,9 +720,12 @@ uint16_t family_from_proto(uint8_t l3proto)
|
|||||||
{
|
{
|
||||||
switch (l3proto)
|
switch (l3proto)
|
||||||
{
|
{
|
||||||
case IPPROTO_IP: return AF_INET;
|
case IPPROTO_IP:
|
||||||
case IPPROTO_IPV6: return AF_INET6;
|
return AF_INET;
|
||||||
default: return -1;
|
case IPPROTO_IPV6:
|
||||||
|
return AF_INET6;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,12 +774,18 @@ void print_ip6hdr(const struct ip6_hdr *ip6hdr, uint8_t proto)
|
|||||||
void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr)
|
void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr)
|
||||||
{
|
{
|
||||||
char flags[7], *f = flags;
|
char flags[7], *f = flags;
|
||||||
if (tcphdr->th_flags & TH_SYN) *f++='S';
|
if (tcphdr->th_flags & TH_SYN)
|
||||||
if (tcphdr->th_flags & TH_ACK) *f++='A';
|
*f++ = 'S';
|
||||||
if (tcphdr->th_flags & TH_RST) *f++='R';
|
if (tcphdr->th_flags & TH_ACK)
|
||||||
if (tcphdr->th_flags & TH_FIN) *f++='F';
|
*f++ = 'A';
|
||||||
if (tcphdr->th_flags & TH_PUSH) *f++='P';
|
if (tcphdr->th_flags & TH_RST)
|
||||||
if (tcphdr->th_flags & TH_URG) *f++='U';
|
*f++ = 'R';
|
||||||
|
if (tcphdr->th_flags & TH_FIN)
|
||||||
|
*f++ = 'F';
|
||||||
|
if (tcphdr->th_flags & TH_PUSH)
|
||||||
|
*f++ = 'P';
|
||||||
|
if (tcphdr->th_flags & TH_URG)
|
||||||
|
*f++ = 'U';
|
||||||
*f = 0;
|
*f = 0;
|
||||||
snprintf(s, s_len, "sport=%u dport=%u flags=%s seq=%u ack_seq=%u", htons(tcphdr->th_sport), htons(tcphdr->th_dport), flags, htonl(tcphdr->th_seq), htonl(tcphdr->th_ack));
|
snprintf(s, s_len, "sport=%u dport=%u flags=%s seq=%u ack_seq=%u", htons(tcphdr->th_sport), htons(tcphdr->th_dport), flags, htonl(tcphdr->th_seq), htonl(tcphdr->th_ack));
|
||||||
}
|
}
|
||||||
@ -769,9 +806,6 @@ void print_udphdr(const struct udphdr *udphdr)
|
|||||||
printf("%s", s);
|
printf("%s", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool proto_check_ipv4(const uint8_t *data, size_t len)
|
bool proto_check_ipv4(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
return len >= 20 && (data[0] & 0xF0) == 0x40 &&
|
return len >= 20 && (data[0] & 0xF0) == 0x40 &&
|
||||||
@ -819,11 +853,14 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type, uint8_t *
|
|||||||
size_t hdrlen;
|
size_t hdrlen;
|
||||||
uint8_t HeaderType;
|
uint8_t HeaderType;
|
||||||
|
|
||||||
if (proto_type) *proto_type = 0; // put error in advance
|
if (proto_type)
|
||||||
|
*proto_type = 0; // put error in advance
|
||||||
|
|
||||||
HeaderType = (*data)[6]; // NextHeader field
|
HeaderType = (*data)[6]; // NextHeader field
|
||||||
if (last_header_type) *last_header_type = (*data)+6;
|
if (last_header_type)
|
||||||
*data += 40; *len -= 40; // skip ipv6 base header
|
*last_header_type = (*data) + 6;
|
||||||
|
*data += 40;
|
||||||
|
*len -= 40; // skip IPv6 base header
|
||||||
while (*len > 0) // need at least one byte for NextHeader field
|
while (*len > 0) // need at least one byte for NextHeader field
|
||||||
{
|
{
|
||||||
switch (HeaderType)
|
switch (HeaderType)
|
||||||
@ -835,7 +872,8 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type, uint8_t *
|
|||||||
case 135: // mobility
|
case 135: // mobility
|
||||||
case 139: // Host Identity Protocol Version v2
|
case 139: // Host Identity Protocol Version v2
|
||||||
case 140: // Shim6
|
case 140: // Shim6
|
||||||
if (*len < 2) return; // error
|
if (*len < 2)
|
||||||
|
return; // error
|
||||||
hdrlen = 8 + ((*data)[1] << 3);
|
hdrlen = 8 + ((*data)[1] << 3);
|
||||||
break;
|
break;
|
||||||
case 44: // fragment. length fixed to 8, hdrlen field defined as reserved
|
case 44: // fragment. length fixed to 8, hdrlen field defined as reserved
|
||||||
@ -844,13 +882,16 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type, uint8_t *
|
|||||||
case 59: // no next header
|
case 59: // no next header
|
||||||
return; // error
|
return; // error
|
||||||
default:
|
default:
|
||||||
// we found some meaningful payload. it can be tcp, udp, icmp or some another exotic shit
|
// we found some meaningful payload. it can be TCP, UDP, ICMP or some another exotic shit
|
||||||
if (proto_type) *proto_type = HeaderType;
|
if (proto_type)
|
||||||
|
*proto_type = HeaderType;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (*len < hdrlen) return; // error
|
if (*len < hdrlen)
|
||||||
|
return; // error
|
||||||
HeaderType = **data;
|
HeaderType = **data;
|
||||||
if (last_header_type) *last_header_type = *data;
|
if (last_header_type)
|
||||||
|
*last_header_type = *data;
|
||||||
// advance to the next header location
|
// advance to the next header location
|
||||||
*len -= hdrlen;
|
*len -= hdrlen;
|
||||||
*data += hdrlen;
|
*data += hdrlen;
|
||||||
@ -901,7 +942,6 @@ void proto_dissect_l3l4(
|
|||||||
|
|
||||||
*data_payload = data;
|
*data_payload = data;
|
||||||
*len_payload = len;
|
*len_payload = len;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (*proto == IPPROTO_UDP && proto_check_udp(data, len))
|
else if (*proto == IPPROTO_UDP && proto_check_udp(data, len))
|
||||||
{
|
{
|
||||||
@ -915,7 +955,6 @@ void proto_dissect_l3l4(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool tcp_synack_segment(const struct tcphdr *tcphdr)
|
bool tcp_synack_segment(const struct tcphdr *tcphdr)
|
||||||
{
|
{
|
||||||
/* check for set bits in TCP hdr */
|
/* check for set bits in TCP hdr */
|
||||||
@ -965,7 +1004,6 @@ void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize, uint8_t scale_fac
|
|||||||
tcp_rewrite_wscale(tcp, scale_factor);
|
tcp_rewrite_wscale(tcp, scale_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
|
|
||||||
static HANDLE w_filter = NULL;
|
static HANDLE w_filter = NULL;
|
||||||
@ -986,12 +1024,14 @@ static bool str2guid(const char* str, GUID *guid)
|
|||||||
if (36 != strlen(str) || 11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", u + 0, u + 1, u + 2, u + 3, u + 4, u + 5, u + 6, u + 7, u + 8, u + 9, u + 10))
|
if (36 != strlen(str) || 11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", u + 0, u + 1, u + 2, u + 3, u + 4, u + 5, u + 6, u + 7, u + 8, u + 9, u + 10))
|
||||||
return false;
|
return false;
|
||||||
guid->Data1 = u[0];
|
guid->Data1 = u[0];
|
||||||
if ((u[1] & 0xFFFF0000) || (u[2] & 0xFFFF0000)) return false;
|
if ((u[1] & 0xFFFF0000) || (u[2] & 0xFFFF0000))
|
||||||
|
return false;
|
||||||
guid->Data2 = (USHORT)u[1];
|
guid->Data2 = (USHORT)u[1];
|
||||||
guid->Data3 = (USHORT)u[2];
|
guid->Data3 = (USHORT)u[2];
|
||||||
for (k = 0; k < 8; k++)
|
for (k = 0; k < 8; k++)
|
||||||
{
|
{
|
||||||
if (u[k+3] & 0xFFFFFF00) return false;
|
if (u[k + 3] & 0xFFFFFF00)
|
||||||
|
return false;
|
||||||
guid->Data4[k] = (UCHAR)u[k + 3];
|
guid->Data4[k] = (UCHAR)u[k + 3];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -1008,7 +1048,8 @@ static bool AdapterID2Name(const GUID *guid,char *name,DWORD name_len)
|
|||||||
WCHAR namew[128];
|
WCHAR namew[128];
|
||||||
DWORD namew_len;
|
DWORD namew_len;
|
||||||
|
|
||||||
if (name_len<2) return false;
|
if (name_len < 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
if ((w_win32_error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, sNetworkCards, 0, KEY_ENUMERATE_SUB_KEYS, &hkNetworkCards)) == ERROR_SUCCESS)
|
if ((w_win32_error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, sNetworkCards, 0, KEY_ENUMERATE_SUB_KEYS, &hkNetworkCards)) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -1044,7 +1085,8 @@ static bool AdapterID2Name(const GUID *guid,char *name,DWORD name_len)
|
|||||||
}
|
}
|
||||||
RegCloseKey(hkCard);
|
RegCloseKey(hkCard);
|
||||||
}
|
}
|
||||||
if (bRet) break;
|
if (bRet)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@ -1058,8 +1100,10 @@ static bool AdapterID2Name(const GUID *guid,char *name,DWORD name_len)
|
|||||||
bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter)
|
bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter)
|
||||||
{
|
{
|
||||||
win_dark_deinit();
|
win_dark_deinit();
|
||||||
if (LIST_EMPTY(ssid_filter)) ssid_filter=NULL;
|
if (LIST_EMPTY(ssid_filter))
|
||||||
if (LIST_EMPTY(nlm_filter)) nlm_filter=NULL;
|
ssid_filter = NULL;
|
||||||
|
if (LIST_EMPTY(nlm_filter))
|
||||||
|
nlm_filter = NULL;
|
||||||
if (nlm_filter)
|
if (nlm_filter)
|
||||||
{
|
{
|
||||||
if (SUCCEEDED(w_win32_error = CoInitialize(NULL)))
|
if (SUCCEEDED(w_win32_error = CoInitialize(NULL)))
|
||||||
@ -1084,11 +1128,11 @@ bool win_dark_deinit(void)
|
|||||||
pNetworkListManager->lpVtbl->Release(pNetworkListManager);
|
pNetworkListManager->lpVtbl->Release(pNetworkListManager);
|
||||||
pNetworkListManager = NULL;
|
pNetworkListManager = NULL;
|
||||||
}
|
}
|
||||||
if (nlm_filter_net) CoUninitialize();
|
if (nlm_filter_net)
|
||||||
|
CoUninitialize();
|
||||||
wlan_filter_ssid = nlm_filter_net = NULL;
|
wlan_filter_ssid = nlm_filter_net = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool nlm_list(bool bAll)
|
bool nlm_list(bool bAll)
|
||||||
{
|
{
|
||||||
bool bRet = true;
|
bool bRet = true;
|
||||||
@ -1119,7 +1163,8 @@ bool nlm_list(bool bAll)
|
|||||||
bRet = false;
|
bRet = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (w_win32_error != S_OK) break;
|
if (w_win32_error != S_OK)
|
||||||
|
break;
|
||||||
if (SUCCEEDED(w_win32_error = pNet->lpVtbl->get_IsConnected(pNet, &bIsConnected)) &&
|
if (SUCCEEDED(w_win32_error = pNet->lpVtbl->get_IsConnected(pNet, &bIsConnected)) &&
|
||||||
SUCCEEDED(w_win32_error = pNet->lpVtbl->get_IsConnectedToInternet(pNet, &bIsConnectedInet)) &&
|
SUCCEEDED(w_win32_error = pNet->lpVtbl->get_IsConnectedToInternet(pNet, &bIsConnectedInet)) &&
|
||||||
SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkId(pNet, &idNet)) &&
|
SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkId(pNet, &idNet)) &&
|
||||||
@ -1131,13 +1176,14 @@ bool nlm_list(bool bAll)
|
|||||||
if (WideCharToMultiByte(CP_UTF8, 0, bstrName, -1, Name, sizeof(Name), NULL, NULL))
|
if (WideCharToMultiByte(CP_UTF8, 0, bstrName, -1, Name, sizeof(Name), NULL, NULL))
|
||||||
{
|
{
|
||||||
printf("Name : %s", Name);
|
printf("Name : %s", Name);
|
||||||
if (bIsConnected) printf(" (connected)");
|
if (bIsConnected)
|
||||||
if (bIsConnectedInet) printf(" (inet)");
|
printf(" (connected)");
|
||||||
|
if (bIsConnectedInet)
|
||||||
|
printf(" (inet)");
|
||||||
printf(" (%s)\n",
|
printf(" (%s)\n",
|
||||||
category==NLM_NETWORK_CATEGORY_PUBLIC ? "public" :
|
category == NLM_NETWORK_CATEGORY_PUBLIC ? "public" : category == NLM_NETWORK_CATEGORY_PRIVATE ? "private"
|
||||||
category==NLM_NETWORK_CATEGORY_PRIVATE ? "private" :
|
: category == NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED ? "domain"
|
||||||
category==NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED ? "domain" :
|
: "unknown");
|
||||||
"unknown");
|
|
||||||
guid2str(&idNet, Name);
|
guid2str(&idNet, Name);
|
||||||
printf("NetID : %s\n", Name);
|
printf("NetID : %s\n", Name);
|
||||||
if (connected && SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkConnections(pNet, &pEnumConnections)))
|
if (connected && SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkConnections(pNet, &pEnumConnections)))
|
||||||
@ -1169,9 +1215,11 @@ bool nlm_list(bool bAll)
|
|||||||
else
|
else
|
||||||
bRet = false;
|
bRet = false;
|
||||||
pNet->lpVtbl->Release(pNet);
|
pNet->lpVtbl->Release(pNet);
|
||||||
if (!bRet) break;
|
if (!bRet)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!bRet) break;
|
if (!bRet)
|
||||||
|
break;
|
||||||
pEnumNetworks->lpVtbl->Reset(pEnumNetworks);
|
pEnumNetworks->lpVtbl->Reset(pEnumNetworks);
|
||||||
}
|
}
|
||||||
pEnumNetworks->lpVtbl->Release(pEnumNetworks);
|
pEnumNetworks->lpVtbl->Release(pEnumNetworks);
|
||||||
@ -1216,7 +1264,8 @@ static bool nlm_filter_match(const struct str_list_head *nlm_list)
|
|||||||
bRet = false;
|
bRet = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (w_win32_error != S_OK) break;
|
if (w_win32_error != S_OK)
|
||||||
|
break;
|
||||||
if (SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkId(pNet, &idNet)) &&
|
if (SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkId(pNet, &idNet)) &&
|
||||||
SUCCEEDED(w_win32_error = pNet->lpVtbl->GetName(pNet, &bstrName)))
|
SUCCEEDED(w_win32_error = pNet->lpVtbl->GetName(pNet, &bstrName)))
|
||||||
{
|
{
|
||||||
@ -1225,7 +1274,8 @@ static bool nlm_filter_match(const struct str_list_head *nlm_list)
|
|||||||
LIST_FOREACH(nlm, nlm_list, next)
|
LIST_FOREACH(nlm, nlm_list, next)
|
||||||
{
|
{
|
||||||
bMatch = !strcmp(Name, nlm->str) || str2guid(nlm->str, &g) && !memcmp(&idNet, &g, sizeof(GUID));
|
bMatch = !strcmp(Name, nlm->str) || str2guid(nlm->str, &g) && !memcmp(&idNet, &g, sizeof(GUID));
|
||||||
if (bMatch) break;
|
if (bMatch)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1238,7 +1288,8 @@ static bool nlm_filter_match(const struct str_list_head *nlm_list)
|
|||||||
else
|
else
|
||||||
bRet = false;
|
bRet = false;
|
||||||
pNet->lpVtbl->Release(pNet);
|
pNet->lpVtbl->Release(pNet);
|
||||||
if (!bRet || bMatch) break;
|
if (!bRet || bMatch)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
pEnum->lpVtbl->Release(pEnum);
|
pEnum->lpVtbl->Release(pEnum);
|
||||||
}
|
}
|
||||||
@ -1267,9 +1318,11 @@ static bool wlan_filter_match(const struct str_list_head *ssid_list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
w_win32_error = WlanOpenHandle(2, NULL, &dwCurVersion, &hClient);
|
w_win32_error = WlanOpenHandle(2, NULL, &dwCurVersion, &hClient);
|
||||||
if (w_win32_error != ERROR_SUCCESS) goto fail;
|
if (w_win32_error != ERROR_SUCCESS)
|
||||||
|
goto fail;
|
||||||
w_win32_error = WlanEnumInterfaces(hClient, NULL, &pIfList);
|
w_win32_error = WlanEnumInterfaces(hClient, NULL, &pIfList);
|
||||||
if (w_win32_error != ERROR_SUCCESS) goto fail;
|
if (w_win32_error != ERROR_SUCCESS)
|
||||||
|
goto fail;
|
||||||
for (k = 0; k < pIfList->dwNumberOfItems; k++)
|
for (k = 0; k < pIfList->dwNumberOfItems; k++)
|
||||||
{
|
{
|
||||||
pIfInfo = pIfList->InterfaceInfo + k;
|
pIfInfo = pIfList->InterfaceInfo + k;
|
||||||
@ -1282,7 +1335,8 @@ static bool wlan_filter_match(const struct str_list_head *ssid_list)
|
|||||||
&connectInfoSize,
|
&connectInfoSize,
|
||||||
(PVOID *)&pConnectInfo,
|
(PVOID *)&pConnectInfo,
|
||||||
NULL);
|
NULL);
|
||||||
if (w_win32_error != ERROR_SUCCESS) goto fail;
|
if (w_win32_error != ERROR_SUCCESS)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
// printf("%s\n", pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID);
|
// printf("%s\n", pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID);
|
||||||
|
|
||||||
@ -1303,8 +1357,10 @@ static bool wlan_filter_match(const struct str_list_head *ssid_list)
|
|||||||
fail:
|
fail:
|
||||||
bRes = false;
|
bRes = false;
|
||||||
ex:
|
ex:
|
||||||
if (pIfList) WlanFreeMemory(pIfList);
|
if (pIfList)
|
||||||
if (hClient) WlanCloseHandle(hClient, 0);
|
WlanFreeMemory(pIfList);
|
||||||
|
if (hClient)
|
||||||
|
WlanCloseHandle(hClient, 0);
|
||||||
return bRes;
|
return bRes;
|
||||||
found:
|
found:
|
||||||
w_win32_error = 0;
|
w_win32_error = 0;
|
||||||
@ -1320,7 +1376,8 @@ bool logical_net_filter_match(void)
|
|||||||
static bool logical_net_filter_match_rate_limited(void)
|
static bool logical_net_filter_match_rate_limited(void)
|
||||||
{
|
{
|
||||||
DWORD dwTick = GetTickCount() / 1000;
|
DWORD dwTick = GetTickCount() / 1000;
|
||||||
if (logical_net_filter_tick == dwTick) return true;
|
if (logical_net_filter_tick == dwTick)
|
||||||
|
return true;
|
||||||
logical_net_filter_tick = dwTick;
|
logical_net_filter_tick = dwTick;
|
||||||
return logical_net_filter_match();
|
return logical_net_filter_match();
|
||||||
}
|
}
|
||||||
@ -1345,7 +1402,8 @@ static HANDLE windivert_init_filter(const char *filter, UINT64 flags)
|
|||||||
SetLastError(w_win32_error);
|
SetLastError(w_win32_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h != INVALID_HANDLE_VALUE) return h;
|
if (h != INVALID_HANDLE_VALUE)
|
||||||
|
return h;
|
||||||
|
|
||||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
NULL, w_win32_error, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPSTR)&errormessage, 0, NULL);
|
NULL, w_win32_error, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPSTR)&errormessage, 0, NULL);
|
||||||
@ -1506,9 +1564,12 @@ static int *rawsend_family_sock(sa_family_t family)
|
|||||||
{
|
{
|
||||||
switch (family)
|
switch (family)
|
||||||
{
|
{
|
||||||
case AF_INET: return &rawsend_sock4;
|
case AF_INET:
|
||||||
case AF_INET6: return &rawsend_sock6;
|
return &rawsend_sock4;
|
||||||
default: return NULL;
|
case AF_INET6:
|
||||||
|
return &rawsend_sock6;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1617,7 +1678,8 @@ static bool set_socket_fwmark(int sock, uint32_t fwmark)
|
|||||||
static int rawsend_socket(sa_family_t family)
|
static int rawsend_socket(sa_family_t family)
|
||||||
{
|
{
|
||||||
int *sock = rawsend_family_sock(family);
|
int *sock = rawsend_family_sock(family);
|
||||||
if (!sock) return -1;
|
if (!sock)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (*sock == -1)
|
if (*sock == -1)
|
||||||
{
|
{
|
||||||
@ -1660,7 +1722,7 @@ static int rawsend_socket(sa_family_t family)
|
|||||||
if (family == AF_INET6 && setsockopt(*sock, SOL_IPV6, IPV6_FREEBIND, &yes, sizeof(yes)) == -1)
|
if (family == AF_INET6 && setsockopt(*sock, SOL_IPV6, IPV6_FREEBIND, &yes, sizeof(yes)) == -1)
|
||||||
{
|
{
|
||||||
// DLOG_PERROR("rawsend: setsockopt(IPV6_FREEBIND)");
|
// DLOG_PERROR("rawsend: setsockopt(IPV6_FREEBIND)");
|
||||||
// dont error because it's supported only from kernel 4.15
|
// don't error because it's supported only from kernel 4.15
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -1673,21 +1735,23 @@ bool rawsend_preinit(bool bind_fix4, bool bind_fix6)
|
|||||||
{
|
{
|
||||||
b_bind_fix4 = bind_fix4;
|
b_bind_fix4 = bind_fix4;
|
||||||
b_bind_fix6 = bind_fix6;
|
b_bind_fix6 = bind_fix6;
|
||||||
// allow ipv6 disabled systems
|
// allow IPv6 disabled systems
|
||||||
return rawsend_socket(AF_INET) != -1 && (rawsend_socket(AF_INET6) != -1 || errno == EAFNOSUPPORT);
|
return rawsend_socket(AF_INET) != -1 && (rawsend_socket(AF_INET6) != -1 || errno == EAFNOSUPPORT);
|
||||||
}
|
}
|
||||||
bool rawsend(const struct sockaddr *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len)
|
bool rawsend(const struct sockaddr *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len)
|
||||||
{
|
{
|
||||||
ssize_t bytes;
|
ssize_t bytes;
|
||||||
int sock = rawsend_socket(dst->sa_family);
|
int sock = rawsend_socket(dst->sa_family);
|
||||||
if (sock==-1) return false;
|
if (sock == -1)
|
||||||
if (!set_socket_fwmark(sock,fwmark)) return false;
|
return false;
|
||||||
|
if (!set_socket_fwmark(sock, fwmark))
|
||||||
|
return false;
|
||||||
|
|
||||||
int salen = dst->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
int salen = dst->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||||
struct sockaddr_storage dst2;
|
struct sockaddr_storage dst2;
|
||||||
memcpy(&dst2, dst, salen);
|
memcpy(&dst2, dst, salen);
|
||||||
if (dst->sa_family == AF_INET6)
|
if (dst->sa_family == AF_INET6)
|
||||||
((struct sockaddr_in6 *)&dst2)->sin6_port = 0; // or will be EINVAL in linux
|
((struct sockaddr_in6 *)&dst2)->sin6_port = 0; // or will be EINVAL in Linux
|
||||||
|
|
||||||
#if defined(BSD)
|
#if defined(BSD)
|
||||||
bytes = rawsend_sendto_divert(dst->sa_family, sock, data, len);
|
bytes = rawsend_sendto_divert(dst->sa_family, sock, data, len);
|
||||||
@ -1705,11 +1769,13 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const
|
|||||||
switch (dst->sa_family)
|
switch (dst->sa_family)
|
||||||
{
|
{
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
if (!b_bind_fix4) goto nofix;
|
if (!b_bind_fix4)
|
||||||
|
goto nofix;
|
||||||
extract_endpoints(data, NULL, NULL, NULL, &sa_src, NULL);
|
extract_endpoints(data, NULL, NULL, NULL, &sa_src, NULL);
|
||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
if (!b_bind_fix6) goto nofix;
|
if (!b_bind_fix6)
|
||||||
|
goto nofix;
|
||||||
extract_endpoints(NULL, data, NULL, NULL, &sa_src, NULL);
|
extract_endpoints(NULL, data, NULL, NULL, &sa_src, NULL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1763,7 +1829,6 @@ bool rawsend_queue(struct rawpacket_tailhead *q)
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling
|
// return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling
|
||||||
// ttl = TTL of incoming packet
|
// ttl = TTL of incoming packet
|
||||||
uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
|
uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
|
||||||
@ -1786,10 +1851,13 @@ uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
|
|||||||
path = orig - ttl;
|
path = orig - ttl;
|
||||||
|
|
||||||
fake = path > attl->delta ? path - attl->delta : attl->min;
|
fake = path > attl->delta ? path - attl->delta : attl->min;
|
||||||
if (fake<attl->min) fake=attl->min;
|
if (fake < attl->min)
|
||||||
else if (fake>attl->max) fake=attl->max;
|
fake = attl->min;
|
||||||
|
else if (fake > attl->max)
|
||||||
|
fake = attl->max;
|
||||||
|
|
||||||
if (fake>=path) return 0;
|
if (fake >= path)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return fake;
|
return fake;
|
||||||
}
|
}
|
||||||
@ -1836,7 +1904,6 @@ void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr)
|
void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr)
|
||||||
{
|
{
|
||||||
if (!(verdict & VERDICT_NOCSUM))
|
if (!(verdict & VERDICT_NOCSUM))
|
||||||
@ -1844,7 +1911,7 @@ void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transpo
|
|||||||
// always fix csum for windivert. original can be partial or bad
|
// always fix csum for windivert. original can be partial or bad
|
||||||
#ifndef __CYGWIN__
|
#ifndef __CYGWIN__
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
// FreeBSD tend to pass ipv6 frames with wrong checksum
|
// FreeBSD tend to pass IPv6 frames with wrong checksum
|
||||||
if ((verdict & VERDICT_MASK) == VERDICT_MODIFY || ip6hdr)
|
if ((verdict & VERDICT_MASK) == VERDICT_MODIFY || ip6hdr)
|
||||||
#else
|
#else
|
||||||
// if original packet was tampered earlier it needs checksum fixed
|
// if original packet was tampered earlier it needs checksum fixed
|
||||||
@ -1861,7 +1928,7 @@ void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transpo
|
|||||||
// always fix csum for windivert. original can be partial or bad
|
// always fix csum for windivert. original can be partial or bad
|
||||||
#ifndef __CYGWIN__
|
#ifndef __CYGWIN__
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
// FreeBSD tend to pass ipv6 frames with wrong checksum
|
// FreeBSD tend to pass IPv6 frames with wrong checksum
|
||||||
if ((verdict & VERDICT_MASK) == VERDICT_MODIFY || ip6hdr)
|
if ((verdict & VERDICT_MASK) == VERDICT_MODIFY || ip6hdr)
|
||||||
#else
|
#else
|
||||||
// if original packet was tampered earlier it needs checksum fixed
|
// if original packet was tampered earlier it needs checksum fixed
|
||||||
|
@ -100,7 +100,6 @@ bool prepare_tcp_segment(
|
|||||||
const void *data, uint16_t len,
|
const void *data, uint16_t len,
|
||||||
uint8_t *buf, size_t *buflen);
|
uint8_t *buf, size_t *buflen);
|
||||||
|
|
||||||
|
|
||||||
bool prepare_udp_segment4(
|
bool prepare_udp_segment4(
|
||||||
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
||||||
uint8_t ttl,
|
uint8_t ttl,
|
||||||
@ -225,7 +224,12 @@ typedef struct
|
|||||||
#define AUTOTTL_DEFAULT_MIN 3
|
#define AUTOTTL_DEFAULT_MIN 3
|
||||||
#define AUTOTTL_DEFAULT_MAX 20
|
#define AUTOTTL_DEFAULT_MAX 20
|
||||||
#define AUTOTTL_ENABLED(a) (!!(a).delta)
|
#define AUTOTTL_ENABLED(a) (!!(a).delta)
|
||||||
#define AUTOTTL_SET_DEFAULT(a) {(a).delta=AUTOTTL_DEFAULT_DELTA; (a).min=AUTOTTL_DEFAULT_MIN; (a).max=AUTOTTL_DEFAULT_MAX;}
|
#define AUTOTTL_SET_DEFAULT(a) \
|
||||||
|
{ \
|
||||||
|
(a).delta = AUTOTTL_DEFAULT_DELTA; \
|
||||||
|
(a).min = AUTOTTL_DEFAULT_MIN; \
|
||||||
|
(a).max = AUTOTTL_DEFAULT_MAX; \
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t autottl_guess(uint8_t ttl, const autottl *attl);
|
uint8_t autottl_guess(uint8_t ttl, const autottl *attl);
|
||||||
void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6);
|
void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6);
|
||||||
|
195
nfq/desync.c
195
nfq/desync.c
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
const char *fake_http_request_default = "GET / HTTP/1.1\r\nHost: www.iana.org\r\n"
|
const char *fake_http_request_default = "GET / HTTP/1.1\r\nHost: www.iana.org\r\n"
|
||||||
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0\r\n"
|
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0\r\n"
|
||||||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n"
|
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n"
|
||||||
@ -59,8 +58,7 @@ const uint8_t fake_tls_clienthello_default[648] = {
|
|||||||
0x64, 0x2f, 0x97, 0xd0, 0x6a, 0x06, 0x36, 0xcd, 0x25, 0xda, 0x51, 0xab, 0xd6, 0xf7, 0x5e, 0xeb,
|
0x64, 0x2f, 0x97, 0xd0, 0x6a, 0x06, 0x36, 0xcd, 0x25, 0xda, 0x51, 0xab, 0xd6, 0xf7, 0x5e, 0xeb,
|
||||||
0xd4, 0x03, 0x39, 0xa4, 0xc4, 0x2a, 0x9c, 0x17, 0xe8, 0xb0, 0x9f, 0xc0, 0xd3, 0x8c, 0x76, 0xdd,
|
0xd4, 0x03, 0x39, 0xa4, 0xc4, 0x2a, 0x9c, 0x17, 0xe8, 0xb0, 0x9f, 0xc0, 0xd3, 0x8c, 0x76, 0xdd,
|
||||||
0xa1, 0x0b, 0x76, 0x9f, 0x23, 0xfa, 0xed, 0xfb, 0xd7, 0x78, 0x0f, 0x00, 0xf7, 0x45, 0x03, 0x04,
|
0xa1, 0x0b, 0x76, 0x9f, 0x23, 0xfa, 0xed, 0xfb, 0xd7, 0x78, 0x0f, 0x00, 0xf7, 0x45, 0x03, 0x04,
|
||||||
0x84,0x66,0x6b,0xec,0xc7,0xed,0xbc,0xe4
|
0x84, 0x66, 0x6b, 0xec, 0xc7, 0xed, 0xbc, 0xe4};
|
||||||
};
|
|
||||||
|
|
||||||
static const char *tld[] = {"com", "org", "net", "edu", "gov", "biz"};
|
static const char *tld[] = {"com", "org", "net", "edu", "gov", "biz"};
|
||||||
void randomize_default_tls_payload(uint8_t *p)
|
void randomize_default_tls_payload(uint8_t *p)
|
||||||
@ -145,7 +143,6 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
|
|||||||
return DESYNC_INVALID;
|
return DESYNC_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// auto creates internal socket and uses it for subsequent calls
|
// auto creates internal socket and uses it for subsequent calls
|
||||||
static bool rawsend_rep(const struct sockaddr *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len)
|
static bool rawsend_rep(const struct sockaddr *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len)
|
||||||
{
|
{
|
||||||
@ -155,15 +152,18 @@ static bool rawsend_rep(const struct sockaddr* dst,uint32_t fwmark,const char *i
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint64_t cutoff_get_limit(const t_ctrack *ctrack, char mode)
|
static uint64_t cutoff_get_limit(const t_ctrack *ctrack, char mode)
|
||||||
{
|
{
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case 'n': return ctrack->pcounter_orig;
|
case 'n':
|
||||||
case 'd': return ctrack->pdcounter_orig;
|
return ctrack->pcounter_orig;
|
||||||
case 's': return ctrack->seq_last - ctrack->seq0;
|
case 'd':
|
||||||
default: return 0;
|
return ctrack->pdcounter_orig;
|
||||||
|
case 's':
|
||||||
|
return ctrack->seq_last - ctrack->seq0;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static bool cutoff_test(const t_ctrack *ctrack, uint64_t cutoff, char mode)
|
static bool cutoff_test(const t_ctrack *ctrack, uint64_t cutoff, char mode)
|
||||||
@ -181,7 +181,7 @@ static void maybe_cutoff(t_ctrack *ctrack, uint8_t proto)
|
|||||||
// we do not need conntrack entry anymore if all cutoff conditions are either not defined or reached
|
// we do not need conntrack entry anymore if all cutoff conditions are either not defined or reached
|
||||||
// do not drop udp entry because it will be recreated when next packet arrives
|
// do not drop udp entry because it will be recreated when next packet arrives
|
||||||
if (proto == IPPROTO_TCP)
|
if (proto == IPPROTO_TCP)
|
||||||
ctrack->b_cutoff |= \
|
ctrack->b_cutoff |=
|
||||||
(!params.wssize || ctrack->b_wssize_cutoff) &&
|
(!params.wssize || ctrack->b_wssize_cutoff) &&
|
||||||
(!params.desync_cutoff || ctrack->b_desync_cutoff) &&
|
(!params.desync_cutoff || ctrack->b_desync_cutoff) &&
|
||||||
(!ctrack->hostname_ah_check || ctrack->req_retrans_counter == RETRANS_COUNTER_STOP) &&
|
(!ctrack->hostname_ah_check || ctrack->req_retrans_counter == RETRANS_COUNTER_STOP) &&
|
||||||
@ -325,7 +325,6 @@ static bool send_delayed(t_ctrack *ctrack)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
|
static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
|
||||||
{
|
{
|
||||||
ReasmClear(reasm);
|
ReasmClear(reasm);
|
||||||
@ -393,7 +392,6 @@ static void reasm_orig_fin(t_ctrack *ctrack)
|
|||||||
reasm_orig_stop(ctrack, "reassemble session finished\n");
|
reasm_orig_stop(ctrack, "reassemble session finished\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, struct ip *ip, struct ip6_hdr *ip6, uint8_t proto, struct udphdr *udp, struct tcphdr *tcp, size_t *len_pkt)
|
static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, struct ip *ip, struct ip6_hdr *ip6, uint8_t proto, struct udphdr *udp, struct tcphdr *tcp, size_t *len_pkt)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@ -403,7 +401,7 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, struct ip *ip, struct
|
|||||||
// we also can't use fooling because DPI would accept fooled packets
|
// we also can't use fooling because DPI would accept fooled packets
|
||||||
if (ctrack && ctrack->pcounter_orig == 1)
|
if (ctrack && ctrack->pcounter_orig == 1)
|
||||||
{
|
{
|
||||||
DLOG("applying linux postnat conntrack workaround\n");
|
DLOG("applying Linux postnat conntrack workaround\n");
|
||||||
if (proto == IPPROTO_UDP && udp && len_pkt)
|
if (proto == IPPROTO_UDP && udp && len_pkt)
|
||||||
{
|
{
|
||||||
// make malformed udp packet with zero length and invalid checksum
|
// make malformed udp packet with zero length and invalid checksum
|
||||||
@ -426,7 +424,8 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, struct ip *ip, struct
|
|||||||
// make flags invalid and also corrupt checksum
|
// make flags invalid and also corrupt checksum
|
||||||
tcp->th_flags = 0;
|
tcp->th_flags = 0;
|
||||||
}
|
}
|
||||||
if (ip) ip->ip_sum ^= htons(0xBEAF);
|
if (ip)
|
||||||
|
ip->ip_sum ^= htons(0xBEAF);
|
||||||
return VERDICT_MODIFY | VERDICT_NOCSUM;
|
return VERDICT_MODIFY | VERDICT_NOCSUM;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -442,7 +441,6 @@ static uint8_t ct_new_postnat_fix_udp(const t_ctrack *ctrack, struct ip *ip, str
|
|||||||
return ct_new_postnat_fix(ctrack, ip, ip6, IPPROTO_UDP, udphdr, NULL, len_pkt);
|
return ct_new_postnat_fix(ctrack, ip, ip6, IPPROTO_UDP, udphdr, NULL, len_pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool check_desync_interval(const t_ctrack *ctrack)
|
static bool check_desync_interval(const t_ctrack *ctrack)
|
||||||
{
|
{
|
||||||
if (params.desync_start)
|
if (params.desync_start)
|
||||||
@ -519,7 +517,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
uint8_t verdict = VERDICT_PASS;
|
uint8_t verdict = VERDICT_PASS;
|
||||||
|
|
||||||
// additional safety check
|
// additional safety check
|
||||||
if (!!ip == !!ip6hdr) return verdict;
|
if (!!ip == !!ip6hdr)
|
||||||
|
return verdict;
|
||||||
|
|
||||||
t_ctrack *ctrack = NULL, *ctrack_replay = NULL;
|
t_ctrack *ctrack = NULL, *ctrack_replay = NULL;
|
||||||
bool bReverse = false;
|
bool bReverse = false;
|
||||||
@ -610,8 +609,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
}
|
}
|
||||||
if (bFail)
|
if (bFail)
|
||||||
auto_hostlist_failed(ctrack->hostname);
|
auto_hostlist_failed(ctrack->hostname);
|
||||||
else
|
else if (len_payload)
|
||||||
if (len_payload)
|
|
||||||
auto_hostlist_reset_fail_counter(ctrack->hostname);
|
auto_hostlist_reset_fail_counter(ctrack->hostname);
|
||||||
if (tcphdr->th_flags & TH_RST)
|
if (tcphdr->th_flags & TH_RST)
|
||||||
ConntrackClearHostname(ctrack); // do not react to further dup RSTs
|
ConntrackClearHostname(ctrack); // do not react to further dup RSTs
|
||||||
@ -620,7 +618,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
return verdict; // nothing to do. do not waste cpu
|
return verdict; // nothing to do. do not waste cpu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (params.wssize)
|
if (params.wssize)
|
||||||
{
|
{
|
||||||
if (ctrack)
|
if (ctrack)
|
||||||
@ -631,7 +628,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (params.wssize_cutoff) DLOG("wssize-cutoff not reached (mode %c): %llu/%u\n", params.wssize_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,params.wssize_cutoff_mode), params.wssize_cutoff);
|
if (params.wssize_cutoff)
|
||||||
|
DLOG("wssize-cutoff not reached (mode %c): %llu/%u\n", params.wssize_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack, params.wssize_cutoff_mode), params.wssize_cutoff);
|
||||||
tcp_rewrite_winsize(tcphdr, params.wssize, params.wsscale);
|
tcp_rewrite_winsize(tcphdr, params.wssize, params.wsscale);
|
||||||
verdict = VERDICT_MODIFY;
|
verdict = VERDICT_MODIFY;
|
||||||
}
|
}
|
||||||
@ -687,7 +685,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
DLOG("sending SYN with fake data : ");
|
DLOG("sending SYN with fake data : ");
|
||||||
hexdump_limited_dlog(params.fake_syndata,params.fake_syndata_size,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(params.fake_syndata, params.fake_syndata_size, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
verdict = ct_new_postnat_fix_tcp(ctrack, ip, ip6hdr, tcphdr);
|
verdict = ct_new_postnat_fix_tcp(ctrack, ip, ip6hdr, tcphdr);
|
||||||
@ -700,10 +699,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start and cutoff limiters
|
// start and cutoff limiters
|
||||||
if (!process_desync_interval(ctrack)) return verdict;
|
if (!process_desync_interval(ctrack))
|
||||||
|
return verdict;
|
||||||
} // !replay
|
} // !replay
|
||||||
|
|
||||||
if (!params.wssize && params.desync_mode==DESYNC_NONE && !params.hostcase && !params.hostnospace && !params.domcase && !*params.hostlist_auto_filename) return verdict; // nothing to do. do not waste cpu
|
if (!params.wssize && params.desync_mode == DESYNC_NONE && !params.hostcase && !params.hostnospace && !params.domcase && !*params.hostlist_auto_filename)
|
||||||
|
return verdict; // nothing to do. do not waste cpu
|
||||||
|
|
||||||
if (!(tcphdr->th_flags & TH_SYN) && len_payload)
|
if (!(tcphdr->th_flags & TH_SYN) && len_payload)
|
||||||
{
|
{
|
||||||
@ -734,7 +735,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
if ((bIsHttp = IsHttp(rdata_payload, rlen_payload)))
|
if ((bIsHttp = IsHttp(rdata_payload, rlen_payload)))
|
||||||
{
|
{
|
||||||
DLOG("packet contains HTTP request\n");
|
DLOG("packet contains HTTP request\n");
|
||||||
if (ctrack && !ctrack->l7proto) ctrack->l7proto = HTTP;
|
if (ctrack && !ctrack->l7proto)
|
||||||
|
ctrack->l7proto = HTTP;
|
||||||
|
|
||||||
// we do not reassemble http
|
// we do not reassemble http
|
||||||
reasm_orig_cancel(ctrack);
|
reasm_orig_cancel(ctrack);
|
||||||
@ -774,7 +776,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
|
|
||||||
if (ctrack)
|
if (ctrack)
|
||||||
{
|
{
|
||||||
if (!ctrack->l7proto) ctrack->l7proto = TLS;
|
if (!ctrack->l7proto)
|
||||||
|
ctrack->l7proto = TLS;
|
||||||
// do not reasm retransmissions
|
// do not reasm retransmissions
|
||||||
if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_orig) && !ctrack->req_seq_abandoned &&
|
if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_orig) && !ctrack->req_seq_abandoned &&
|
||||||
!(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
|
!(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
|
||||||
@ -785,7 +788,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
reasm_orig_cancel(ctrack);
|
reasm_orig_cancel(ctrack);
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (!ctrack->req_seq_finalized)
|
if (!ctrack->req_seq_finalized)
|
||||||
{
|
{
|
||||||
@ -801,7 +803,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
DLOG("req retrans : seq interval %u-%u\n", ctrack->req_seq_start, ctrack->req_seq_end);
|
DLOG("req retrans : seq interval %u-%u\n", ctrack->req_seq_start, ctrack->req_seq_end);
|
||||||
ctrack->req_seq_finalized |= bReqFull;
|
ctrack->req_seq_finalized |= bReqFull;
|
||||||
}
|
}
|
||||||
if (bReqFull || ReasmIsEmpty(&ctrack->reasm_orig)) forced_wssize_cutoff(ctrack);
|
if (bReqFull || ReasmIsEmpty(&ctrack->reasm_orig))
|
||||||
|
forced_wssize_cutoff(ctrack);
|
||||||
|
|
||||||
if (!ReasmIsEmpty(&ctrack->reasm_orig))
|
if (!ReasmIsEmpty(&ctrack->reasm_orig))
|
||||||
{
|
{
|
||||||
@ -847,7 +850,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
{
|
{
|
||||||
uint32_t dseq = ctrack->seq_last - ctrack->req_seq_end;
|
uint32_t dseq = ctrack->seq_last - ctrack->req_seq_end;
|
||||||
// do not react to 32-bit overflowed sequence numbers. allow 16 Mb grace window then cutoff.
|
// do not react to 32-bit overflowed sequence numbers. allow 16 Mb grace window then cutoff.
|
||||||
if (dseq>=0x1000000 && !(dseq & 0x80000000)) ctrack->req_seq_abandoned=true;
|
if (dseq >= 0x1000000 && !(dseq & 0x80000000))
|
||||||
|
ctrack->req_seq_abandoned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bHaveHost)
|
if (bHaveHost)
|
||||||
@ -865,7 +869,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
ctrack_replay->hostname_ah_check = *params.hostlist_auto_filename && !bBypass;
|
ctrack_replay->hostname_ah_check = *params.hostlist_auto_filename && !bBypass;
|
||||||
if (ctrack_replay->hostname_ah_check)
|
if (ctrack_replay->hostname_ah_check)
|
||||||
{
|
{
|
||||||
if (!ctrack_replay->hostname) ctrack_replay->hostname=strdup(host);
|
if (!ctrack_replay->hostname)
|
||||||
|
ctrack_replay->hostname = strdup(host);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ctrack_stop_retrans_counter(ctrack_replay);
|
ctrack_stop_retrans_counter(ctrack_replay);
|
||||||
@ -878,7 +883,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
|
|
||||||
if (!bKnownProtocol)
|
if (!bKnownProtocol)
|
||||||
{
|
{
|
||||||
if (!params.desync_any_proto) return verdict;
|
if (!params.desync_any_proto)
|
||||||
|
return verdict;
|
||||||
DLOG("applying tampering to unknown protocol\n");
|
DLOG("applying tampering to unknown protocol\n");
|
||||||
fake = params.fake_unknown;
|
fake = params.fake_unknown;
|
||||||
fake_size = params.fake_unknown_size;
|
fake_size = params.fake_unknown_size;
|
||||||
@ -919,7 +925,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.desync_mode==DESYNC_NONE) return verdict;
|
if (params.desync_mode == DESYNC_NONE)
|
||||||
|
return verdict;
|
||||||
|
|
||||||
if (params.debug)
|
if (params.debug)
|
||||||
{
|
{
|
||||||
@ -929,7 +936,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
DLOG("dpi desync src=%s dst=%s\n", s1, s2);
|
DLOG("dpi desync src=%s dst=%s\n", s1, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!split_pos || split_pos>rlen_payload) split_pos=1;
|
if (!split_pos || split_pos > rlen_payload)
|
||||||
|
split_pos = 1;
|
||||||
split_pos = pos_normalize(split_pos, reasm_offset, len_payload);
|
split_pos = pos_normalize(split_pos, reasm_offset, len_payload);
|
||||||
|
|
||||||
enum dpi_desync_mode desync_mode = params.desync_mode;
|
enum dpi_desync_mode desync_mode = params.desync_mode;
|
||||||
@ -953,7 +961,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DESYNC_FAKE:
|
case DESYNC_FAKE:
|
||||||
if (reasm_offset) break;
|
if (reasm_offset)
|
||||||
|
break;
|
||||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
|
||||||
ttl_fake, params.desync_fooling_mode, params.desync_badseq_increment, params.desync_badseq_ack_increment,
|
ttl_fake, params.desync_fooling_mode, params.desync_badseq_increment, params.desync_badseq_ack_increment,
|
||||||
fake, fake_size, pkt1, &pkt1_len))
|
fake, fake_size, pkt1, &pkt1_len))
|
||||||
@ -961,12 +970,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
DLOG("sending fake request : ");
|
DLOG("sending fake request : ");
|
||||||
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(fake, fake_size, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
b = true;
|
b = true;
|
||||||
break;
|
break;
|
||||||
case DESYNC_RST:
|
case DESYNC_RST:
|
||||||
case DESYNC_RSTACK:
|
case DESYNC_RSTACK:
|
||||||
if (reasm_offset) break;
|
if (reasm_offset)
|
||||||
|
break;
|
||||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (desync_mode == DESYNC_RSTACK ? TH_ACK : 0), tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (desync_mode == DESYNC_RSTACK ? TH_ACK : 0), tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
|
||||||
ttl_fake, params.desync_fooling_mode, params.desync_badseq_increment, params.desync_badseq_ack_increment,
|
ttl_fake, params.desync_fooling_mode, params.desync_badseq_increment, params.desync_badseq_ack_increment,
|
||||||
NULL, 0, pkt1, &pkt1_len))
|
NULL, 0, pkt1, &pkt1_len))
|
||||||
@ -979,7 +990,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
case DESYNC_HOPBYHOP:
|
case DESYNC_HOPBYHOP:
|
||||||
case DESYNC_DESTOPT:
|
case DESYNC_DESTOPT:
|
||||||
case DESYNC_IPFRAG1:
|
case DESYNC_IPFRAG1:
|
||||||
fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
|
fooling_orig = (desync_mode == DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode == DESYNC_DESTOPT) ? FOOL_DESTOPT
|
||||||
|
: FOOL_IPFRAG1;
|
||||||
desync_mode = params.desync_mode2;
|
desync_mode = params.desync_mode2;
|
||||||
if (ip6hdr && (desync_mode == DESYNC_NONE || !desync_valid_second_stage_tcp(desync_mode) ||
|
if (ip6hdr && (desync_mode == DESYNC_NONE || !desync_valid_second_stage_tcp(desync_mode) ||
|
||||||
(!split_pos && (desync_mode == DESYNC_SPLIT || desync_mode == DESYNC_SPLIT2 || desync_mode == DESYNC_DISORDER || desync_mode == DESYNC_DISORDER2))))
|
(!split_pos && (desync_mode == DESYNC_SPLIT || desync_mode == DESYNC_SPLIT2 || desync_mode == DESYNC_DISORDER || desync_mode == DESYNC_DISORDER2))))
|
||||||
@ -1057,12 +1069,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
seg, seg_len, pkt1, &pkt1_len))
|
seg, seg_len, pkt1, &pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ", split_pos, len_payload - 1, len_payload - split_pos, params.desync_seqovl);
|
DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ", split_pos, len_payload - 1, len_payload - split_pos, params.desync_seqovl);
|
||||||
hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(seg, seg_len, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (desync_mode == DESYNC_DISORDER)
|
if (desync_mode == DESYNC_DISORDER)
|
||||||
{
|
{
|
||||||
seg_len = sizeof(fakeseg);
|
seg_len = sizeof(fakeseg);
|
||||||
@ -1071,7 +1083,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
zeropkt, split_pos, fakeseg, &seg_len))
|
zeropkt, split_pos, fakeseg, &seg_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
||||||
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(zeropkt, split_pos, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len))
|
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
@ -1082,14 +1095,16 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
data_payload, split_pos, pkt1, &pkt1_len))
|
data_payload, split_pos, pkt1, &pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
||||||
hexdump_limited_dlog(data_payload,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(data_payload, split_pos, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
|
|
||||||
if (desync_mode == DESYNC_DISORDER)
|
if (desync_mode == DESYNC_DISORDER)
|
||||||
{
|
{
|
||||||
DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
||||||
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(zeropkt, split_pos, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len))
|
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
@ -1112,7 +1127,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
zeropkt, split_pos, fakeseg, &fakeseg_len))
|
zeropkt, split_pos, fakeseg, &fakeseg_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
||||||
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(zeropkt, split_pos, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len))
|
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
@ -1140,14 +1156,16 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
seg, seg_len, pkt1, &pkt1_len))
|
seg, seg_len, pkt1, &pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
DLOG("sending 1st tcp segment 0-%zu len=%zu seqovl=%u : ", split_pos - 1, split_pos, params.desync_seqovl);
|
DLOG("sending 1st tcp segment 0-%zu len=%zu seqovl=%u : ", split_pos - 1, split_pos, params.desync_seqovl);
|
||||||
hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(seg, seg_len, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
|
|
||||||
if (desync_mode == DESYNC_SPLIT)
|
if (desync_mode == DESYNC_SPLIT)
|
||||||
{
|
{
|
||||||
DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
|
||||||
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(zeropkt, split_pos, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len))
|
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
@ -1159,7 +1177,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
data_payload + split_pos, len_payload - split_pos, pkt1, &pkt1_len))
|
data_payload + split_pos, len_payload - split_pos, pkt1, &pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ", split_pos, len_payload - 1, len_payload - split_pos);
|
DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ", split_pos, len_payload - 1, len_payload - split_pos);
|
||||||
hexdump_limited_dlog(data_payload+split_pos,len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(data_payload + split_pos, len_payload - split_pos, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
@ -1198,12 +1217,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
return verdict;
|
return verdict;
|
||||||
|
|
||||||
DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos - 1, ipfrag_pos);
|
DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos - 1, ipfrag_pos);
|
||||||
hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(pkt1, pkt1_len, IP_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
|
|
||||||
DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, transport_len - 1, transport_len - ipfrag_pos);
|
DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, transport_len - 1, transport_len - ipfrag_pos);
|
||||||
hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(pkt2, pkt2_len, IP_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt2, pkt2_len))
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt2, pkt2_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
|
|
||||||
@ -1212,7 +1233,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return verdict;
|
return verdict;
|
||||||
@ -1239,10 +1259,12 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
uint8_t verdict = VERDICT_PASS;
|
uint8_t verdict = VERDICT_PASS;
|
||||||
|
|
||||||
// additional safety check
|
// additional safety check
|
||||||
if (!!ip == !!ip6hdr) return verdict;
|
if (!!ip == !!ip6hdr)
|
||||||
|
return verdict;
|
||||||
|
|
||||||
// no need to desync middle packets in reasm session
|
// no need to desync middle packets in reasm session
|
||||||
if (reasm_offset) return verdict;
|
if (reasm_offset)
|
||||||
|
return verdict;
|
||||||
|
|
||||||
t_ctrack *ctrack = NULL, *ctrack_replay = NULL;
|
t_ctrack *ctrack = NULL, *ctrack_replay = NULL;
|
||||||
bool bReverse = false;
|
bool bReverse = false;
|
||||||
@ -1274,17 +1296,22 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
// ConntrackPoolDump(¶ms.conntrack);
|
// ConntrackPoolDump(¶ms.conntrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bReverse) return verdict; // nothing to do. do not waste cpu
|
if (bReverse)
|
||||||
|
return verdict; // nothing to do. do not waste cpu
|
||||||
|
|
||||||
if (params.desync_mode==DESYNC_NONE && !*params.hostlist_auto_filename) return verdict; // do not waste cpu
|
if (params.desync_mode == DESYNC_NONE && !*params.hostlist_auto_filename)
|
||||||
|
return verdict; // do not waste cpu
|
||||||
|
|
||||||
// start and cutoff limiters
|
// start and cutoff limiters
|
||||||
if (!replay && !process_desync_interval(ctrack)) return verdict;
|
if (!replay && !process_desync_interval(ctrack))
|
||||||
|
return verdict;
|
||||||
|
|
||||||
uint32_t desync_fwmark = fwmark | params.desync_fwmark;
|
uint32_t desync_fwmark = fwmark | params.desync_fwmark;
|
||||||
ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim;
|
ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim;
|
||||||
if (ip6hdr) ttl_fake = params.desync_ttl6 ? params.desync_ttl6 : ttl_orig;
|
if (ip6hdr)
|
||||||
else ttl_fake = params.desync_ttl ? params.desync_ttl : ttl_orig;
|
ttl_fake = params.desync_ttl6 ? params.desync_ttl6 : ttl_orig;
|
||||||
|
else
|
||||||
|
ttl_fake = params.desync_ttl ? params.desync_ttl : ttl_orig;
|
||||||
extract_endpoints(ip, ip6hdr, NULL, udphdr, &src, &dst);
|
extract_endpoints(ip, ip6hdr, NULL, udphdr, &src, &dst);
|
||||||
|
|
||||||
if (len_payload)
|
if (len_payload)
|
||||||
@ -1299,7 +1326,8 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
if (IsQUICInitial(data_payload, len_payload))
|
if (IsQUICInitial(data_payload, len_payload))
|
||||||
{
|
{
|
||||||
DLOG("packet contains QUIC initial\n");
|
DLOG("packet contains QUIC initial\n");
|
||||||
if (ctrack && !ctrack->l7proto) ctrack->l7proto = QUIC;
|
if (ctrack && !ctrack->l7proto)
|
||||||
|
ctrack->l7proto = QUIC;
|
||||||
|
|
||||||
uint8_t clean[16384], *pclean;
|
uint8_t clean[16384], *pclean;
|
||||||
size_t clean_len;
|
size_t clean_len;
|
||||||
@ -1386,19 +1414,22 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict;
|
if (!quic_reasm_cancel(ctrack, "QUIC initial without ClientHello"))
|
||||||
|
return verdict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// defrag failed
|
// defrag failed
|
||||||
if (!quic_reasm_cancel(ctrack,"QUIC initial defrag CRYPTO failed")) return verdict;
|
if (!quic_reasm_cancel(ctrack, "QUIC initial defrag CRYPTO failed"))
|
||||||
|
return verdict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// decrypt failed
|
// decrypt failed
|
||||||
if (!quic_reasm_cancel(ctrack,"QUIC initial decryption failed")) return verdict;
|
if (!quic_reasm_cancel(ctrack, "QUIC initial decryption failed"))
|
||||||
|
return verdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
fake = params.fake_quic;
|
fake = params.fake_quic;
|
||||||
@ -1414,8 +1445,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
|
|
||||||
if (IsWireguardHandshakeInitiation(data_payload, len_payload))
|
if (IsWireguardHandshakeInitiation(data_payload, len_payload))
|
||||||
{
|
{
|
||||||
DLOG("packet contains wireguard handshake initiation\n");
|
DLOG("packet contains WireGuard handshake initiation\n");
|
||||||
if (ctrack && !ctrack->l7proto) ctrack->l7proto = WIREGUARD;
|
if (ctrack && !ctrack->l7proto)
|
||||||
|
ctrack->l7proto = WIREGUARD;
|
||||||
fake = params.fake_wg;
|
fake = params.fake_wg;
|
||||||
fake_size = params.fake_wg_size;
|
fake_size = params.fake_wg_size;
|
||||||
bKnownProtocol = true;
|
bKnownProtocol = true;
|
||||||
@ -1423,14 +1455,16 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
else if (IsDhtD1(data_payload, len_payload))
|
else if (IsDhtD1(data_payload, len_payload))
|
||||||
{
|
{
|
||||||
DLOG("packet contains DHT d1...e\n");
|
DLOG("packet contains DHT d1...e\n");
|
||||||
if (ctrack && !ctrack->l7proto) ctrack->l7proto = DHT;
|
if (ctrack && !ctrack->l7proto)
|
||||||
|
ctrack->l7proto = DHT;
|
||||||
fake = params.fake_dht;
|
fake = params.fake_dht;
|
||||||
fake_size = params.fake_dht_size;
|
fake_size = params.fake_dht_size;
|
||||||
bKnownProtocol = true;
|
bKnownProtocol = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!params.desync_any_proto) return verdict;
|
if (!params.desync_any_proto)
|
||||||
|
return verdict;
|
||||||
DLOG("applying tampering to unknown protocol\n");
|
DLOG("applying tampering to unknown protocol\n");
|
||||||
fake = params.fake_unknown_udp;
|
fake = params.fake_unknown_udp;
|
||||||
fake_size = params.fake_unknown_udp_size;
|
fake_size = params.fake_unknown_udp_size;
|
||||||
@ -1489,7 +1523,8 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len))
|
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
DLOG("sending fake request : ");
|
DLOG("sending fake request : ");
|
||||||
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(fake, fake_size, PKTDATA_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
b = true;
|
b = true;
|
||||||
@ -1497,7 +1532,8 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
case DESYNC_HOPBYHOP:
|
case DESYNC_HOPBYHOP:
|
||||||
case DESYNC_DESTOPT:
|
case DESYNC_DESTOPT:
|
||||||
case DESYNC_IPFRAG1:
|
case DESYNC_IPFRAG1:
|
||||||
fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
|
fooling_orig = (desync_mode == DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode == DESYNC_DESTOPT) ? FOOL_DESTOPT
|
||||||
|
: FOOL_IPFRAG1;
|
||||||
if (ip6hdr && (params.desync_mode2 == DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2)))
|
if (ip6hdr && (params.desync_mode2 == DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2)))
|
||||||
{
|
{
|
||||||
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
|
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
|
||||||
@ -1607,12 +1643,14 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
return verdict;
|
return verdict;
|
||||||
|
|
||||||
DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos - 1, ipfrag_pos);
|
DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos - 1, ipfrag_pos);
|
||||||
hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(pkt1, pkt1_len, IP_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
|
|
||||||
DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, transport_len - 1, transport_len - ipfrag_pos);
|
DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, transport_len - 1, transport_len - ipfrag_pos);
|
||||||
hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(pkt2, pkt2_len, IP_MAXDUMP);
|
||||||
|
DLOG("\n");
|
||||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt2, pkt2_len))
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt2, pkt2_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
|
|
||||||
@ -1621,18 +1659,17 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void packet_debug(bool replay, uint8_t proto, const struct ip *ip, const struct ip6_hdr *ip6hdr, const struct tcphdr *tcphdr, const struct udphdr *udphdr, const uint8_t *data_payload, size_t len_payload)
|
static void packet_debug(bool replay, uint8_t proto, const struct ip *ip, const struct ip6_hdr *ip6hdr, const struct tcphdr *tcphdr, const struct udphdr *udphdr, const uint8_t *data_payload, size_t len_payload)
|
||||||
{
|
{
|
||||||
if (params.debug)
|
if (params.debug)
|
||||||
{
|
{
|
||||||
if (replay) DLOG("REPLAY ");
|
if (replay)
|
||||||
|
DLOG("REPLAY ");
|
||||||
if (ip)
|
if (ip)
|
||||||
{
|
{
|
||||||
char s[66];
|
char s[66];
|
||||||
@ -1650,22 +1687,30 @@ static void packet_debug(bool replay, uint8_t proto, const struct ip *ip, const
|
|||||||
char s[80];
|
char s[80];
|
||||||
str_tcphdr(s, sizeof(s), tcphdr);
|
str_tcphdr(s, sizeof(s), tcphdr);
|
||||||
DLOG(" %s\n", s);
|
DLOG(" %s\n", s);
|
||||||
if (len_payload) { DLOG("TCP: "); hexdump_limited_dlog(data_payload, len_payload, 32); DLOG("\n"); }
|
if (len_payload)
|
||||||
|
{
|
||||||
|
DLOG("TCP: ");
|
||||||
|
hexdump_limited_dlog(data_payload, len_payload, 32);
|
||||||
|
DLOG("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (udphdr)
|
else if (udphdr)
|
||||||
{
|
{
|
||||||
char s[30];
|
char s[30];
|
||||||
str_udphdr(s, sizeof(s), udphdr);
|
str_udphdr(s, sizeof(s), udphdr);
|
||||||
DLOG(" %s\n", s);
|
DLOG(" %s\n", s);
|
||||||
if (len_payload) { DLOG("UDP: "); hexdump_limited_dlog(data_payload, len_payload, 32); DLOG("\n"); }
|
if (len_payload)
|
||||||
|
{
|
||||||
|
DLOG("UDP: ");
|
||||||
|
hexdump_limited_dlog(data_payload, len_payload, 32);
|
||||||
|
DLOG("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DLOG("\n");
|
DLOG("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt)
|
static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt)
|
||||||
{
|
{
|
||||||
struct ip *ip;
|
struct ip *ip;
|
||||||
@ -1706,8 +1751,6 @@ uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifout, uint8_t *data_pkt,
|
|||||||
return dpi_desync_packet_play(false, 0, fwmark, ifout, data_pkt, len_pkt);
|
return dpi_desync_packet_play(false, 0, fwmark, ifout, data_pkt, len_pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool replay_queue(struct rawpacket_tailhead *q)
|
static bool replay_queue(struct rawpacket_tailhead *q)
|
||||||
{
|
{
|
||||||
struct rawpacket *rp;
|
struct rawpacket *rp;
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
|
|
||||||
#define DPI_DESYNC_MAX_FAKE_LEN 9216
|
#define DPI_DESYNC_MAX_FAKE_LEN 9216
|
||||||
|
|
||||||
enum dpi_desync_mode {
|
enum dpi_desync_mode
|
||||||
|
{
|
||||||
DESYNC_NONE = 0,
|
DESYNC_NONE = 0,
|
||||||
DESYNC_INVALID,
|
DESYNC_INVALID,
|
||||||
DESYNC_FAKE,
|
DESYNC_FAKE,
|
||||||
|
12
nfq/gzip.c
12
nfq/gzip.c
@ -21,7 +21,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
bufsize = *size = 0;
|
bufsize = *size = 0;
|
||||||
|
|
||||||
r = inflateInit2(&zs, 47);
|
r = inflateInit2(&zs, 47);
|
||||||
if (r != Z_OK) return r;
|
if (r != Z_OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -31,7 +32,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
r = Z_ERRNO;
|
r = Z_ERRNO;
|
||||||
goto zerr;
|
goto zerr;
|
||||||
}
|
}
|
||||||
if (!zs.avail_in) break;
|
if (!zs.avail_in)
|
||||||
|
break;
|
||||||
zs.next_in = in;
|
zs.next_in = in;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -49,7 +51,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
zs.avail_out = bufsize - *size;
|
zs.avail_out = bufsize - *size;
|
||||||
zs.next_out = (unsigned char *)(*buf + *size);
|
zs.next_out = (unsigned char *)(*buf + *size);
|
||||||
r = inflate(&zs, Z_NO_FLUSH);
|
r = inflate(&zs, Z_NO_FLUSH);
|
||||||
if (r != Z_OK && r != Z_STREAM_END) goto zerr;
|
if (r != Z_OK && r != Z_STREAM_END)
|
||||||
|
goto zerr;
|
||||||
*size = bufsize - zs.avail_out;
|
*size = bufsize - zs.avail_out;
|
||||||
} while (r == Z_OK && zs.avail_in);
|
} while (r == Z_OK && zs.avail_in);
|
||||||
} while (r == Z_OK);
|
} while (r == Z_OK);
|
||||||
@ -57,7 +60,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
if (*size < bufsize)
|
if (*size < bufsize)
|
||||||
{
|
{
|
||||||
// free extra space
|
// free extra space
|
||||||
if ((newbuf = realloc(*buf, *size))) *buf = newbuf;
|
if ((newbuf = realloc(*buf, *size)))
|
||||||
|
*buf = newbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
inflateEnd(&zs);
|
inflateEnd(&zs);
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|
||||||
#include "params.h"
|
#include "params.h"
|
||||||
|
|
||||||
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
|
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
|
||||||
@ -19,11 +18,15 @@ void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
|
|||||||
size = limit;
|
size = limit;
|
||||||
bcut = true;
|
bcut = true;
|
||||||
}
|
}
|
||||||
if (!size) return;
|
if (!size)
|
||||||
for (k = 0; k < size; k++) DLOG("%02X ", data[k]);
|
return;
|
||||||
|
for (k = 0; k < size; k++)
|
||||||
|
DLOG("%02X ", data[k]);
|
||||||
DLOG(bcut ? "... : " : ": ");
|
DLOG(bcut ? "... : " : ": ");
|
||||||
for (k = 0; k < size; k++) DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.');
|
for (k = 0; k < size; k++)
|
||||||
if (bcut) DLOG(" ...");
|
DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.');
|
||||||
|
if (bcut)
|
||||||
|
DLOG(" ...");
|
||||||
}
|
}
|
||||||
|
|
||||||
char *strncasestr(const char *s, const char *find, size_t slen)
|
char *strncasestr(const char *s, const char *find, size_t slen)
|
||||||
@ -38,9 +41,11 @@ char *strncasestr(const char *s, const char *find, size_t slen)
|
|||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (slen-- < 1 || (sc = *s++) == '\0') return NULL;
|
if (slen-- < 1 || (sc = *s++) == '\0')
|
||||||
|
return NULL;
|
||||||
} while (toupper(c) != toupper(sc));
|
} while (toupper(c) != toupper(sc));
|
||||||
if (len > slen) return NULL;
|
if (len > slen)
|
||||||
|
return NULL;
|
||||||
} while (strncasecmp(s, find, len) != 0);
|
} while (strncasecmp(s, find, len) != 0);
|
||||||
s--;
|
s--;
|
||||||
}
|
}
|
||||||
@ -52,7 +57,8 @@ bool load_file(const char *filename, void *buffer, size_t *buffer_size)
|
|||||||
FILE *F;
|
FILE *F;
|
||||||
|
|
||||||
F = fopen(filename, "rb");
|
F = fopen(filename, "rb");
|
||||||
if (!F) return false;
|
if (!F)
|
||||||
|
return false;
|
||||||
|
|
||||||
*buffer_size = fread(buffer, 1, *buffer_size, F);
|
*buffer_size = fread(buffer, 1, *buffer_size, F);
|
||||||
if (ferror(F))
|
if (ferror(F))
|
||||||
@ -74,7 +80,8 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size)
|
|||||||
FILE *F;
|
FILE *F;
|
||||||
|
|
||||||
F = fopen(filename, "wb");
|
F = fopen(filename, "wb");
|
||||||
if (!F) return false;
|
if (!F)
|
||||||
|
return false;
|
||||||
|
|
||||||
fwrite(buffer, 1, buffer_size, F);
|
fwrite(buffer, 1, buffer_size, F);
|
||||||
if (ferror(F))
|
if (ferror(F))
|
||||||
@ -89,16 +96,17 @@ bool save_file(const char *filename, const 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -143,15 +151,18 @@ bool pton4_port(const char *s, struct sockaddr_in *sa)
|
|||||||
unsigned int u;
|
unsigned int u;
|
||||||
|
|
||||||
p = strchr(s, ':');
|
p = strchr(s, ':');
|
||||||
if (!p) return false;
|
if (!p)
|
||||||
|
return false;
|
||||||
l = p - s;
|
l = p - s;
|
||||||
if (l<7 || l>15) return false;
|
if (l < 7 || l > 15)
|
||||||
|
return false;
|
||||||
memcpy(ip, s, l);
|
memcpy(ip, s, l);
|
||||||
ip[l] = 0;
|
ip[l] = 0;
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
sa->sin_family = AF_INET;
|
sa->sin_family = AF_INET;
|
||||||
if (inet_pton(AF_INET,ip,&sa->sin_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false;
|
if (inet_pton(AF_INET, ip, &sa->sin_addr) != 1 || sscanf(p, "%u", &u) != 1 || !u || u > 0xFFFF)
|
||||||
|
return false;
|
||||||
sa->sin_port = htons((uint16_t)u);
|
sa->sin_port = htons((uint16_t)u);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -162,17 +173,21 @@ bool pton6_port(const char *s, struct sockaddr_in6 *sa)
|
|||||||
size_t l;
|
size_t l;
|
||||||
unsigned int u;
|
unsigned int u;
|
||||||
|
|
||||||
if (*s++!='[') return false;
|
if (*s++ != '[')
|
||||||
|
return false;
|
||||||
p = strchr(s, ']');
|
p = strchr(s, ']');
|
||||||
if (!p || p[1]!=':') return false;
|
if (!p || p[1] != ':')
|
||||||
|
return false;
|
||||||
l = p - s;
|
l = p - s;
|
||||||
if (l<2 || l>39) return false;
|
if (l < 2 || l > 39)
|
||||||
|
return false;
|
||||||
p += 2;
|
p += 2;
|
||||||
memcpy(ip, s, l);
|
memcpy(ip, s, l);
|
||||||
ip[l] = 0;
|
ip[l] = 0;
|
||||||
|
|
||||||
sa->sin6_family = AF_INET6;
|
sa->sin6_family = AF_INET6;
|
||||||
if (inet_pton(AF_INET6,ip,&sa->sin6_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false;
|
if (inet_pton(AF_INET6, ip, &sa->sin6_addr) != 1 || sscanf(p, "%u", &u) != 1 || !u || u > 0xFFFF)
|
||||||
|
return false;
|
||||||
sa->sin6_port = htons((uint16_t)u);
|
sa->sin6_port = htons((uint16_t)u);
|
||||||
sa->sin6_flowinfo = 0;
|
sa->sin6_flowinfo = 0;
|
||||||
sa->sin6_scope_id = 0;
|
sa->sin6_scope_id = 0;
|
||||||
@ -180,7 +195,6 @@ bool pton6_port(const char *s, struct sockaddr_in6 *sa)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dbgprint_socket_buffers(int fd)
|
void dbgprint_socket_buffers(int fd)
|
||||||
{
|
{
|
||||||
if (params.debug)
|
if (params.debug)
|
||||||
@ -247,11 +261,12 @@ bool ipv6_addr_is_zero(const struct in6_addr *a)
|
|||||||
return !memcmp(a, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
|
return !memcmp(a, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define INVALID_HEX_DIGIT ((uint8_t) - 1)
|
#define INVALID_HEX_DIGIT ((uint8_t) - 1)
|
||||||
static inline uint8_t parse_hex_digit(char c)
|
static inline uint8_t parse_hex_digit(char c)
|
||||||
{
|
{
|
||||||
return (c>='0' && c<='9') ? c-'0' : (c>='a' && c<='f') ? c-'a'+0xA : (c>='A' && c<='F') ? c-'A'+0xA : INVALID_HEX_DIGIT;
|
return (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 0xA
|
||||||
|
: (c >= 'A' && c <= 'F') ? c - 'A' + 0xA
|
||||||
|
: INVALID_HEX_DIGIT;
|
||||||
}
|
}
|
||||||
static inline bool parse_hex_byte(const char *s, uint8_t *pbyte)
|
static inline bool parse_hex_byte(const char *s, uint8_t *pbyte)
|
||||||
{
|
{
|
||||||
@ -277,7 +292,9 @@ bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size)
|
|||||||
{
|
{
|
||||||
if (!parse_hex_byte(s, pbuf))
|
if (!parse_hex_byte(s, pbuf))
|
||||||
return false;
|
return false;
|
||||||
pbuf++; s+=2; (*size)++;
|
pbuf++;
|
||||||
|
s += 2;
|
||||||
|
(*size)++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -319,7 +336,8 @@ 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;
|
||||||
@ -329,13 +347,15 @@ 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 || 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 || v1 > 65535)
|
||||||
|
return false;
|
||||||
pf->to = pf->from = (uint16_t)v1;
|
pf->to = pf->from = (uint16_t)v1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -346,13 +366,16 @@ bool pf_parse(const char *s, port_filter *pf)
|
|||||||
void fill_random_bytes(uint8_t *p, size_t sz)
|
void fill_random_bytes(uint8_t *p, size_t sz)
|
||||||
{
|
{
|
||||||
size_t k, sz16 = sz >> 1;
|
size_t k, sz16 = sz >> 1;
|
||||||
for(k=0;k<sz16;k++) ((uint16_t*)p)[k]=(uint16_t)random();
|
for (k = 0; k < sz16; k++)
|
||||||
if (sz & 1) p[sz-1]=(uint8_t)random();
|
((uint16_t *)p)[k] = (uint16_t)random();
|
||||||
|
if (sz & 1)
|
||||||
|
p[sz - 1] = (uint8_t)random();
|
||||||
}
|
}
|
||||||
void fill_random_az(uint8_t *p, size_t sz)
|
void fill_random_az(uint8_t *p, size_t sz)
|
||||||
{
|
{
|
||||||
size_t k;
|
size_t k;
|
||||||
for(k=0;k<sz;k++) p[k] = 'a'+(random() % ('z'-'a'));
|
for (k = 0; k < sz; k++)
|
||||||
|
p[k] = 'a' + (random() % ('z' - 'a'));
|
||||||
}
|
}
|
||||||
void fill_random_az09(uint8_t *p, size_t sz)
|
void fill_random_az09(uint8_t *p, size_t sz)
|
||||||
{
|
{
|
||||||
|
@ -32,14 +32,17 @@ void phton64(uint8_t *p, uint64_t v);
|
|||||||
|
|
||||||
bool ipv6_addr_is_zero(const struct in6_addr *a);
|
bool ipv6_addr_is_zero(const struct in6_addr *a);
|
||||||
|
|
||||||
static inline uint16_t pntoh16(const uint8_t *p) {
|
static inline uint16_t pntoh16(const uint8_t *p)
|
||||||
|
{
|
||||||
return ((uint16_t)p[0] << 8) | (uint16_t)p[1];
|
return ((uint16_t)p[0] << 8) | (uint16_t)p[1];
|
||||||
}
|
}
|
||||||
static inline void phton16(uint8_t *p, uint16_t v) {
|
static inline void phton16(uint8_t *p, uint16_t v)
|
||||||
|
{
|
||||||
p[0] = (uint8_t)(v >> 8);
|
p[0] = (uint8_t)(v >> 8);
|
||||||
p[1] = v & 0xFF;
|
p[1] = v & 0xFF;
|
||||||
}
|
}
|
||||||
static inline uint32_t pntoh32(const uint8_t *p) {
|
static inline uint32_t pntoh32(const uint8_t *p)
|
||||||
|
{
|
||||||
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
|
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ static bool addpool(strpool **hostlist, char **s, const char *end)
|
|||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
// advance until eol lowering all chars
|
// advance until eol lowering all chars
|
||||||
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
for (p = *s; p < end && *p && *p != '\r' && *p != '\n'; p++)
|
||||||
|
*p = tolower(*p);
|
||||||
if (!StrPoolAddStrLen(hostlist, *s, p - *s))
|
if (!StrPoolAddStrLen(hostlist, *s, p - *s))
|
||||||
{
|
{
|
||||||
StrPoolDestroy(hostlist);
|
StrPoolDestroy(hostlist);
|
||||||
@ -18,7 +19,8 @@ static bool addpool(strpool **hostlist, char **s, const char *end)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// advance to the next line
|
// advance to the next line
|
||||||
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
|
for (; p < end && (!*p || *p == '\r' || *p == '\n'); p++)
|
||||||
|
;
|
||||||
*s = p;
|
*s = p;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -51,7 +53,8 @@ bool AppendHostList(strpool **hostlist, char *filename)
|
|||||||
e = zbuf + zsize;
|
e = zbuf + zsize;
|
||||||
while (p < e)
|
while (p < e)
|
||||||
{
|
{
|
||||||
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
|
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
|
||||||
|
continue;
|
||||||
if (!addpool(hostlist, &p, e))
|
if (!addpool(hostlist, &p, e))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
||||||
@ -75,7 +78,8 @@ bool AppendHostList(strpool **hostlist, char *filename)
|
|||||||
while (fgets(s, 256, F))
|
while (fgets(s, 256, F))
|
||||||
{
|
{
|
||||||
p = s;
|
p = s;
|
||||||
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
|
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
|
||||||
|
continue;
|
||||||
if (!addpool(hostlist, &p, p + strlen(p)))
|
if (!addpool(hostlist, &p, p + strlen(p)))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
||||||
@ -103,7 +107,8 @@ bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list)
|
|||||||
|
|
||||||
LIST_FOREACH(file, file_list, next)
|
LIST_FOREACH(file, file_list, next)
|
||||||
{
|
{
|
||||||
if (!AppendHostList(hostlist, file->str)) return false;
|
if (!AppendHostList(hostlist, file->str))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -114,7 +119,6 @@ bool NonEmptyHostlist(strpool **hostlist)
|
|||||||
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
|
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SearchHostList(strpool *hostlist, const char *host)
|
bool SearchHostList(strpool *hostlist, const char *host)
|
||||||
{
|
{
|
||||||
if (hostlist)
|
if (hostlist)
|
||||||
@ -125,9 +129,11 @@ bool SearchHostList(strpool *hostlist, const char *host)
|
|||||||
{
|
{
|
||||||
bInHostList = StrPoolCheckStr(hostlist, p);
|
bInHostList = StrPoolCheckStr(hostlist, p);
|
||||||
DLOG("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
|
DLOG("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
|
||||||
if (bInHostList) return true;
|
if (bInHostList)
|
||||||
|
return true;
|
||||||
p = strchr(p, '.');
|
p = strchr(p, '.');
|
||||||
if (p) p++;
|
if (p)
|
||||||
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -136,13 +142,15 @@ bool SearchHostList(strpool *hostlist, const char *host)
|
|||||||
// return : true = apply fooling, false = do not apply
|
// return : true = apply fooling, false = do not apply
|
||||||
static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded)
|
static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded)
|
||||||
{
|
{
|
||||||
if (excluded) *excluded = false;
|
if (excluded)
|
||||||
|
*excluded = false;
|
||||||
if (hostlist_exclude)
|
if (hostlist_exclude)
|
||||||
{
|
{
|
||||||
DLOG("Checking exclude hostlist\n");
|
DLOG("Checking exclude hostlist\n");
|
||||||
if (SearchHostList(hostlist_exclude, host))
|
if (SearchHostList(hostlist_exclude, host))
|
||||||
{
|
{
|
||||||
if (excluded) *excluded = true;
|
if (excluded)
|
||||||
|
*excluded = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
155
nfq/nfqws.c
155
nfq/nfqws.c
@ -94,7 +94,6 @@ static void pre_desync(void)
|
|||||||
desync_init();
|
desync_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt)
|
static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@ -107,7 +106,6 @@ static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *dat
|
|||||||
return dpi_desync_packet(*mark, ifout, data_pkt, len_pkt);
|
return dpi_desync_packet(*mark, ifout, data_pkt, len_pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *cookie)
|
static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *cookie)
|
||||||
{
|
{
|
||||||
@ -131,10 +129,12 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da
|
|||||||
uint32_t ifidx_in;
|
uint32_t ifidx_in;
|
||||||
|
|
||||||
ifidx = nfq_get_outdev(nfa);
|
ifidx = nfq_get_outdev(nfa);
|
||||||
if (ifidx) if_indextoname(ifidx,ifout);
|
if (ifidx)
|
||||||
|
if_indextoname(ifidx, ifout);
|
||||||
*ifin = 0;
|
*ifin = 0;
|
||||||
ifidx_in = nfq_get_indev(nfa);
|
ifidx_in = nfq_get_indev(nfa);
|
||||||
if (ifidx_in) if_indextoname(ifidx_in,ifin);
|
if (ifidx_in)
|
||||||
|
if_indextoname(ifidx_in, ifin);
|
||||||
|
|
||||||
DLOG("packet: id=%d len=%d mark=%08X ifin=%s(%u) ifout=%s(%u)\n", id, ilen, mark, ifin, ifidx_in, ifout, ifidx);
|
DLOG("packet: id=%d len=%d mark=%08X ifin=%s(%u) ifout=%s(%u)\n", id, ilen, mark, ifin, ifidx_in, ifout, ifidx);
|
||||||
}
|
}
|
||||||
@ -167,43 +167,49 @@ static int nfq_main(void)
|
|||||||
|
|
||||||
DLOG_CONDUP("opening library handle\n");
|
DLOG_CONDUP("opening library handle\n");
|
||||||
h = nfq_open();
|
h = nfq_open();
|
||||||
if (!h) {
|
if (!h)
|
||||||
|
{
|
||||||
DLOG_PERROR("nfq_open()");
|
DLOG_PERROR("nfq_open()");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLOG_CONDUP("unbinding existing nf_queue handler for AF_INET (if any)\n");
|
DLOG_CONDUP("unbinding existing nf_queue handler for AF_INET (if any)\n");
|
||||||
if (nfq_unbind_pf(h, AF_INET) < 0) {
|
if (nfq_unbind_pf(h, AF_INET) < 0)
|
||||||
|
{
|
||||||
DLOG_PERROR("nfq_unbind_pf()");
|
DLOG_PERROR("nfq_unbind_pf()");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLOG_CONDUP("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
|
DLOG_CONDUP("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
|
||||||
if (nfq_bind_pf(h, AF_INET) < 0) {
|
if (nfq_bind_pf(h, AF_INET) < 0)
|
||||||
|
{
|
||||||
DLOG_PERROR("nfq_bind_pf()");
|
DLOG_PERROR("nfq_bind_pf()");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLOG_CONDUP("binding this socket to queue '%u'\n", params.qnum);
|
DLOG_CONDUP("binding this socket to queue '%u'\n", params.qnum);
|
||||||
qh = nfq_create_queue(h, params.qnum, &nfq_cb, ¶ms);
|
qh = nfq_create_queue(h, params.qnum, &nfq_cb, ¶ms);
|
||||||
if (!qh) {
|
if (!qh)
|
||||||
|
{
|
||||||
DLOG_PERROR("nfq_create_queue()");
|
DLOG_PERROR("nfq_create_queue()");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLOG_CONDUP("setting copy_packet mode\n");
|
DLOG_CONDUP("setting copy_packet mode\n");
|
||||||
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
|
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0)
|
||||||
|
{
|
||||||
DLOG_PERROR("can't set packet_copy mode");
|
DLOG_PERROR("can't set packet_copy mode");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
if (nfq_set_queue_maxlen(qh, Q_MAXLEN) < 0) {
|
if (nfq_set_queue_maxlen(qh, Q_MAXLEN) < 0)
|
||||||
|
{
|
||||||
DLOG_PERROR("can't set queue maxlen");
|
DLOG_PERROR("can't set queue maxlen");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
// accept packets if they cant be handled
|
// accept packets if they cant be handled
|
||||||
if (nfq_set_queue_flags(qh, NFQA_CFG_F_FAIL_OPEN, NFQA_CFG_F_FAIL_OPEN))
|
if (nfq_set_queue_flags(qh, NFQA_CFG_F_FAIL_OPEN, NFQA_CFG_F_FAIL_OPEN))
|
||||||
{
|
{
|
||||||
DLOG_ERR("can't set queue flags. its OK on linux <3.6\n");
|
DLOG_ERR("can't set queue flags. its OK on Linux <3.6\n");
|
||||||
// dot not fail. not supported on old linuxes <3.6
|
// dot not fail. not supported on old linuxes <3.6
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +240,8 @@ static int nfq_main(void)
|
|||||||
{
|
{
|
||||||
dohup();
|
dohup();
|
||||||
int r = nfq_handle_packet(h, (char *)buf, rv);
|
int r = nfq_handle_packet(h, (char *)buf, rv);
|
||||||
if (r) DLOG_ERR("nfq_handle_packet error %d\n", r);
|
if (r)
|
||||||
|
DLOG_ERR("nfq_handle_packet error %d\n", r);
|
||||||
}
|
}
|
||||||
DLOG_ERR("recv: errno %d\n", errno);
|
DLOG_ERR("recv: errno %d\n", errno);
|
||||||
DLOG_PERROR("recv");
|
DLOG_PERROR("recv");
|
||||||
@ -256,8 +263,10 @@ static int nfq_main(void)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exiterr:
|
exiterr:
|
||||||
if (qh) nfq_destroy_queue(qh);
|
if (qh)
|
||||||
if (h) nfq_close(h);
|
nfq_destroy_queue(qh);
|
||||||
|
if (h)
|
||||||
|
nfq_close(h);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +291,8 @@ static int dvt_main(void)
|
|||||||
|
|
||||||
DLOG_CONDUP("creating divert4 socket\n");
|
DLOG_CONDUP("creating divert4 socket\n");
|
||||||
fd[0] = socket_divert(AF_INET);
|
fd[0] = socket_divert(AF_INET);
|
||||||
if (fd[0] == -1) {
|
if (fd[0] == -1)
|
||||||
|
{
|
||||||
DLOG_PERROR("socket (DIVERT4)");
|
DLOG_PERROR("socket (DIVERT4)");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
@ -296,7 +306,6 @@ static int dvt_main(void)
|
|||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
{
|
{
|
||||||
// in OpenBSD must use separate divert sockets for ipv4 and ipv6
|
// in OpenBSD must use separate divert sockets for ipv4 and ipv6
|
||||||
@ -307,7 +316,8 @@ static int dvt_main(void)
|
|||||||
|
|
||||||
DLOG_CONDUP("creating divert6 socket\n");
|
DLOG_CONDUP("creating divert6 socket\n");
|
||||||
fd[1] = socket_divert(AF_INET6);
|
fd[1] = socket_divert(AF_INET6);
|
||||||
if (fd[1] == -1) {
|
if (fd[1] == -1)
|
||||||
|
{
|
||||||
DLOG_PERROR("socket (DIVERT6)");
|
DLOG_PERROR("socket (DIVERT6)");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
@ -337,7 +347,8 @@ static int dvt_main(void)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
for(i=0;i<fdct;i++) FD_SET(fd[i], &fdset);
|
for (i = 0; i < fdct; i++)
|
||||||
|
FD_SET(fd[i], &fdset);
|
||||||
r = select(fdmax, &fdset, NULL, NULL, NULL);
|
r = select(fdmax, &fdset, NULL, NULL, NULL);
|
||||||
if (r == -1)
|
if (r == -1)
|
||||||
{
|
{
|
||||||
@ -398,12 +409,13 @@ static int dvt_main(void)
|
|||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
exiterr:
|
exiterr:
|
||||||
if (fd[0]!=-1) close(fd[0]);
|
if (fd[0] != -1)
|
||||||
if (fd[1]!=-1) close(fd[1]);
|
close(fd[0]);
|
||||||
|
if (fd[1] != -1)
|
||||||
|
close(fd[1]);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#elif defined(__CYGWIN__)
|
#elif defined(__CYGWIN__)
|
||||||
|
|
||||||
static int win_main(const char *windivert_filter)
|
static int win_main(const char *windivert_filter)
|
||||||
@ -440,8 +452,7 @@ static int win_main(const char *windivert_filter)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
usleep(500000);
|
usleep(500000);
|
||||||
}
|
} while (!logical_net_filter_match());
|
||||||
while (!logical_net_filter_match());
|
|
||||||
DLOG_CONDUP("logical network now present\n");
|
DLOG_CONDUP("logical network now present\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
@ -485,7 +496,8 @@ static int win_main(const char *windivert_filter)
|
|||||||
return w_win32_error;
|
return w_win32_error;
|
||||||
}
|
}
|
||||||
*ifout = 0;
|
*ifout = 0;
|
||||||
if (wa.Outbound) snprintf(ifout,sizeof(ifout),"%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx);
|
if (wa.Outbound)
|
||||||
|
snprintf(ifout, sizeof(ifout), "%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx);
|
||||||
DLOG("packet: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx);
|
DLOG("packet: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx);
|
||||||
if (wa.Impostor)
|
if (wa.Impostor)
|
||||||
{
|
{
|
||||||
@ -529,14 +541,13 @@ static int win_main(const char *windivert_filter)
|
|||||||
|
|
||||||
#endif // multiple OS divert handlers
|
#endif // multiple OS divert handlers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale)
|
static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale)
|
||||||
{
|
{
|
||||||
int v;
|
int v;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
if ((p = strchr(s,':'))) *p++=0;
|
if ((p = strchr(s, ':')))
|
||||||
|
*p++ = 0;
|
||||||
v = atoi(s);
|
v = atoi(s);
|
||||||
if (v < 0 || v > 65535)
|
if (v < 0 || v > 65535)
|
||||||
{
|
{
|
||||||
@ -557,8 +568,6 @@ static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void cleanup_params(void)
|
static void cleanup_params(void)
|
||||||
{
|
{
|
||||||
ConntrackPoolDestroy(¶ms.conntrack);
|
ConntrackPoolDestroy(¶ms.conntrack);
|
||||||
@ -588,7 +597,8 @@ static bool parse_badseq_increment(const char *opt, uint32_t *value)
|
|||||||
{
|
{
|
||||||
if (((opt[0] == '0' && opt[1] == 'x') || (opt[0] == '-' && opt[1] == '0' && opt[2] == 'x')) && sscanf(opt + 2 + (opt[0] == '-'), "%X", (int32_t *)value) > 0)
|
if (((opt[0] == '0' && opt[1] == 'x') || (opt[0] == '-' && opt[1] == '0' && opt[2] == 'x')) && sscanf(opt + 2 + (opt[0] == '-'), "%X", (int32_t *)value) > 0)
|
||||||
{
|
{
|
||||||
if (opt[0]=='-') params.desync_badseq_increment = -params.desync_badseq_increment;
|
if (opt[0] == '-')
|
||||||
|
params.desync_badseq_increment = -params.desync_badseq_increment;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -628,13 +638,16 @@ bool parse_autottl(const char *s, autottl *t)
|
|||||||
switch (sscanf(s, "%u:%u-%u", &delta, &min, &max))
|
switch (sscanf(s, "%u:%u-%u", &delta, &min, &max))
|
||||||
{
|
{
|
||||||
case 3:
|
case 3:
|
||||||
if ((delta && !max) || max>255) return false;
|
if ((delta && !max) || max > 255)
|
||||||
|
return false;
|
||||||
t->max = (uint8_t)max;
|
t->max = (uint8_t)max;
|
||||||
case 2:
|
case 2:
|
||||||
if ((delta && !min) || min>255 || min>max) return false;
|
if ((delta && !min) || min > 255 || min > max)
|
||||||
|
return false;
|
||||||
t->min = (uint8_t)min;
|
t->min = (uint8_t)min;
|
||||||
case 1:
|
case 1:
|
||||||
if (delta>255) return false;
|
if (delta > 255)
|
||||||
|
return false;
|
||||||
t->delta = (uint8_t)delta;
|
t->delta = (uint8_t)delta;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -651,7 +664,8 @@ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *bu
|
|||||||
port_filter pf;
|
port_filter pf;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if (len<3) return false;
|
if (len < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
for (n = 0, p = opt, *buf = '(', buf[1] = 0; p; n++)
|
for (n = 0, p = opt, *buf = '(', buf[1] = 0; p; n++)
|
||||||
{
|
{
|
||||||
@ -660,13 +674,15 @@ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *bu
|
|||||||
c = *e;
|
c = *e;
|
||||||
*e = 0;
|
*e = 0;
|
||||||
}
|
}
|
||||||
if (!pf_parse(p,&pf)) return false;
|
if (!pf_parse(p, &pf))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (pf.from == pf.to)
|
if (pf.from == pf.to)
|
||||||
snprintf(s1, sizeof(s1), "(%s.%s %s %u)", l4, portname, pf.neg ? "!=" : "==", pf.from);
|
snprintf(s1, sizeof(s1), "(%s.%s %s %u)", l4, portname, pf.neg ? "!=" : "==", pf.from);
|
||||||
else
|
else
|
||||||
snprintf(s1, sizeof(s1), "(%s.%s %s %u %s %s.%s %s %u)", l4, portname, pf.neg ? "<" : ">=", pf.from, pf.neg ? "or" : "and", l4, portname, pf.neg ? ">" : "<=", pf.to);
|
snprintf(s1, sizeof(s1), "(%s.%s %s %u %s %s.%s %s %u)", l4, portname, pf.neg ? "<" : ">=", pf.from, pf.neg ? "or" : "and", l4, portname, pf.neg ? ">" : "<=", pf.to);
|
||||||
if (n) strncat(buf," or ",len-strlen(buf)-1);
|
if (n)
|
||||||
|
strncat(buf, " or ", len - strlen(buf) - 1);
|
||||||
strncat(buf, s1, len - strlen(buf) - 1);
|
strncat(buf, s1, len - strlen(buf) - 1);
|
||||||
|
|
||||||
if (e)
|
if (e)
|
||||||
@ -694,7 +710,8 @@ static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
|
|||||||
*ipv4 = true;
|
*ipv4 = true;
|
||||||
else if (!strcmp(p, "ipv6"))
|
else if (!strcmp(p, "ipv6"))
|
||||||
*ipv6 = true;
|
*ipv6 = true;
|
||||||
else return false;
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
@ -754,7 +771,8 @@ static bool wf_make_filter(
|
|||||||
|
|
||||||
snprintf(iface, sizeof(iface), " ifIdx=%u and subIfIdx=%u and", IfIdx, SubIfIdx);
|
snprintf(iface, sizeof(iface), " ifIdx=%u and subIfIdx=%u and", IfIdx, SubIfIdx);
|
||||||
|
|
||||||
if (!*pf_tcp_src && !*pf_udp_src) return false;
|
if (!*pf_tcp_src && !*pf_udp_src)
|
||||||
|
return false;
|
||||||
if (*pf_tcp_src && *pf_udp_src)
|
if (*pf_tcp_src && *pf_udp_src)
|
||||||
{
|
{
|
||||||
snprintf(pf_dst_buf, sizeof(pf_dst_buf), "(%s or %s)", pf_tcp_dst, pf_udp_dst);
|
snprintf(pf_dst_buf, sizeof(pf_dst_buf), "(%s or %s)", pf_tcp_dst, pf_udp_dst);
|
||||||
@ -774,8 +792,7 @@ static bool wf_make_filter(
|
|||||||
*pf_tcp_src ? " and " : "",
|
*pf_tcp_src ? " and " : "",
|
||||||
*pf_tcp_src ? pf_tcp_src : "",
|
*pf_tcp_src ? pf_tcp_src : "",
|
||||||
*pf_tcp_src ? " and " : "",
|
*pf_tcp_src ? " and " : "",
|
||||||
*pf_tcp_src ? ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_SRC : DIVERT_NO_LOCALNETSv4_SRC : DIVERT_NO_LOCALNETSv6_SRC : ""
|
*pf_tcp_src ? ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_SRC : DIVERT_NO_LOCALNETSv4_SRC : DIVERT_NO_LOCALNETSv6_SRC : "");
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -789,7 +806,6 @@ static unsigned int hash_jen(const void *data,unsigned int len)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void exithelp(void)
|
static void exithelp(void)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
@ -884,8 +900,7 @@ static void exithelp(void)
|
|||||||
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT,
|
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT,
|
||||||
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT,
|
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT,
|
||||||
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
|
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
|
||||||
UDPLEN_INCREMENT_DEFAULT
|
UDPLEN_INCREMENT_DEFAULT);
|
||||||
);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
static void exithelp_clean(void)
|
static void exithelp_clean(void)
|
||||||
@ -963,7 +978,7 @@ int main(int argc, char **argv)
|
|||||||
params.fake_unknown_size = 256;
|
params.fake_unknown_size = 256;
|
||||||
params.fake_syndata_size = 16;
|
params.fake_syndata_size = 16;
|
||||||
params.fake_unknown_udp_size = 64;
|
params.fake_unknown_udp_size = 64;
|
||||||
params.wscale=-1; // default - dont change scale factor (client)
|
params.wscale = -1; // default - don't change scale factor (client)
|
||||||
params.ctrack_t_syn = CTRACK_T_SYN;
|
params.ctrack_t_syn = CTRACK_T_SYN;
|
||||||
params.ctrack_t_est = CTRACK_T_EST;
|
params.ctrack_t_est = CTRACK_T_EST;
|
||||||
params.ctrack_t_fin = CTRACK_T_FIN;
|
params.ctrack_t_fin = CTRACK_T_FIN;
|
||||||
@ -1076,12 +1091,13 @@ int main(int argc, char **argv)
|
|||||||
{"nlm-filter", required_argument, 0, 0}, // optidx=59
|
{"nlm-filter", required_argument, 0, 0}, // optidx=59
|
||||||
{"nlm-list", optional_argument, 0, 0}, // optidx=60
|
{"nlm-list", optional_argument, 0, 0}, // optidx=60
|
||||||
#endif
|
#endif
|
||||||
{NULL,0,NULL,0}
|
{NULL, 0, NULL, 0}};
|
||||||
};
|
if (argc < 2)
|
||||||
if (argc < 2) exithelp();
|
exithelp();
|
||||||
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
||||||
{
|
{
|
||||||
if (v) exithelp();
|
if (v)
|
||||||
|
exithelp();
|
||||||
switch (option_index)
|
switch (option_index)
|
||||||
{
|
{
|
||||||
case 0: /* debug */
|
case 0: /* debug */
|
||||||
@ -1219,9 +1235,11 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
char *mode = optarg, *mode2, *mode3;
|
char *mode = optarg, *mode2, *mode3;
|
||||||
mode2 = mode ? strchr(mode, ',') : NULL;
|
mode2 = mode ? strchr(mode, ',') : NULL;
|
||||||
if (mode2) *mode2++=0;
|
if (mode2)
|
||||||
|
*mode2++ = 0;
|
||||||
mode3 = mode2 ? strchr(mode2, ',') : NULL;
|
mode3 = mode2 ? strchr(mode2, ',') : NULL;
|
||||||
if (mode3) *mode3++=0;
|
if (mode3)
|
||||||
|
*mode3++ = 0;
|
||||||
|
|
||||||
params.desync_mode0 = desync_mode_from_string(mode);
|
params.desync_mode0 = desync_mode_from_string(mode);
|
||||||
if (desync_valid_zero_stage(params.desync_mode0))
|
if (desync_valid_zero_stage(params.desync_mode0))
|
||||||
@ -1264,7 +1282,8 @@ int main(int argc, char **argv)
|
|||||||
case 15: /* dpi-desync-fwmark/dpi-desync-sockarg */
|
case 15: /* dpi-desync-fwmark/dpi-desync-sockarg */
|
||||||
#if defined(__linux__) || defined(SO_USER_COOKIE)
|
#if defined(__linux__) || defined(SO_USER_COOKIE)
|
||||||
params.desync_fwmark = 0;
|
params.desync_fwmark = 0;
|
||||||
if (sscanf(optarg, "0x%X", ¶ms.desync_fwmark)<=0) sscanf(optarg, "%u", ¶ms.desync_fwmark);
|
if (sscanf(optarg, "0x%X", ¶ms.desync_fwmark) <= 0)
|
||||||
|
sscanf(optarg, "%u", ¶ms.desync_fwmark);
|
||||||
if (!params.desync_fwmark)
|
if (!params.desync_fwmark)
|
||||||
{
|
{
|
||||||
DLOG_ERR("fwmark/sockarg should be decimal or 0xHEX and should not be zero\n");
|
DLOG_ERR("fwmark/sockarg should be decimal or 0xHEX and should not be zero\n");
|
||||||
@ -1302,7 +1321,8 @@ int main(int argc, char **argv)
|
|||||||
while (p)
|
while (p)
|
||||||
{
|
{
|
||||||
e = strchr(p, ',');
|
e = strchr(p, ',');
|
||||||
if (e) *e++=0;
|
if (e)
|
||||||
|
*e++ = 0;
|
||||||
if (!strcmp(p, "md5sig"))
|
if (!strcmp(p, "md5sig"))
|
||||||
params.desync_fooling_mode |= FOOL_MD5SIG;
|
params.desync_fooling_mode |= FOOL_MD5SIG;
|
||||||
else if (!strcmp(p, "ts"))
|
else if (!strcmp(p, "ts"))
|
||||||
@ -1632,14 +1652,14 @@ int main(int argc, char **argv)
|
|||||||
while (p)
|
while (p)
|
||||||
{
|
{
|
||||||
e = strchr(p, ',');
|
e = strchr(p, ',');
|
||||||
if (e) *e++=0;
|
if (e)
|
||||||
|
*e++ = 0;
|
||||||
if (*p && !strlist_add(¶ms.ssid_filter, p))
|
if (*p && !strlist_add(¶ms.ssid_filter, p))
|
||||||
{
|
{
|
||||||
DLOG_ERR("strlist_add failed\n");
|
DLOG_ERR("strlist_add failed\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
p = e;
|
p = e;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1650,14 +1670,14 @@ int main(int argc, char **argv)
|
|||||||
while (p)
|
while (p)
|
||||||
{
|
{
|
||||||
e = strchr(p, ',');
|
e = strchr(p, ',');
|
||||||
if (e) *e++=0;
|
if (e)
|
||||||
|
*e++ = 0;
|
||||||
if (*p && !strlist_add(¶ms.nlm_filter, p))
|
if (*p && !strlist_add(¶ms.nlm_filter, p))
|
||||||
{
|
{
|
||||||
DLOG_ERR("strlist_add failed\n");
|
DLOG_ERR("strlist_add failed\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
p = e;
|
p = e;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1721,23 +1741,27 @@ int main(int argc, char **argv)
|
|||||||
hMutexArg = CreateMutexA(NULL, TRUE, mutex_name);
|
hMutexArg = CreateMutexA(NULL, TRUE, mutex_name);
|
||||||
if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS)
|
if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS)
|
||||||
{
|
{
|
||||||
CloseHandle(hMutexArg); hMutexArg = NULL;
|
CloseHandle(hMutexArg);
|
||||||
|
hMutexArg = NULL;
|
||||||
DLOG_ERR("A copy of winws is already running with the same filter\n");
|
DLOG_ERR("A copy of winws is already running with the same filter\n");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// not specified - use desync_ttl value instead
|
// not specified - use desync_ttl value instead
|
||||||
if (params.desync_ttl6 == 0xFF) params.desync_ttl6=params.desync_ttl;
|
if (params.desync_ttl6 == 0xFF)
|
||||||
if (!AUTOTTL_ENABLED(params.desync_autottl6)) params.desync_autottl6 = params.desync_autottl;
|
params.desync_ttl6 = params.desync_ttl;
|
||||||
|
if (!AUTOTTL_ENABLED(params.desync_autottl6))
|
||||||
|
params.desync_autottl6 = params.desync_autottl;
|
||||||
if (AUTOTTL_ENABLED(params.desync_autottl))
|
if (AUTOTTL_ENABLED(params.desync_autottl))
|
||||||
DLOG("autottl ipv4 %u:%u-%u\n",params.desync_autottl.delta,params.desync_autottl.min,params.desync_autottl.max);
|
DLOG("autottl IPv4 %u:%u-%u\n", params.desync_autottl.delta, params.desync_autottl.min, params.desync_autottl.max);
|
||||||
if (AUTOTTL_ENABLED(params.desync_autottl6))
|
if (AUTOTTL_ENABLED(params.desync_autottl6))
|
||||||
DLOG("autottl ipv6 %u:%u-%u\n",params.desync_autottl6.delta,params.desync_autottl6.min,params.desync_autottl6.max);
|
DLOG("autottl IPv6 %u:%u-%u\n", params.desync_autottl6.delta, params.desync_autottl6.min, params.desync_autottl6.max);
|
||||||
if (params.desync_split_tls==tlspos_none && params.desync_split_pos) params.desync_split_tls=tlspos_pos;
|
if (params.desync_split_tls == tlspos_none && params.desync_split_pos)
|
||||||
if (params.desync_split_http_req==httpreqpos_none && params.desync_split_pos) params.desync_split_http_req=httpreqpos_pos;
|
params.desync_split_tls = tlspos_pos;
|
||||||
|
if (params.desync_split_http_req == httpreqpos_none && params.desync_split_pos)
|
||||||
|
params.desync_split_http_req = httpreqpos_pos;
|
||||||
|
|
||||||
if (!LoadIncludeHostLists())
|
if (!LoadIncludeHostLists())
|
||||||
{
|
{
|
||||||
@ -1752,7 +1776,8 @@ int main(int argc, char **argv)
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (daemon) daemonize();
|
if (daemon)
|
||||||
|
daemonize();
|
||||||
|
|
||||||
if (*pidfile && !writepid(pidfile))
|
if (*pidfile && !writepid(pidfile))
|
||||||
{
|
{
|
||||||
|
@ -9,26 +9,30 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q)
|
|||||||
}
|
}
|
||||||
void rawpacket_free(struct rawpacket *rp)
|
void rawpacket_free(struct rawpacket *rp)
|
||||||
{
|
{
|
||||||
if (rp) free(rp->packet);
|
if (rp)
|
||||||
|
free(rp->packet);
|
||||||
free(rp);
|
free(rp);
|
||||||
}
|
}
|
||||||
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q)
|
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q)
|
||||||
{
|
{
|
||||||
struct rawpacket *rp;
|
struct rawpacket *rp;
|
||||||
rp = TAILQ_FIRST(q);
|
rp = TAILQ_FIRST(q);
|
||||||
if (rp) TAILQ_REMOVE(q, rp, next);
|
if (rp)
|
||||||
|
TAILQ_REMOVE(q, rp, next);
|
||||||
return rp;
|
return rp;
|
||||||
}
|
}
|
||||||
void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
|
void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
|
||||||
{
|
{
|
||||||
struct rawpacket *rp;
|
struct rawpacket *rp;
|
||||||
while((rp = rawpacket_dequeue(q))) rawpacket_free(rp);
|
while ((rp = rawpacket_dequeue(q)))
|
||||||
|
rawpacket_free(rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q, const struct sockaddr_storage *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len, size_t len_payload)
|
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q, const struct sockaddr_storage *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len, size_t len_payload)
|
||||||
{
|
{
|
||||||
struct rawpacket *rp = malloc(sizeof(struct rawpacket));
|
struct rawpacket *rp = malloc(sizeof(struct rawpacket));
|
||||||
if (!rp) return NULL;
|
if (!rp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
rp->packet = malloc(len);
|
rp->packet = malloc(len);
|
||||||
if (!rp->packet)
|
if (!rp->packet)
|
||||||
@ -59,7 +63,8 @@ unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q)
|
|||||||
{
|
{
|
||||||
const struct rawpacket *rp;
|
const struct rawpacket *rp;
|
||||||
unsigned int ct = 0;
|
unsigned int ct = 0;
|
||||||
TAILQ_FOREACH(rp, q, next) ct++;
|
TAILQ_FOREACH(rp, q, next)
|
||||||
|
ct++;
|
||||||
return ct;
|
return ct;
|
||||||
}
|
}
|
||||||
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q)
|
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q)
|
||||||
|
@ -13,7 +13,8 @@ struct rawpacket
|
|||||||
uint32_t fwmark;
|
uint32_t fwmark;
|
||||||
size_t len, len_payload;
|
size_t len, len_payload;
|
||||||
uint8_t *packet;
|
uint8_t *packet;
|
||||||
TAILQ_ENTRY(rawpacket) next;
|
TAILQ_ENTRY(rawpacket)
|
||||||
|
next;
|
||||||
};
|
};
|
||||||
TAILQ_HEAD(rawpacket_tailhead, rawpacket);
|
TAILQ_HEAD(rawpacket_tailhead, rawpacket);
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ const char *progname = "nfqws";
|
|||||||
#error UNKNOWN_SYSTEM_TIME
|
#error UNKNOWN_SYSTEM_TIME
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int DLOG_FILE(FILE *F, const char *format, va_list args)
|
int DLOG_FILE(FILE *F, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
return vfprintf(F, format, args);
|
return vfprintf(F, format, args);
|
||||||
@ -116,7 +115,6 @@ int DLOG_PERROR(const char *s)
|
|||||||
return DLOG_ERR("%s: %s\n", s, strerror(errno));
|
return DLOG_ERR("%s: %s\n", s, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int LOG_APPEND(const char *filename, const char *format, va_list args)
|
int LOG_APPEND(const char *filename, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
@ -33,7 +33,12 @@
|
|||||||
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
||||||
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
|
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
|
||||||
|
|
||||||
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 params_s
|
||||||
{
|
{
|
||||||
|
20
nfq/pools.c
20
nfq/pools.c
@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
#define DESTROY_STR_POOL(etype, ppool) \
|
#define DESTROY_STR_POOL(etype, ppool) \
|
||||||
etype *elem, *tmp; \
|
etype *elem, *tmp; \
|
||||||
HASH_ITER(hh, *ppool, elem, tmp) { \
|
HASH_ITER(hh, *ppool, elem, tmp) \
|
||||||
|
{ \
|
||||||
free(elem->str); \
|
free(elem->str); \
|
||||||
HASH_DEL(*ppool, elem); \
|
HASH_DEL(*ppool, elem); \
|
||||||
free(elem); \
|
free(elem); \
|
||||||
@ -32,7 +33,6 @@
|
|||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef uthash_nonfatal_oom
|
#undef uthash_nonfatal_oom
|
||||||
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
|
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
|
||||||
static bool oom = false;
|
static bool oom = false;
|
||||||
@ -65,13 +65,8 @@ void StrPoolDestroy(strpool **pp)
|
|||||||
DESTROY_STR_POOL(strpool, pp)
|
DESTROY_STR_POOL(strpool, pp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HostFailPoolDestroy(hostfail_pool **pp){
|
||||||
|
DESTROY_STR_POOL(hostfail_pool, pp)} hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time)
|
||||||
void HostFailPoolDestroy(hostfail_pool **pp)
|
|
||||||
{
|
|
||||||
DESTROY_STR_POOL(hostfail_pool, pp)
|
|
||||||
}
|
|
||||||
hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
|
|
||||||
{
|
{
|
||||||
size_t slen = strlen(s);
|
size_t slen = strlen(s);
|
||||||
ADD_STR_POOL(hostfail_pool, pp, s, slen)
|
ADD_STR_POOL(hostfail_pool, pp, s, slen)
|
||||||
@ -123,11 +118,11 @@ void HostFailPoolDump(hostfail_pool *p)
|
|||||||
printf("host=%s counter=%d time_left=%lld\n", elem->str, elem->counter, (long long int)elem->expire - now);
|
printf("host=%s counter=%d time_left=%lld\n", elem->str, elem->counter, (long long int)elem->expire - now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool strlist_add(struct str_list_head *head, const char *filename)
|
bool strlist_add(struct str_list_head *head, const char *filename)
|
||||||
{
|
{
|
||||||
struct str_list *entry = malloc(sizeof(struct str_list));
|
struct str_list *entry = malloc(sizeof(struct str_list));
|
||||||
if (!entry) return false;
|
if (!entry)
|
||||||
|
return false;
|
||||||
entry->str = strdup(filename);
|
entry->str = strdup(filename);
|
||||||
if (!entry->str)
|
if (!entry->str)
|
||||||
{
|
{
|
||||||
@ -139,7 +134,8 @@ bool strlist_add(struct str_list_head *head, const char *filename)
|
|||||||
}
|
}
|
||||||
static void strlist_entry_destroy(struct str_list *entry)
|
static void strlist_entry_destroy(struct str_list *entry)
|
||||||
{
|
{
|
||||||
if (entry->str) free(entry->str);
|
if (entry->str)
|
||||||
|
free(entry->str);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
void strlist_destroy(struct str_list_head *head)
|
void strlist_destroy(struct str_list_head *head)
|
||||||
|
13
nfq/pools.h
13
nfq/pools.h
@ -10,7 +10,8 @@
|
|||||||
#define HASH_FUNCTION HASH_BER
|
#define HASH_FUNCTION HASH_BER
|
||||||
#include "uthash.h"
|
#include "uthash.h"
|
||||||
|
|
||||||
typedef struct strpool {
|
typedef struct strpool
|
||||||
|
{
|
||||||
char *str; /* key */
|
char *str; /* key */
|
||||||
UT_hash_handle hh; /* makes this structure hashable */
|
UT_hash_handle hh; /* makes this structure hashable */
|
||||||
} strpool;
|
} strpool;
|
||||||
@ -20,14 +21,16 @@ bool StrPoolAddStr(strpool **pp,const char *s);
|
|||||||
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen);
|
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen);
|
||||||
bool StrPoolCheckStr(strpool *p, const char *s);
|
bool StrPoolCheckStr(strpool *p, const char *s);
|
||||||
|
|
||||||
struct str_list {
|
struct str_list
|
||||||
|
{
|
||||||
char *str;
|
char *str;
|
||||||
LIST_ENTRY(str_list) next;
|
LIST_ENTRY(str_list)
|
||||||
|
next;
|
||||||
};
|
};
|
||||||
LIST_HEAD(str_list_head, str_list);
|
LIST_HEAD(str_list_head, str_list);
|
||||||
|
|
||||||
|
typedef struct hostfail_pool
|
||||||
typedef struct hostfail_pool {
|
{
|
||||||
char *str; /* key */
|
char *str; /* key */
|
||||||
int counter; /* value */
|
int counter; /* value */
|
||||||
time_t expire; /* when to expire record (unixtime) */
|
time_t expire; /* when to expire record (unixtime) */
|
||||||
|
375
nfq/protocol.c
375
nfq/protocol.c
@ -30,7 +30,8 @@ bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs)
|
|||||||
if (!*pHost)
|
if (!*pHost)
|
||||||
{
|
{
|
||||||
*pHost = memmem(buf, bs, "\nHost:", 6);
|
*pHost = memmem(buf, bs, "\nHost:", 6);
|
||||||
if (*pHost) (*pHost)++;
|
if (*pHost)
|
||||||
|
(*pHost)++;
|
||||||
}
|
}
|
||||||
return !!*pHost;
|
return !!*pHost;
|
||||||
}
|
}
|
||||||
@ -39,7 +40,8 @@ bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs)
|
|||||||
if (!*pHost)
|
if (!*pHost)
|
||||||
{
|
{
|
||||||
*pHost = memmem(buf, bs, "\nHost:", 6);
|
*pHost = memmem(buf, bs, "\nHost:", 6);
|
||||||
if (*pHost) (*pHost)++;
|
if (*pHost)
|
||||||
|
(*pHost)++;
|
||||||
}
|
}
|
||||||
return !!*pHost;
|
return !!*pHost;
|
||||||
}
|
}
|
||||||
@ -61,18 +63,23 @@ bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char
|
|||||||
const uint8_t *p, *s, *e = data + len;
|
const uint8_t *p, *s, *e = data + len;
|
||||||
|
|
||||||
p = (uint8_t *)strncasestr((char *)data, header, len);
|
p = (uint8_t *)strncasestr((char *)data, header, len);
|
||||||
if (!p) return false;
|
if (!p)
|
||||||
|
return false;
|
||||||
p += strlen(header);
|
p += strlen(header);
|
||||||
while (p < e && (*p == ' ' || *p == '\t')) p++;
|
while (p < e && (*p == ' ' || *p == '\t'))
|
||||||
|
p++;
|
||||||
s = p;
|
s = p;
|
||||||
while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t')) s++;
|
while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t'))
|
||||||
|
s++;
|
||||||
if (s > p)
|
if (s > p)
|
||||||
{
|
{
|
||||||
size_t slen = s - p;
|
size_t slen = s - p;
|
||||||
if (buf && len_buf)
|
if (buf && len_buf)
|
||||||
{
|
{
|
||||||
if (slen >= len_buf) slen = len_buf - 1;
|
if (slen >= len_buf)
|
||||||
for (size_t i = 0; i < slen; i++) buf[i] = tolower(p[i]);
|
slen = len_buf - 1;
|
||||||
|
for (size_t i = 0; i < slen; i++)
|
||||||
|
buf[i] = tolower(p[i]);
|
||||||
buf[slen] = 0;
|
buf[slen] = 0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -88,9 +95,13 @@ const char *HttpFind2ndLevelDomain(const char *host)
|
|||||||
const char *p = NULL;
|
const char *p = NULL;
|
||||||
if (*host)
|
if (*host)
|
||||||
{
|
{
|
||||||
for (p = host + strlen(host)-1; p>host && *p!='.'; p--);
|
for (p = host + strlen(host) - 1; p > host && *p != '.'; p--)
|
||||||
if (*p=='.') for (p--; p>host && *p!='.'; p--);
|
;
|
||||||
if (*p=='.') p++;
|
if (*p == '.')
|
||||||
|
for (p--; p > host && *p != '.'; p--)
|
||||||
|
;
|
||||||
|
if (*p == '.')
|
||||||
|
p++;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -100,11 +111,13 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
|||||||
char loc[256], *redirect_host, *p;
|
char loc[256], *redirect_host, *p;
|
||||||
int code;
|
int code;
|
||||||
|
|
||||||
if (!host || !*host) return false;
|
if (!host || !*host)
|
||||||
|
return false;
|
||||||
|
|
||||||
code = HttpReplyCode(data, len);
|
code = HttpReplyCode(data, len);
|
||||||
|
|
||||||
if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false;
|
if ((code != 302 && code != 307) || !HttpExtractHeader(data, len, "\nLocation:", loc, sizeof(loc)))
|
||||||
|
return false;
|
||||||
|
|
||||||
// something like : https://censor.net/badpage.php?reason=denied&source=RKN
|
// something like : https://censor.net/badpage.php?reason=denied&source=RKN
|
||||||
|
|
||||||
@ -117,9 +130,11 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
|||||||
|
|
||||||
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
|
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
|
||||||
|
|
||||||
for(p=redirect_host; *p && *p!='/' ; p++);
|
for (p = redirect_host; *p && *p != '/'; p++)
|
||||||
|
;
|
||||||
*p = 0;
|
*p = 0;
|
||||||
if (!*redirect_host) return false;
|
if (!*redirect_host)
|
||||||
|
return false;
|
||||||
|
|
||||||
// somethinkg like : censor.net
|
// somethinkg like : censor.net
|
||||||
|
|
||||||
@ -140,17 +155,24 @@ size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http,
|
|||||||
case httpreqpos_method:
|
case httpreqpos_method:
|
||||||
// recognize some tpws pre-applied hacks
|
// recognize some tpws pre-applied hacks
|
||||||
method = http;
|
method = http;
|
||||||
if (sz<10) break;
|
if (sz < 10)
|
||||||
if (*method=='\n' || *method=='\r') method++;
|
break;
|
||||||
if (*method=='\n' || *method=='\r') method++;
|
if (*method == '\n' || *method == '\r')
|
||||||
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
|
method++;
|
||||||
if (i<3 || *method!=' ') break;
|
if (*method == '\n' || *method == '\r')
|
||||||
|
method++;
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
if (*method >= 'A' && *method <= 'Z')
|
||||||
|
method++;
|
||||||
|
if (i < 3 || *method != ' ')
|
||||||
|
break;
|
||||||
return method - http - 1;
|
return method - http - 1;
|
||||||
case httpreqpos_host:
|
case httpreqpos_host:
|
||||||
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
|
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
|
||||||
{
|
{
|
||||||
host += 5;
|
host += 5;
|
||||||
if (*host==' ') host++;
|
if (*host == ' ')
|
||||||
|
host++;
|
||||||
return host - http;
|
return host - http;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -162,7 +184,6 @@ size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http,
|
|||||||
return hpos_pos < sz ? hpos_pos : 0;
|
return hpos_pos < sz ? hpos_pos : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t TLSRecordDataLen(const uint8_t *data)
|
uint16_t TLSRecordDataLen(const uint8_t *data)
|
||||||
{
|
{
|
||||||
return pntoh16(data + 3);
|
return pntoh16(data + 3);
|
||||||
@ -193,7 +214,6 @@ bool IsTLSHandshakeFull(const uint8_t *data, size_t len)
|
|||||||
return (4 + TLSHandshakeLen(data)) <= len;
|
return (4 + TLSHandshakeLen(data)) <= len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// bPartialIsOK=true - accept partial packets not containing the whole TLS message
|
// bPartialIsOK=true - accept partial packets not containing the whole TLS message
|
||||||
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK)
|
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK)
|
||||||
{
|
{
|
||||||
@ -212,40 +232,51 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
|
|||||||
|
|
||||||
size_t l;
|
size_t l;
|
||||||
|
|
||||||
if (!bPartialIsOK && !IsTLSHandshakeFull(data,len)) return false;
|
if (!bPartialIsOK && !IsTLSHandshakeFull(data, len))
|
||||||
|
return false;
|
||||||
|
|
||||||
l = 1 + 3 + 2 + 32;
|
l = 1 + 3 + 2 + 32;
|
||||||
// SessionIDLength
|
// SessionIDLength
|
||||||
if (len < (l + 1)) return false;
|
if (len < (l + 1))
|
||||||
|
return false;
|
||||||
l += data[l] + 1;
|
l += data[l] + 1;
|
||||||
// CipherSuitesLength
|
// CipherSuitesLength
|
||||||
if (len < (l + 2)) return false;
|
if (len < (l + 2))
|
||||||
|
return false;
|
||||||
l += pntoh16(data + l) + 2;
|
l += pntoh16(data + l) + 2;
|
||||||
// CompressionMethodsLength
|
// CompressionMethodsLength
|
||||||
if (len < (l + 1)) return false;
|
if (len < (l + 1))
|
||||||
|
return false;
|
||||||
l += data[l] + 1;
|
l += data[l] + 1;
|
||||||
// ExtensionsLength
|
// ExtensionsLength
|
||||||
if (len < (l + 2)) return false;
|
if (len < (l + 2))
|
||||||
|
return false;
|
||||||
|
|
||||||
data += l; len -= l;
|
data += l;
|
||||||
|
len -= l;
|
||||||
l = pntoh16(data);
|
l = pntoh16(data);
|
||||||
data += 2; len -= 2;
|
data += 2;
|
||||||
|
len -= 2;
|
||||||
|
|
||||||
if (bPartialIsOK)
|
if (bPartialIsOK)
|
||||||
{
|
{
|
||||||
if (len < l) l = len;
|
if (len < l)
|
||||||
|
l = len;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (len < l) return false;
|
if (len < l)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (l >= 4)
|
while (l >= 4)
|
||||||
{
|
{
|
||||||
uint16_t etype = pntoh16(data);
|
uint16_t etype = pntoh16(data);
|
||||||
size_t elen = pntoh16(data + 2);
|
size_t elen = pntoh16(data + 2);
|
||||||
data += 4; l -= 4;
|
data += 4;
|
||||||
if (l < elen) break;
|
l -= 4;
|
||||||
|
if (l < elen)
|
||||||
|
break;
|
||||||
if (etype == type)
|
if (etype == type)
|
||||||
{
|
{
|
||||||
if (ext && len_ext)
|
if (ext && len_ext)
|
||||||
@ -255,7 +286,8 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
data += elen; l -= elen;
|
data += elen;
|
||||||
|
l -= elen;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -267,9 +299,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
|||||||
// u16 Version: TLS1.0
|
// u16 Version: TLS1.0
|
||||||
// u16 Length
|
// u16 Length
|
||||||
size_t reclen;
|
size_t reclen;
|
||||||
if (!IsTLSClientHello(data, len, bPartialIsOK)) return false;
|
if (!IsTLSClientHello(data, len, bPartialIsOK))
|
||||||
|
return false;
|
||||||
reclen = TLSRecordLen(data);
|
reclen = TLSRecordLen(data);
|
||||||
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
|
if (reclen < len)
|
||||||
|
len = reclen; // correct len if it has more data than the first tls record has
|
||||||
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
||||||
}
|
}
|
||||||
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
|
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
|
||||||
@ -277,14 +311,19 @@ static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, s
|
|||||||
// u16 data+0 - name list length
|
// u16 data+0 - name list length
|
||||||
// u8 data+2 - server name type. 0=host_name
|
// u8 data+2 - server name type. 0=host_name
|
||||||
// u16 data+3 - server name length
|
// u16 data+3 - server name length
|
||||||
if (elen < 5 || ext[2] != 0) return false;
|
if (elen < 5 || ext[2] != 0)
|
||||||
|
return false;
|
||||||
size_t slen = pntoh16(ext + 3);
|
size_t slen = pntoh16(ext + 3);
|
||||||
ext += 5; elen -= 5;
|
ext += 5;
|
||||||
if (slen < elen) return false;
|
elen -= 5;
|
||||||
|
if (slen < elen)
|
||||||
|
return false;
|
||||||
if (host && len_host)
|
if (host && len_host)
|
||||||
{
|
{
|
||||||
if (slen >= len_host) slen = len_host - 1;
|
if (slen >= len_host)
|
||||||
for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]);
|
slen = len_host - 1;
|
||||||
|
for (size_t i = 0; i < slen; i++)
|
||||||
|
host[i] = tolower(ext[i]);
|
||||||
host[slen] = 0;
|
host[slen] = 0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -294,7 +333,8 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len
|
|||||||
const uint8_t *ext;
|
const uint8_t *ext;
|
||||||
size_t elen;
|
size_t elen;
|
||||||
|
|
||||||
if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK))
|
||||||
|
return false;
|
||||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||||
}
|
}
|
||||||
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK)
|
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK)
|
||||||
@ -302,7 +342,8 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
|||||||
const uint8_t *ext;
|
const uint8_t *ext;
|
||||||
size_t elen;
|
size_t elen;
|
||||||
|
|
||||||
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK))
|
||||||
|
return false;
|
||||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||||
}
|
}
|
||||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
||||||
@ -323,27 +364,30 @@ size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static uint8_t tvb_get_varint(const uint8_t *tvb, uint64_t *value)
|
static uint8_t tvb_get_varint(const uint8_t *tvb, uint64_t *value)
|
||||||
{
|
{
|
||||||
switch (*tvb >> 6)
|
switch (*tvb >> 6)
|
||||||
{
|
{
|
||||||
case 0: /* 0b00 => 1 byte length (6 bits Usable) */
|
case 0: /* 0b00 => 1 byte length (6 bits Usable) */
|
||||||
if (value) *value = *tvb & 0x3F;
|
if (value)
|
||||||
|
*value = *tvb & 0x3F;
|
||||||
return 1;
|
return 1;
|
||||||
case 1: /* 0b01 => 2 bytes length (14 bits Usable) */
|
case 1: /* 0b01 => 2 bytes length (14 bits Usable) */
|
||||||
if (value) *value = pntoh16(tvb) & 0x3FFF;
|
if (value)
|
||||||
|
*value = pntoh16(tvb) & 0x3FFF;
|
||||||
return 2;
|
return 2;
|
||||||
case 2: /* 0b10 => 4 bytes length (30 bits Usable) */
|
case 2: /* 0b10 => 4 bytes length (30 bits Usable) */
|
||||||
if (value) *value = pntoh32(tvb) & 0x3FFFFFFF;
|
if (value)
|
||||||
|
*value = pntoh32(tvb) & 0x3FFFFFFF;
|
||||||
return 4;
|
return 4;
|
||||||
case 3: /* 0b11 => 8 bytes length (62 bits Usable) */
|
case 3: /* 0b11 => 8 bytes length (62 bits Usable) */
|
||||||
if (value) *value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF;
|
if (value)
|
||||||
|
*value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF;
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
// impossible case
|
// impossible case
|
||||||
if (*value) *value = 0;
|
if (*value)
|
||||||
|
*value = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static uint8_t tvb_get_size(uint8_t tvb)
|
static uint8_t tvb_get_size(uint8_t tvb)
|
||||||
@ -355,15 +399,21 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
|
|||||||
{
|
{
|
||||||
size_t offset = 1;
|
size_t offset = 1;
|
||||||
uint64_t coff, clen;
|
uint64_t coff, clen;
|
||||||
if (len < 3 || *data != 6) return false;
|
if (len < 3 || *data != 6)
|
||||||
if ((offset+tvb_get_size(data[offset])) >= len) return false;
|
return false;
|
||||||
|
if ((offset + tvb_get_size(data[offset])) >= len)
|
||||||
|
return false;
|
||||||
offset += tvb_get_varint(data + offset, &coff);
|
offset += tvb_get_varint(data + offset, &coff);
|
||||||
// offset must be 0 if it's a full segment, not just a chunk
|
// offset must be 0 if it's a full segment, not just a chunk
|
||||||
if (coff || (offset+tvb_get_size(data[offset])) >= len) return false;
|
if (coff || (offset + tvb_get_size(data[offset])) >= len)
|
||||||
|
return false;
|
||||||
offset += tvb_get_varint(data + offset, &clen);
|
offset += tvb_get_varint(data + offset, &clen);
|
||||||
if ((offset + clen) > len || !IsTLSHandshakeClientHello(data+offset,clen)) return false;
|
if ((offset + clen) > len || !IsTLSHandshakeClientHello(data + offset, clen))
|
||||||
if (hello_offset) *hello_offset = offset;
|
return false;
|
||||||
if (hello_len) *hello_len = (size_t)clen;
|
if (hello_offset)
|
||||||
|
*hello_offset = offset;
|
||||||
|
if (hello_len)
|
||||||
|
*hello_len = (size_t)clen;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,22 +421,26 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
|
|||||||
uint8_t QUICDraftVersion(uint32_t version)
|
uint8_t QUICDraftVersion(uint32_t version)
|
||||||
{
|
{
|
||||||
/* IETF Draft versions */
|
/* IETF Draft versions */
|
||||||
if ((version >> 8) == 0xff0000) {
|
if ((version >> 8) == 0xff0000)
|
||||||
|
{
|
||||||
return (uint8_t)version;
|
return (uint8_t)version;
|
||||||
}
|
}
|
||||||
/* Facebook mvfst, based on draft -22. */
|
/* Facebook mvfst, based on draft -22. */
|
||||||
if (version == 0xfaceb001) {
|
if (version == 0xfaceb001)
|
||||||
|
{
|
||||||
return 22;
|
return 22;
|
||||||
}
|
}
|
||||||
/* Facebook mvfst, based on draft -27. */
|
/* Facebook mvfst, based on draft -27. */
|
||||||
if (version == 0xfaceb002 || version == 0xfaceb00e) {
|
if (version == 0xfaceb002 || version == 0xfaceb00e)
|
||||||
|
{
|
||||||
return 27;
|
return 27;
|
||||||
}
|
}
|
||||||
/* GQUIC Q050, T050 and T051: they are not really based on any drafts,
|
/* GQUIC Q050, T050 and T051: they are not really based on any drafts,
|
||||||
* but we must return a sensible value */
|
* but we must return a sensible value */
|
||||||
if (version == 0x51303530 ||
|
if (version == 0x51303530 ||
|
||||||
version == 0x54303530 ||
|
version == 0x54303530 ||
|
||||||
version == 0x54303531) {
|
version == 0x54303531)
|
||||||
|
{
|
||||||
return 27;
|
return 27;
|
||||||
}
|
}
|
||||||
/* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15
|
/* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15
|
||||||
@ -396,17 +450,20 @@ uint8_t QUICDraftVersion(uint32_t version)
|
|||||||
used to select a proper salt (which depends on the version itself), but
|
used to select a proper salt (which depends on the version itself), but
|
||||||
we don't have a real version here! Let's hope that we need to handle
|
we don't have a real version here! Let's hope that we need to handle
|
||||||
only latest drafts... */
|
only latest drafts... */
|
||||||
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) {
|
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a)
|
||||||
|
{
|
||||||
return 29;
|
return 29;
|
||||||
}
|
}
|
||||||
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
|
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
|
||||||
final draft version */
|
final draft version */
|
||||||
if (version == 0x00000001) {
|
if (version == 0x00000001)
|
||||||
|
{
|
||||||
return 34;
|
return 34;
|
||||||
}
|
}
|
||||||
/* QUIC Version 2 */
|
/* QUIC Version 2 */
|
||||||
/* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */
|
/* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */
|
||||||
if (version == 0x709A50C4) {
|
if (version == 0x709A50C4)
|
||||||
|
{
|
||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -426,9 +483,11 @@ static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, co
|
|||||||
uint8_t hkdflabel[64];
|
uint8_t hkdflabel[64];
|
||||||
|
|
||||||
size_t label_size = strlen(label);
|
size_t label_size = strlen(label);
|
||||||
if (label_size > 255) return false;
|
if (label_size > 255)
|
||||||
|
return false;
|
||||||
size_t hkdflabel_size = 2 + 1 + label_size + 1;
|
size_t hkdflabel_size = 2 + 1 + label_size + 1;
|
||||||
if (hkdflabel_size > sizeof(hkdflabel)) return false;
|
if (hkdflabel_size > sizeof(hkdflabel))
|
||||||
|
return false;
|
||||||
|
|
||||||
phton16(hkdflabel, out_len);
|
phton16(hkdflabel, out_len);
|
||||||
hkdflabel[2] = (uint8_t)label_size;
|
hkdflabel[2] = (uint8_t)label_size;
|
||||||
@ -454,69 +513,89 @@ static bool quic_derive_initial_secret(const quic_cid_t *cid, uint8_t *client_in
|
|||||||
*/
|
*/
|
||||||
static const uint8_t handshake_salt_draft_22[20] = {
|
static const uint8_t handshake_salt_draft_22[20] = {
|
||||||
0x7f, 0xbc, 0xdb, 0x0e, 0x7c, 0x66, 0xbb, 0xe9, 0x19, 0x3a,
|
0x7f, 0xbc, 0xdb, 0x0e, 0x7c, 0x66, 0xbb, 0xe9, 0x19, 0x3a,
|
||||||
0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a
|
0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a};
|
||||||
};
|
|
||||||
static const uint8_t handshake_salt_draft_23[20] = {
|
static const uint8_t handshake_salt_draft_23[20] = {
|
||||||
0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7,
|
0xc3,
|
||||||
0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02,
|
0xee,
|
||||||
|
0xf7,
|
||||||
|
0x12,
|
||||||
|
0xc7,
|
||||||
|
0x2e,
|
||||||
|
0xbb,
|
||||||
|
0x5a,
|
||||||
|
0x11,
|
||||||
|
0xa7,
|
||||||
|
0xd2,
|
||||||
|
0x43,
|
||||||
|
0x2b,
|
||||||
|
0xb4,
|
||||||
|
0x63,
|
||||||
|
0x65,
|
||||||
|
0xbe,
|
||||||
|
0xf9,
|
||||||
|
0xf5,
|
||||||
|
0x02,
|
||||||
};
|
};
|
||||||
static const uint8_t handshake_salt_draft_29[20] = {
|
static const uint8_t handshake_salt_draft_29[20] = {
|
||||||
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97,
|
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97,
|
||||||
0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99
|
0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99};
|
||||||
};
|
|
||||||
static const uint8_t handshake_salt_v1[20] = {
|
static const uint8_t handshake_salt_v1[20] = {
|
||||||
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17,
|
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17,
|
||||||
0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a
|
0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a};
|
||||||
};
|
|
||||||
static const uint8_t hanshake_salt_draft_q50[20] = {
|
static const uint8_t hanshake_salt_draft_q50[20] = {
|
||||||
0x50, 0x45, 0x74, 0xEF, 0xD0, 0x66, 0xFE, 0x2F, 0x9D, 0x94,
|
0x50, 0x45, 0x74, 0xEF, 0xD0, 0x66, 0xFE, 0x2F, 0x9D, 0x94,
|
||||||
0x5C, 0xFC, 0xDB, 0xD3, 0xA7, 0xF0, 0xD3, 0xB5, 0x6B, 0x45
|
0x5C, 0xFC, 0xDB, 0xD3, 0xA7, 0xF0, 0xD3, 0xB5, 0x6B, 0x45};
|
||||||
};
|
|
||||||
static const uint8_t hanshake_salt_draft_t50[20] = {
|
static const uint8_t hanshake_salt_draft_t50[20] = {
|
||||||
0x7f, 0xf5, 0x79, 0xe5, 0xac, 0xd0, 0x72, 0x91, 0x55, 0x80,
|
0x7f, 0xf5, 0x79, 0xe5, 0xac, 0xd0, 0x72, 0x91, 0x55, 0x80,
|
||||||
0x30, 0x4c, 0x43, 0xa2, 0x36, 0x7c, 0x60, 0x48, 0x83, 0x10
|
0x30, 0x4c, 0x43, 0xa2, 0x36, 0x7c, 0x60, 0x48, 0x83, 0x10};
|
||||||
};
|
|
||||||
static const uint8_t hanshake_salt_draft_t51[20] = {
|
static const uint8_t hanshake_salt_draft_t51[20] = {
|
||||||
0x7a, 0x4e, 0xde, 0xf4, 0xe7, 0xcc, 0xee, 0x5f, 0xa4, 0x50,
|
0x7a, 0x4e, 0xde, 0xf4, 0xe7, 0xcc, 0xee, 0x5f, 0xa4, 0x50,
|
||||||
0x6c, 0x19, 0x12, 0x4f, 0xc8, 0xcc, 0xda, 0x6e, 0x03, 0x3d
|
0x6c, 0x19, 0x12, 0x4f, 0xc8, 0xcc, 0xda, 0x6e, 0x03, 0x3d};
|
||||||
};
|
|
||||||
static const uint8_t handshake_salt_v2[20] = {
|
static const uint8_t handshake_salt_v2[20] = {
|
||||||
0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93,
|
0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93,
|
||||||
0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9
|
0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9};
|
||||||
};
|
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
const uint8_t *salt;
|
const uint8_t *salt;
|
||||||
uint8_t secret[USHAMaxHashSize];
|
uint8_t secret[USHAMaxHashSize];
|
||||||
uint8_t draft_version = QUICDraftVersion(version);
|
uint8_t draft_version = QUICDraftVersion(version);
|
||||||
|
|
||||||
if (version == 0x51303530) {
|
if (version == 0x51303530)
|
||||||
|
{
|
||||||
salt = hanshake_salt_draft_q50;
|
salt = hanshake_salt_draft_q50;
|
||||||
}
|
}
|
||||||
else if (version == 0x54303530) {
|
else if (version == 0x54303530)
|
||||||
|
{
|
||||||
salt = hanshake_salt_draft_t50;
|
salt = hanshake_salt_draft_t50;
|
||||||
}
|
}
|
||||||
else if (version == 0x54303531) {
|
else if (version == 0x54303531)
|
||||||
|
{
|
||||||
salt = hanshake_salt_draft_t51;
|
salt = hanshake_salt_draft_t51;
|
||||||
}
|
}
|
||||||
else if (is_quic_draft_max(draft_version, 22)) {
|
else if (is_quic_draft_max(draft_version, 22))
|
||||||
|
{
|
||||||
salt = handshake_salt_draft_22;
|
salt = handshake_salt_draft_22;
|
||||||
}
|
}
|
||||||
else if (is_quic_draft_max(draft_version, 28)) {
|
else if (is_quic_draft_max(draft_version, 28))
|
||||||
|
{
|
||||||
salt = handshake_salt_draft_23;
|
salt = handshake_salt_draft_23;
|
||||||
}
|
}
|
||||||
else if (is_quic_draft_max(draft_version, 32)) {
|
else if (is_quic_draft_max(draft_version, 32))
|
||||||
|
{
|
||||||
salt = handshake_salt_draft_29;
|
salt = handshake_salt_draft_29;
|
||||||
}
|
}
|
||||||
else if (is_quic_draft_max(draft_version, 34)) {
|
else if (is_quic_draft_max(draft_version, 34))
|
||||||
|
{
|
||||||
salt = handshake_salt_v1;
|
salt = handshake_salt_v1;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
salt = handshake_salt_v2;
|
salt = handshake_salt_v2;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = hkdfExtract(SHA256, salt, 20, cid->cid, cid->len, secret);
|
err = hkdfExtract(SHA256, salt, 20, cid->cid, cid->len, secret);
|
||||||
if (err) return false;
|
if (err)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (client_initial_secret && !quic_hkdf_expand_label(secret, SHA256HashSize, "tls13 client in", client_initial_secret, SHA256HashSize))
|
if (client_initial_secret && !quic_hkdf_expand_label(secret, SHA256HashSize, "tls13 client in", client_initial_secret, SHA256HashSize))
|
||||||
return false;
|
return false;
|
||||||
@ -534,7 +613,8 @@ uint32_t QUICExtractVersion(const uint8_t *data, size_t len)
|
|||||||
}
|
}
|
||||||
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid)
|
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid)
|
||||||
{
|
{
|
||||||
if (!QUICIsLongHeader(data,len) || !data[5] || data[5] > QUIC_MAX_CID_LENGTH || (6+data[5])>len) return false;
|
if (!QUICIsLongHeader(data, len) || !data[5] || data[5] > QUIC_MAX_CID_LENGTH || (6 + data[5]) > len)
|
||||||
|
return false;
|
||||||
cid->len = data[5];
|
cid->len = data[5];
|
||||||
memcpy(&cid->cid, data + 6, data[5]);
|
memcpy(&cid->cid, data + 6, data[5]);
|
||||||
return true;
|
return true;
|
||||||
@ -542,13 +622,16 @@ bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid)
|
|||||||
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len)
|
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len)
|
||||||
{
|
{
|
||||||
uint32_t ver = QUICExtractVersion(data, data_len);
|
uint32_t ver = QUICExtractVersion(data, data_len);
|
||||||
if (!ver) return false;
|
if (!ver)
|
||||||
|
return false;
|
||||||
|
|
||||||
quic_cid_t dcid;
|
quic_cid_t dcid;
|
||||||
if (!QUICExtractDCID(data, data_len, &dcid)) return false;
|
if (!QUICExtractDCID(data, data_len, &dcid))
|
||||||
|
return false;
|
||||||
|
|
||||||
uint8_t client_initial_secret[SHA256HashSize];
|
uint8_t client_initial_secret[SHA256HashSize];
|
||||||
if (!quic_derive_initial_secret(&dcid, client_initial_secret, ver)) return false;
|
if (!quic_derive_initial_secret(&dcid, client_initial_secret, ver))
|
||||||
|
return false;
|
||||||
|
|
||||||
uint8_t aeskey[16], aesiv[12], aeshp[16];
|
uint8_t aeskey[16], aesiv[12], aeshp[16];
|
||||||
bool v1_label = !is_quic_v2(ver);
|
bool v1_label = !is_quic_v2(ver);
|
||||||
@ -562,20 +645,25 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
|
|||||||
uint64_t payload_len, token_len;
|
uint64_t payload_len, token_len;
|
||||||
size_t pn_offset;
|
size_t pn_offset;
|
||||||
pn_offset = 1 + 4 + 1 + data[5];
|
pn_offset = 1 + 4 + 1 + data[5];
|
||||||
if (pn_offset >= data_len) return false;
|
if (pn_offset >= data_len)
|
||||||
|
return false;
|
||||||
pn_offset += 1 + data[pn_offset];
|
pn_offset += 1 + data[pn_offset];
|
||||||
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
|
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len)
|
||||||
|
return false;
|
||||||
pn_offset += tvb_get_varint(data + pn_offset, &token_len);
|
pn_offset += tvb_get_varint(data + pn_offset, &token_len);
|
||||||
pn_offset += token_len;
|
pn_offset += token_len;
|
||||||
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
|
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len)
|
||||||
|
return false;
|
||||||
pn_offset += tvb_get_varint(data + pn_offset, &payload_len);
|
pn_offset += tvb_get_varint(data + pn_offset, &payload_len);
|
||||||
if (payload_len<20 || (pn_offset + payload_len)>data_len) return false;
|
if (payload_len < 20 || (pn_offset + payload_len) > data_len)
|
||||||
|
return false;
|
||||||
|
|
||||||
aes_init_keygen_tables();
|
aes_init_keygen_tables();
|
||||||
|
|
||||||
uint8_t sample_enc[16];
|
uint8_t sample_enc[16];
|
||||||
aes_context ctx;
|
aes_context ctx;
|
||||||
if (aes_setkey(&ctx, 1, aeshp, sizeof(aeshp)) || aes_cipher(&ctx, data + pn_offset + 4, sample_enc)) return false;
|
if (aes_setkey(&ctx, 1, aeshp, sizeof(aeshp)) || aes_cipher(&ctx, data + pn_offset + 4, sample_enc))
|
||||||
|
return false;
|
||||||
|
|
||||||
uint8_t mask[5];
|
uint8_t mask[5];
|
||||||
memcpy(mask, sample_enc, sizeof(mask));
|
memcpy(mask, sample_enc, sizeof(mask));
|
||||||
@ -586,21 +674,25 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
|
|||||||
uint8_t pkn_bytes[4];
|
uint8_t pkn_bytes[4];
|
||||||
memcpy(pkn_bytes, data + pn_offset, pkn_len);
|
memcpy(pkn_bytes, data + pn_offset, pkn_len);
|
||||||
uint32_t pkn = 0;
|
uint32_t pkn = 0;
|
||||||
for (uint8_t i = 0; i < pkn_len; i++) pkn |= (uint32_t)(pkn_bytes[i] ^ mask[1 + i]) << (8 * (pkn_len - 1 - i));
|
for (uint8_t i = 0; i < pkn_len; i++)
|
||||||
|
pkn |= (uint32_t)(pkn_bytes[i] ^ mask[1 + i]) << (8 * (pkn_len - 1 - i));
|
||||||
|
|
||||||
phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn);
|
phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn);
|
||||||
|
|
||||||
size_t cryptlen = payload_len - pkn_len - 16;
|
size_t cryptlen = payload_len - pkn_len - 16;
|
||||||
if (cryptlen > *clean_len) return false;
|
if (cryptlen > *clean_len)
|
||||||
|
return false;
|
||||||
*clean_len = cryptlen;
|
*clean_len = cryptlen;
|
||||||
const uint8_t *decrypt_begin = data + pn_offset + pkn_len;
|
const uint8_t *decrypt_begin = data + pn_offset + pkn_len;
|
||||||
|
|
||||||
uint8_t atag[16], header[256];
|
uint8_t atag[16], header[256];
|
||||||
size_t header_len = pn_offset + pkn_len;
|
size_t header_len = pn_offset + pkn_len;
|
||||||
if (header_len > sizeof(header)) return false; // not likely header will be so large
|
if (header_len > sizeof(header))
|
||||||
|
return false; // not likely header will be so large
|
||||||
memcpy(header, data, header_len);
|
memcpy(header, data, header_len);
|
||||||
header[0] = packet0;
|
header[0] = packet0;
|
||||||
for(uint8_t i = 0; i < pkn_len; i++) header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i));
|
for (uint8_t i = 0; i < pkn_len; i++)
|
||||||
|
header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i));
|
||||||
|
|
||||||
if (aes_gcm_crypt(AES_DECRYPT, clean, decrypt_begin, cryptlen, aeskey, sizeof(aeskey), aesiv, sizeof(aesiv), header, header_len, atag, sizeof(atag)))
|
if (aes_gcm_crypt(AES_DECRYPT, clean, decrypt_begin, cryptlen, aeskey, sizeof(aeskey), aesiv, sizeof(aesiv), header, header_len, atag, sizeof(atag)))
|
||||||
return false;
|
return false;
|
||||||
@ -615,7 +707,8 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
|||||||
// chromium randomly splits it and pads with zero/one bytes to force support the standard
|
// chromium randomly splits it and pads with zero/one bytes to force support the standard
|
||||||
// mozilla does not split
|
// mozilla does not split
|
||||||
|
|
||||||
if (*defrag_len<10) return false;
|
if (*defrag_len < 10)
|
||||||
|
return false;
|
||||||
uint8_t *defrag_data = defrag + 10;
|
uint8_t *defrag_data = defrag + 10;
|
||||||
size_t defrag_data_len = *defrag_len - 10;
|
size_t defrag_data_len = *defrag_len - 10;
|
||||||
|
|
||||||
@ -629,25 +722,32 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
|||||||
pos++;
|
pos++;
|
||||||
if (ft > 1) // 00 - padding, 01 - ping
|
if (ft > 1) // 00 - padding, 01 - ping
|
||||||
{
|
{
|
||||||
if (ft!=6) return false; // dont want to know all possible frame type formats
|
if (ft != 6)
|
||||||
|
return false; // don't want to know all possible frame type formats
|
||||||
|
|
||||||
if (pos>=clean_len) return false;
|
if (pos >= clean_len)
|
||||||
|
return false;
|
||||||
|
|
||||||
if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false;
|
if ((pos + tvb_get_size(clean[pos]) >= clean_len))
|
||||||
|
return false;
|
||||||
pos += tvb_get_varint(clean + pos, &offset);
|
pos += tvb_get_varint(clean + pos, &offset);
|
||||||
|
|
||||||
if ((pos+tvb_get_size(clean[pos])>clean_len)) return false;
|
if ((pos + tvb_get_size(clean[pos]) > clean_len))
|
||||||
|
return false;
|
||||||
pos += tvb_get_varint(clean + pos, &sz);
|
pos += tvb_get_varint(clean + pos, &sz);
|
||||||
if ((pos+sz)>clean_len) return false;
|
if ((pos + sz) > clean_len)
|
||||||
|
return false;
|
||||||
|
|
||||||
if ((offset+sz)>defrag_data_len) return false;
|
if ((offset + sz) > defrag_data_len)
|
||||||
|
return false;
|
||||||
if (zeropos < offset)
|
if (zeropos < offset)
|
||||||
// make sure no uninitialized gaps exist in case of not full fragment coverage
|
// make sure no uninitialized gaps exist in case of not full fragment coverage
|
||||||
memset(defrag_data + zeropos, 0, offset - zeropos);
|
memset(defrag_data + zeropos, 0, offset - zeropos);
|
||||||
if ((offset + sz) > zeropos)
|
if ((offset + sz) > zeropos)
|
||||||
zeropos = offset + sz;
|
zeropos = offset + sz;
|
||||||
memcpy(defrag_data + offset, clean + pos, sz);
|
memcpy(defrag_data + offset, clean + pos, sz);
|
||||||
if ((offset+sz) > szmax) szmax = offset+sz;
|
if ((offset + sz) > szmax)
|
||||||
|
szmax = offset + sz;
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
pos += sz;
|
pos += sz;
|
||||||
@ -668,22 +768,29 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
|||||||
|
|
||||||
bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello)
|
bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello)
|
||||||
{
|
{
|
||||||
if (bIsCryptoHello) *bIsCryptoHello=false;
|
if (bIsCryptoHello)
|
||||||
if (bDecryptOK) *bDecryptOK=false;
|
*bIsCryptoHello = false;
|
||||||
|
if (bDecryptOK)
|
||||||
|
*bDecryptOK = false;
|
||||||
|
|
||||||
uint8_t clean[1500];
|
uint8_t clean[1500];
|
||||||
size_t clean_len = sizeof(clean);
|
size_t clean_len = sizeof(clean);
|
||||||
if (!QUICDecryptInitial(data,data_len,clean,&clean_len)) return false;
|
if (!QUICDecryptInitial(data, data_len, clean, &clean_len))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (bDecryptOK) *bDecryptOK=true;
|
if (bDecryptOK)
|
||||||
|
*bDecryptOK = true;
|
||||||
|
|
||||||
uint8_t defrag[1500];
|
uint8_t defrag[1500];
|
||||||
size_t defrag_len = sizeof(defrag);
|
size_t defrag_len = sizeof(defrag);
|
||||||
if (!QUICDefragCrypto(clean,clean_len,defrag,&defrag_len)) return false;
|
if (!QUICDefragCrypto(clean, clean_len, defrag, &defrag_len))
|
||||||
|
return false;
|
||||||
|
|
||||||
size_t hello_offset, hello_len;
|
size_t hello_offset, hello_len;
|
||||||
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len)) return false;
|
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len))
|
||||||
if (bIsCryptoHello) *bIsCryptoHello=true;
|
return false;
|
||||||
|
if (bIsCryptoHello)
|
||||||
|
*bIsCryptoHello = true;
|
||||||
|
|
||||||
return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, true);
|
return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, true);
|
||||||
}
|
}
|
||||||
@ -692,42 +799,48 @@ bool IsQUICInitial(const uint8_t *data, size_t len)
|
|||||||
{
|
{
|
||||||
// too small packets are not likely to be initials with client hello
|
// too small packets are not likely to be initials with client hello
|
||||||
// long header, fixed bit
|
// long header, fixed bit
|
||||||
if (len < 256 || (data[0] & 0xC0)!=0xC0) return false;
|
if (len < 256 || (data[0] & 0xC0) != 0xC0)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint32_t ver = QUICExtractVersion(data, len);
|
uint32_t ver = QUICExtractVersion(data, len);
|
||||||
if (QUICDraftVersion(ver) < 11) return false;
|
if (QUICDraftVersion(ver) < 11)
|
||||||
|
return false;
|
||||||
|
|
||||||
// quic v1 : initial packets are 00b
|
// QUIC v1 : initial packets are 00b
|
||||||
// quic v2 : initial packets are 01b
|
// QUIC v2 : initial packets are 01b
|
||||||
if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00)) return false;
|
if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00))
|
||||||
|
return false;
|
||||||
|
|
||||||
uint64_t offset = 5, sz;
|
uint64_t offset = 5, sz;
|
||||||
|
|
||||||
// DCID. must be present
|
// DCID. must be present
|
||||||
if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH) return false;
|
if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH)
|
||||||
|
return false;
|
||||||
offset += 1 + data[offset];
|
offset += 1 + data[offset];
|
||||||
|
|
||||||
// SCID
|
// SCID
|
||||||
if (data[offset] > QUIC_MAX_CID_LENGTH) return false;
|
if (data[offset] > QUIC_MAX_CID_LENGTH)
|
||||||
|
return false;
|
||||||
offset += 1 + data[offset];
|
offset += 1 + data[offset];
|
||||||
|
|
||||||
// token length
|
// token length
|
||||||
offset += tvb_get_varint(data + offset, &sz);
|
offset += tvb_get_varint(data + offset, &sz);
|
||||||
offset += sz;
|
offset += sz;
|
||||||
if (offset >= len) return false;
|
if (offset >= len)
|
||||||
|
return false;
|
||||||
|
|
||||||
// payload length
|
// payload length
|
||||||
if ((offset + tvb_get_size(data[offset])) > len) return false;
|
if ((offset + tvb_get_size(data[offset])) > len)
|
||||||
|
return false;
|
||||||
tvb_get_varint(data + offset, &sz);
|
tvb_get_varint(data + offset, &sz);
|
||||||
offset += sz;
|
offset += sz;
|
||||||
if (offset > len) return false;
|
if (offset > len)
|
||||||
|
return false;
|
||||||
|
|
||||||
// client hello cannot be too small. likely ACK
|
// ClientHello cannot be too small. likely ACK
|
||||||
return sz >= 96;
|
return sz >= 96;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len)
|
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
return len == 148 && data[0] == 1 && data[1] == 0 && data[2] == 0 && data[3] == 0;
|
return len == 148 && data[0] == 1 && data[1] == 0 && data[2] == 0 && data[3] == 0;
|
||||||
|
@ -21,7 +21,13 @@ const char *HttpFind2ndLevelDomain(const char *host);
|
|||||||
int HttpReplyCode(const uint8_t *data, size_t len);
|
int HttpReplyCode(const uint8_t *data, size_t len);
|
||||||
// must be pre-checked by IsHttpReply
|
// must be pre-checked by IsHttpReply
|
||||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
||||||
enum httpreqpos { httpreqpos_none = 0, httpreqpos_method, httpreqpos_host, httpreqpos_pos };
|
enum httpreqpos
|
||||||
|
{
|
||||||
|
httpreqpos_none = 0,
|
||||||
|
httpreqpos_method,
|
||||||
|
httpreqpos_host,
|
||||||
|
httpreqpos_pos
|
||||||
|
};
|
||||||
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);
|
||||||
|
|
||||||
uint16_t TLSRecordDataLen(const uint8_t *data);
|
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||||
@ -35,14 +41,21 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
|||||||
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
||||||
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||||
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||||
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_pos };
|
enum tlspos
|
||||||
|
{
|
||||||
|
tlspos_none = 0,
|
||||||
|
tlspos_sni,
|
||||||
|
tlspos_sniext,
|
||||||
|
tlspos_pos
|
||||||
|
};
|
||||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
||||||
|
|
||||||
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
|
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
|
||||||
bool IsDhtD1(const uint8_t *data, size_t len);
|
bool IsDhtD1(const uint8_t *data, size_t len);
|
||||||
|
|
||||||
#define QUIC_MAX_CID_LENGTH 20
|
#define QUIC_MAX_CID_LENGTH 20
|
||||||
typedef struct quic_cid {
|
typedef struct quic_cid
|
||||||
|
{
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
uint8_t cid[QUIC_MAX_CID_LENGTH];
|
uint8_t cid[QUIC_MAX_CID_LENGTH];
|
||||||
} quic_cid_t;
|
} quic_cid_t;
|
||||||
|
14
nfq/sec.c
14
nfq/sec.c
@ -144,8 +144,7 @@ SYS_tkill,
|
|||||||
#ifdef SYS_tgkill
|
#ifdef SYS_tgkill
|
||||||
SYS_tgkill,
|
SYS_tgkill,
|
||||||
#endif
|
#endif
|
||||||
SYS_kill, SYS_ptrace
|
SYS_kill, SYS_ptrace};
|
||||||
};
|
|
||||||
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls))
|
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls))
|
||||||
|
|
||||||
static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k)
|
static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k)
|
||||||
@ -205,19 +204,18 @@ bool sec_harden(void)
|
|||||||
if (!set_seccomp())
|
if (!set_seccomp())
|
||||||
{
|
{
|
||||||
DLOG_PERROR("seccomp");
|
DLOG_PERROR("seccomp");
|
||||||
if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
|
if (errno == EINVAL)
|
||||||
|
DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool checkpcap(uint64_t caps)
|
bool checkpcap(uint64_t caps)
|
||||||
{
|
{
|
||||||
if (!caps) return true; // no special caps reqd
|
if (!caps)
|
||||||
|
return true; // no special caps reqd
|
||||||
|
|
||||||
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
|
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
|
||||||
struct __user_cap_data_struct cd[2];
|
struct __user_cap_data_struct cd[2];
|
||||||
@ -248,7 +246,6 @@ int getmaxcap(void)
|
|||||||
fclose(F);
|
fclose(F);
|
||||||
}
|
}
|
||||||
return maxcap;
|
return maxcap;
|
||||||
|
|
||||||
}
|
}
|
||||||
bool dropcaps(void)
|
bool dropcaps(void)
|
||||||
{
|
{
|
||||||
@ -349,7 +346,6 @@ void print_id(void)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void daemonize(void)
|
void daemonize(void)
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
@ -53,7 +53,7 @@ bool dropcaps(void);
|
|||||||
#define ARCH_NR AUDIT_ARCH_MIPS64
|
#define ARCH_NR AUDIT_ARCH_MIPS64
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
# error "Unsupported mips abi"
|
#error "Unsupported MIPS ABI"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(__PPC64__)
|
#elif defined(__PPC64__)
|
||||||
@ -80,7 +80,6 @@ bool dropcaps(void);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef __CYGWIN__
|
#ifndef __CYGWIN__
|
||||||
bool sec_harden(void);
|
bool sec_harden(void);
|
||||||
bool can_drop_root(void);
|
bool can_drop_root(void);
|
||||||
|
600
nfq/uthash.h
600
nfq/uthash.h
File diff suppressed because it is too large
Load Diff
@ -18,8 +18,7 @@ bool service_run(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
SERVICE_TABLE_ENTRY ServiceTable[] = {
|
SERVICE_TABLE_ENTRY ServiceTable[] = {
|
||||||
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main},
|
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main},
|
||||||
{NULL, NULL}
|
{NULL, NULL}};
|
||||||
};
|
|
||||||
|
|
||||||
service_argc = argc;
|
service_argc = argc;
|
||||||
service_argv = argv;
|
service_argv = argv;
|
||||||
@ -76,5 +75,4 @@ void service_main(int argc __attribute__((unused)), char *argv[] __attribute__((
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -62,7 +62,8 @@
|
|||||||
#endif /* __MINGW32__ */
|
#endif /* __MINGW32__ */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -79,7 +80,8 @@ typedef enum
|
|||||||
WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
|
WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
|
||||||
WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */
|
WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */
|
||||||
WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */
|
WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */
|
||||||
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
|
} WINDIVERT_LAYER,
|
||||||
|
*PWINDIVERT_LAYER;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WinDivert NETWORK and NETWORK_FORWARD layer data.
|
* WinDivert NETWORK and NETWORK_FORWARD layer data.
|
||||||
@ -183,7 +185,8 @@ typedef enum
|
|||||||
WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */
|
WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */
|
||||||
WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */
|
WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */
|
||||||
WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */
|
WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */
|
||||||
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
|
} WINDIVERT_EVENT,
|
||||||
|
*PWINDIVERT_EVENT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WinDivert flags.
|
* WinDivert flags.
|
||||||
@ -207,7 +210,8 @@ typedef enum
|
|||||||
WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */
|
WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */
|
||||||
WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */
|
WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */
|
||||||
WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */
|
WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */
|
||||||
} WINDIVERT_PARAM, *PWINDIVERT_PARAM;
|
} WINDIVERT_PARAM,
|
||||||
|
*PWINDIVERT_PARAM;
|
||||||
#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR
|
#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -218,7 +222,8 @@ typedef enum
|
|||||||
WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */
|
WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */
|
||||||
WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */
|
WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */
|
||||||
WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */
|
WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */
|
||||||
} WINDIVERT_SHUTDOWN, *PWINDIVERT_SHUTDOWN;
|
} WINDIVERT_SHUTDOWN,
|
||||||
|
*PWINDIVERT_SHUTDOWN;
|
||||||
#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH
|
#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH
|
||||||
|
|
||||||
#ifndef WINDIVERT_KERNEL
|
#ifndef WINDIVERT_KERNEL
|
||||||
@ -367,29 +372,25 @@ typedef struct
|
|||||||
{ \
|
{ \
|
||||||
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \
|
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \
|
||||||
((val) & 0xFF1F); \
|
((val) & 0xFF1F); \
|
||||||
} \
|
} while (FALSE)
|
||||||
while (FALSE)
|
|
||||||
#define WINDIVERT_IPHDR_SET_MF(hdr, val) \
|
#define WINDIVERT_IPHDR_SET_MF(hdr, val) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \
|
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \
|
||||||
(((val) & 0x0001) << 5); \
|
(((val) & 0x0001) << 5); \
|
||||||
} \
|
} while (FALSE)
|
||||||
while (FALSE)
|
|
||||||
#define WINDIVERT_IPHDR_SET_DF(hdr, val) \
|
#define WINDIVERT_IPHDR_SET_DF(hdr, val) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \
|
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \
|
||||||
(((val) & 0x0001) << 6); \
|
(((val) & 0x0001) << 6); \
|
||||||
} \
|
} while (FALSE)
|
||||||
while (FALSE)
|
|
||||||
#define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \
|
#define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \
|
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \
|
||||||
(((val) & 0x0001) << 7); \
|
(((val) & 0x0001) << 7); \
|
||||||
} \
|
} while (FALSE)
|
||||||
while (FALSE)
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -415,15 +416,13 @@ typedef struct
|
|||||||
{ \
|
{ \
|
||||||
(hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \
|
(hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \
|
||||||
(hdr)->TrafficClass1 = (UINT8)(val); \
|
(hdr)->TrafficClass1 = (UINT8)(val); \
|
||||||
} \
|
} while (FALSE)
|
||||||
while (FALSE)
|
|
||||||
#define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \
|
#define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
(hdr)->FlowLabel0 = (UINT8)((val) >> 16); \
|
(hdr)->FlowLabel0 = (UINT8)((val) >> 16); \
|
||||||
(hdr)->FlowLabel1 = (UINT16)(val); \
|
(hdr)->FlowLabel1 = (UINT16)(val); \
|
||||||
} \
|
} while (FALSE)
|
||||||
while (FALSE)
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
#define SHIM_SYS_EPOLL_H
|
#define SHIM_SYS_EPOLL_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -18,7 +19,10 @@ extern "C" {
|
|||||||
#define EPOLL_CLOEXEC O_CLOEXEC
|
#define EPOLL_CLOEXEC O_CLOEXEC
|
||||||
#define EPOLL_NONBLOCK O_NONBLOCK
|
#define EPOLL_NONBLOCK O_NONBLOCK
|
||||||
|
|
||||||
enum EPOLL_EVENTS { __EPOLL_DUMMY };
|
enum EPOLL_EVENTS
|
||||||
|
{
|
||||||
|
__EPOLL_DUMMY
|
||||||
|
};
|
||||||
#define EPOLLIN 0x001
|
#define EPOLLIN 0x001
|
||||||
#define EPOLLPRI 0x002
|
#define EPOLLPRI 0x002
|
||||||
#define EPOLLOUT 0x004
|
#define EPOLLOUT 0x004
|
||||||
@ -40,14 +44,16 @@ enum EPOLL_EVENTS { __EPOLL_DUMMY };
|
|||||||
#define EPOLL_CTL_DEL 2
|
#define EPOLL_CTL_DEL 2
|
||||||
#define EPOLL_CTL_MOD 3
|
#define EPOLL_CTL_MOD 3
|
||||||
|
|
||||||
typedef union epoll_data {
|
typedef union epoll_data
|
||||||
|
{
|
||||||
void *ptr;
|
void *ptr;
|
||||||
int fd;
|
int fd;
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
} epoll_data_t;
|
} epoll_data_t;
|
||||||
|
|
||||||
struct epoll_event {
|
struct epoll_event
|
||||||
|
{
|
||||||
uint32_t events;
|
uint32_t events;
|
||||||
epoll_data_t data;
|
epoll_data_t data;
|
||||||
}
|
}
|
||||||
@ -56,14 +62,12 @@ __attribute__ ((__packed__))
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
int epoll_create(int);
|
int epoll_create(int);
|
||||||
int epoll_create1(int);
|
int epoll_create1(int);
|
||||||
int epoll_ctl(int, int, int, struct epoll_event *);
|
int epoll_ctl(int, int, int, struct epoll_event *);
|
||||||
int epoll_wait(int, struct epoll_event *, int, int);
|
int epoll_wait(int, struct epoll_event *, int, int);
|
||||||
int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *);
|
int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *);
|
||||||
|
|
||||||
|
|
||||||
#ifndef SHIM_SYS_SHIM_HELPERS
|
#ifndef SHIM_SYS_SHIM_HELPERS
|
||||||
#define SHIM_SYS_SHIM_HELPERS
|
#define SHIM_SYS_SHIM_HELPERS
|
||||||
#include <unistd.h> /* IWYU pragma: keep */
|
#include <unistd.h> /* IWYU pragma: keep */
|
||||||
@ -72,7 +76,6 @@ extern int epoll_shim_close(int);
|
|||||||
#define close epoll_shim_close
|
#define close epoll_shim_close
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,10 +22,12 @@
|
|||||||
// all supported FreeBSD versions.
|
// all supported FreeBSD versions.
|
||||||
#ifndef timespecsub
|
#ifndef timespecsub
|
||||||
#define timespecsub(tsp, usp, vsp) \
|
#define timespecsub(tsp, usp, vsp) \
|
||||||
do { \
|
do \
|
||||||
|
{ \
|
||||||
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
|
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
|
||||||
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
|
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
|
||||||
if ((vsp)->tv_nsec < 0) { \
|
if ((vsp)->tv_nsec < 0) \
|
||||||
|
{ \
|
||||||
(vsp)->tv_sec--; \
|
(vsp)->tv_sec--; \
|
||||||
(vsp)->tv_nsec += 1000000000L; \
|
(vsp)->tv_nsec += 1000000000L; \
|
||||||
} \
|
} \
|
||||||
@ -50,14 +52,16 @@ epoll_create_impl(errno_t *ec)
|
|||||||
FDContextMapNode *node;
|
FDContextMapNode *node;
|
||||||
|
|
||||||
node = epoll_shim_ctx_create_node(&epoll_shim_ctx, ec);
|
node = epoll_shim_ctx_create_node(&epoll_shim_ctx, ec);
|
||||||
if (!node) {
|
if (!node)
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->flags = 0;
|
node->flags = 0;
|
||||||
|
|
||||||
if ((*ec = epollfd_ctx_init(&node->ctx.epollfd, /**/
|
if ((*ec = epollfd_ctx_init(&node->ctx.epollfd, /**/
|
||||||
node->fd)) != 0) {
|
node->fd)) != 0)
|
||||||
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +81,8 @@ epoll_create_common(void)
|
|||||||
errno_t ec;
|
errno_t ec;
|
||||||
|
|
||||||
node = epoll_create_impl(&ec);
|
node = epoll_create_impl(&ec);
|
||||||
if (!node) {
|
if (!node)
|
||||||
|
{
|
||||||
errno = ec;
|
errno = ec;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -85,10 +90,10 @@ epoll_create_common(void)
|
|||||||
return node->fd;
|
return node->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int epoll_create(int size)
|
||||||
epoll_create(int size)
|
{
|
||||||
|
if (size <= 0)
|
||||||
{
|
{
|
||||||
if (size <= 0) {
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -96,10 +101,10 @@ epoll_create(int size)
|
|||||||
return epoll_create_common();
|
return epoll_create_common();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int epoll_create1(int flags)
|
||||||
epoll_create1(int flags)
|
{
|
||||||
|
if (flags & ~EPOLL_CLOEXEC)
|
||||||
{
|
{
|
||||||
if (flags & ~EPOLL_CLOEXEC) {
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -110,12 +115,14 @@ epoll_create1(int flags)
|
|||||||
static errno_t
|
static errno_t
|
||||||
epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev)
|
epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev)
|
||||||
{
|
{
|
||||||
if (!ev && op != EPOLL_CTL_DEL) {
|
if (!ev && op != EPOLL_CTL_DEL)
|
||||||
|
{
|
||||||
return EFAULT;
|
return EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
||||||
if (!node || node->vtable != &epollfd_vtable) {
|
if (!node || node->vtable != &epollfd_vtable)
|
||||||
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
|
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
|
||||||
}
|
}
|
||||||
@ -123,11 +130,11 @@ epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev)
|
|||||||
return epollfd_ctx_ctl(&node->ctx.epollfd, op, fd2, ev);
|
return epollfd_ctx_ctl(&node->ctx.epollfd, op, fd2, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
|
||||||
epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
|
|
||||||
{
|
{
|
||||||
errno_t ec = epoll_ctl_impl(fd, op, fd2, ev);
|
errno_t ec = epoll_ctl_impl(fd, op, fd2, ev);
|
||||||
if (ec != 0) {
|
if (ec != 0)
|
||||||
|
{
|
||||||
errno = ec;
|
errno = ec;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -147,29 +154,35 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
|
|||||||
{
|
{
|
||||||
errno_t ec;
|
errno_t ec;
|
||||||
|
|
||||||
for (;;) {
|
for (;;)
|
||||||
|
{
|
||||||
if ((ec = epollfd_ctx_wait(epollfd, /**/
|
if ((ec = epollfd_ctx_wait(epollfd, /**/
|
||||||
ev, cnt, actual_cnt)) != 0) {
|
ev, cnt, actual_cnt)) != 0)
|
||||||
|
{
|
||||||
return ec;
|
return ec;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*actual_cnt || is_no_wait_deadline(deadline)) {
|
if (*actual_cnt || is_no_wait_deadline(deadline))
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
|
|
||||||
if (deadline) {
|
if (deadline)
|
||||||
|
{
|
||||||
struct timespec current_time;
|
struct timespec current_time;
|
||||||
|
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, /**/
|
if (clock_gettime(CLOCK_MONOTONIC, /**/
|
||||||
¤t_time) < 0) {
|
¤t_time) < 0)
|
||||||
|
{
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
timespecsub(deadline, ¤t_time, &timeout);
|
timespecsub(deadline, ¤t_time, &timeout);
|
||||||
if (timeout.tv_sec < 0 ||
|
if (timeout.tv_sec < 0 ||
|
||||||
is_no_wait_deadline(&timeout)) {
|
is_no_wait_deadline(&timeout))
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,14 +193,16 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
|
|||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
if (__builtin_mul_overflow(nfds, sizeof(struct pollfd),
|
if (__builtin_mul_overflow(nfds, sizeof(struct pollfd),
|
||||||
&size)) {
|
&size))
|
||||||
|
{
|
||||||
ec = ENOMEM;
|
ec = ENOMEM;
|
||||||
(void)pthread_mutex_unlock(&epollfd->mutex);
|
(void)pthread_mutex_unlock(&epollfd->mutex);
|
||||||
return ec;
|
return ec;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pollfd *pfds = malloc(size);
|
struct pollfd *pfds = malloc(size);
|
||||||
if (!pfds) {
|
if (!pfds)
|
||||||
|
{
|
||||||
ec = errno;
|
ec = errno;
|
||||||
(void)pthread_mutex_unlock(&epollfd->mutex);
|
(void)pthread_mutex_unlock(&epollfd->mutex);
|
||||||
return ec;
|
return ec;
|
||||||
@ -211,7 +226,8 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int n = ppoll(pfds, nfds, deadline ? &timeout : NULL, sigs);
|
int n = ppoll(pfds, nfds, deadline ? &timeout : NULL, sigs);
|
||||||
if (n < 0) {
|
if (n < 0)
|
||||||
|
{
|
||||||
ec = errno;
|
ec = errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,13 +235,15 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
|
|||||||
|
|
||||||
(void)pthread_mutex_lock(&epollfd->nr_polling_threads_mutex);
|
(void)pthread_mutex_lock(&epollfd->nr_polling_threads_mutex);
|
||||||
--epollfd->nr_polling_threads;
|
--epollfd->nr_polling_threads;
|
||||||
if (epollfd->nr_polling_threads == 0) {
|
if (epollfd->nr_polling_threads == 0)
|
||||||
|
{
|
||||||
(void)pthread_cond_signal(
|
(void)pthread_cond_signal(
|
||||||
&epollfd->nr_polling_threads_cond);
|
&epollfd->nr_polling_threads_cond);
|
||||||
}
|
}
|
||||||
(void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex);
|
(void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex);
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0)
|
||||||
|
{
|
||||||
return ec;
|
return ec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,21 +254,27 @@ timeout_to_deadline(struct timespec *deadline, int to)
|
|||||||
{
|
{
|
||||||
assert(to >= 0);
|
assert(to >= 0);
|
||||||
|
|
||||||
if (to == 0) {
|
if (to == 0)
|
||||||
|
{
|
||||||
*deadline = (struct timespec){0, 0};
|
*deadline = (struct timespec){0, 0};
|
||||||
} else if (to > 0) {
|
}
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, deadline) < 0) {
|
else if (to > 0)
|
||||||
|
{
|
||||||
|
if (clock_gettime(CLOCK_MONOTONIC, deadline) < 0)
|
||||||
|
{
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__builtin_add_overflow(deadline->tv_sec, to / 1000 + 1,
|
if (__builtin_add_overflow(deadline->tv_sec, to / 1000 + 1,
|
||||||
&deadline->tv_sec)) {
|
&deadline->tv_sec))
|
||||||
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
deadline->tv_sec -= 1;
|
deadline->tv_sec -= 1;
|
||||||
|
|
||||||
deadline->tv_nsec += (to % 1000) * 1000000L;
|
deadline->tv_nsec += (to % 1000) * 1000000L;
|
||||||
if (deadline->tv_nsec >= 1000000000) {
|
if (deadline->tv_nsec >= 1000000000)
|
||||||
|
{
|
||||||
deadline->tv_nsec -= 1000000000;
|
deadline->tv_nsec -= 1000000000;
|
||||||
deadline->tv_sec += 1;
|
deadline->tv_sec += 1;
|
||||||
}
|
}
|
||||||
@ -263,19 +287,22 @@ static errno_t
|
|||||||
epoll_pwait_impl(int fd, struct epoll_event *ev, int cnt, int to,
|
epoll_pwait_impl(int fd, struct epoll_event *ev, int cnt, int to,
|
||||||
sigset_t const *sigs, int *actual_cnt)
|
sigset_t const *sigs, int *actual_cnt)
|
||||||
{
|
{
|
||||||
if (cnt < 1 || cnt > (int)(INT_MAX / sizeof(struct epoll_event))) {
|
if (cnt < 1 || cnt > (int)(INT_MAX / sizeof(struct epoll_event)))
|
||||||
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
||||||
if (!node || node->vtable != &epollfd_vtable) {
|
if (!node || node->vtable != &epollfd_vtable)
|
||||||
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
|
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timespec deadline;
|
struct timespec deadline;
|
||||||
errno_t ec;
|
errno_t ec;
|
||||||
if (to >= 0 && (ec = timeout_to_deadline(&deadline, to)) != 0) {
|
if (to >= 0 && (ec = timeout_to_deadline(&deadline, to)) != 0)
|
||||||
|
{
|
||||||
return ec;
|
return ec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,14 +310,14 @@ epoll_pwait_impl(int fd, struct epoll_event *ev, int cnt, int to,
|
|||||||
actual_cnt, (to >= 0) ? &deadline : NULL, sigs);
|
actual_cnt, (to >= 0) ? &deadline : NULL, sigs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
|
||||||
epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
|
|
||||||
sigset_t const *sigs)
|
sigset_t const *sigs)
|
||||||
{
|
{
|
||||||
int actual_cnt;
|
int actual_cnt;
|
||||||
|
|
||||||
errno_t ec = epoll_pwait_impl(fd, ev, cnt, to, sigs, &actual_cnt);
|
errno_t ec = epoll_pwait_impl(fd, ev, cnt, to, sigs, &actual_cnt);
|
||||||
if (ec != 0) {
|
if (ec != 0)
|
||||||
|
{
|
||||||
errno = ec;
|
errno = ec;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -298,8 +325,7 @@ epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
|
|||||||
return actual_cnt;
|
return actual_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
|
||||||
epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
|
|
||||||
{
|
{
|
||||||
return epoll_pwait(fd, ev, cnt, to, NULL);
|
return epoll_pwait(fd, ev, cnt, to, NULL);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,8 @@ fd_context_map_node_create(int kq, errno_t *ec)
|
|||||||
FDContextMapNode *node;
|
FDContextMapNode *node;
|
||||||
|
|
||||||
node = malloc(sizeof(FDContextMapNode));
|
node = malloc(sizeof(FDContextMapNode));
|
||||||
if (!node) {
|
if (!node)
|
||||||
|
{
|
||||||
*ec = errno;
|
*ec = errno;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -34,7 +35,8 @@ fd_context_map_node_terminate(FDContextMapNode *node, bool close_fd)
|
|||||||
{
|
{
|
||||||
errno_t ec = node->vtable ? node->vtable->close_fun(node) : 0;
|
errno_t ec = node->vtable ? node->vtable->close_fun(node) : 0;
|
||||||
|
|
||||||
if (close_fd && close(node->fd) < 0) {
|
if (close_fd && close(node->fd) < 0)
|
||||||
|
{
|
||||||
ec = ec ? ec : errno;
|
ec = ec ? ec : errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +109,8 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
|
|||||||
&epoll_shim_ctx->fd_context_map, &find);
|
&epoll_shim_ctx->fd_context_map, &find);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node) {
|
if (node)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If we get here, someone must have already closed the old fd
|
* If we get here, someone must have already closed the old fd
|
||||||
* with a normal 'close()' call, i.e. not with our
|
* with a normal 'close()' call, i.e. not with our
|
||||||
@ -118,9 +121,12 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
|
|||||||
*/
|
*/
|
||||||
(void)fd_context_map_node_terminate(node, false);
|
(void)fd_context_map_node_terminate(node, false);
|
||||||
fd_context_map_node_init(node, kq);
|
fd_context_map_node_init(node, kq);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
node = fd_context_map_node_create(kq, ec);
|
node = fd_context_map_node_create(kq, ec);
|
||||||
if (!node) {
|
if (!node)
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +145,8 @@ epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec)
|
|||||||
FDContextMapNode *node;
|
FDContextMapNode *node;
|
||||||
|
|
||||||
int kq = kqueue();
|
int kq = kqueue();
|
||||||
if (kq < 0) {
|
if (kq < 0)
|
||||||
|
{
|
||||||
*ec = errno;
|
*ec = errno;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -148,7 +155,8 @@ epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec)
|
|||||||
node = epoll_shim_ctx_create_node_impl(epoll_shim_ctx, kq, ec);
|
node = epoll_shim_ctx_create_node_impl(epoll_shim_ctx, kq, ec);
|
||||||
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
|
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
|
||||||
|
|
||||||
if (!node) {
|
if (!node)
|
||||||
|
{
|
||||||
close(kq);
|
close(kq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +196,8 @@ epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, int fd)
|
|||||||
|
|
||||||
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
|
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
|
||||||
node = epoll_shim_ctx_find_node_impl(epoll_shim_ctx, fd);
|
node = epoll_shim_ctx_find_node_impl(epoll_shim_ctx, fd);
|
||||||
if (node) {
|
if (node)
|
||||||
|
{
|
||||||
RB_REMOVE(fd_context_map_, /**/
|
RB_REMOVE(fd_context_map_, /**/
|
||||||
&epoll_shim_ctx->fd_context_map, node);
|
&epoll_shim_ctx->fd_context_map, node);
|
||||||
}
|
}
|
||||||
@ -197,8 +206,7 @@ epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, int fd)
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
|
||||||
epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
|
|
||||||
FDContextMapNode *node)
|
FDContextMapNode *node)
|
||||||
{
|
{
|
||||||
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
|
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
|
||||||
@ -209,18 +217,19 @@ epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
|
|||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
int
|
int epoll_shim_close(int fd)
|
||||||
epoll_shim_close(int fd)
|
|
||||||
{
|
{
|
||||||
FDContextMapNode *node;
|
FDContextMapNode *node;
|
||||||
|
|
||||||
node = epoll_shim_ctx_remove_node(&epoll_shim_ctx, fd);
|
node = epoll_shim_ctx_remove_node(&epoll_shim_ctx, fd);
|
||||||
if (!node) {
|
if (!node)
|
||||||
|
{
|
||||||
return close(fd);
|
return close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
errno_t ec = fd_context_map_node_destroy(node);
|
errno_t ec = fd_context_map_node_destroy(node);
|
||||||
if (ec != 0) {
|
if (ec != 0)
|
||||||
|
{
|
||||||
errno = ec;
|
errno = ec;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -234,11 +243,13 @@ epoll_shim_read(int fd, void *buf, size_t nbytes)
|
|||||||
FDContextMapNode *node;
|
FDContextMapNode *node;
|
||||||
|
|
||||||
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
||||||
if (!node) {
|
if (!node)
|
||||||
|
{
|
||||||
return read(fd, buf, nbytes);
|
return read(fd, buf, nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nbytes > SSIZE_MAX) {
|
if (nbytes > SSIZE_MAX)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -246,7 +257,8 @@ epoll_shim_read(int fd, void *buf, size_t nbytes)
|
|||||||
size_t bytes_transferred;
|
size_t bytes_transferred;
|
||||||
errno_t ec = node->vtable->read_fun(node, /**/
|
errno_t ec = node->vtable->read_fun(node, /**/
|
||||||
buf, nbytes, &bytes_transferred);
|
buf, nbytes, &bytes_transferred);
|
||||||
if (ec != 0) {
|
if (ec != 0)
|
||||||
|
{
|
||||||
errno = ec;
|
errno = ec;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -260,11 +272,13 @@ epoll_shim_write(int fd, void const *buf, size_t nbytes)
|
|||||||
FDContextMapNode *node;
|
FDContextMapNode *node;
|
||||||
|
|
||||||
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
||||||
if (!node) {
|
if (!node)
|
||||||
|
{
|
||||||
return write(fd, buf, nbytes);
|
return write(fd, buf, nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nbytes > SSIZE_MAX) {
|
if (nbytes > SSIZE_MAX)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -272,7 +286,8 @@ epoll_shim_write(int fd, void const *buf, size_t nbytes)
|
|||||||
size_t bytes_transferred;
|
size_t bytes_transferred;
|
||||||
errno_t ec = node->vtable->write_fun(node, /**/
|
errno_t ec = node->vtable->write_fun(node, /**/
|
||||||
buf, nbytes, &bytes_transferred);
|
buf, nbytes, &bytes_transferred);
|
||||||
if (ec != 0) {
|
if (ec != 0)
|
||||||
|
{
|
||||||
errno = ec;
|
errno = ec;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@ typedef errno_t (*fd_context_write_fun)(FDContextMapNode *node, /**/
|
|||||||
const void *buf, size_t nbytes, size_t *bytes_transferred);
|
const void *buf, size_t nbytes, size_t *bytes_transferred);
|
||||||
typedef errno_t (*fd_context_close_fun)(FDContextMapNode *node);
|
typedef errno_t (*fd_context_close_fun)(FDContextMapNode *node);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
fd_context_read_fun read_fun;
|
fd_context_read_fun read_fun;
|
||||||
fd_context_write_fun write_fun;
|
fd_context_write_fun write_fun;
|
||||||
fd_context_close_fun close_fun;
|
fd_context_close_fun close_fun;
|
||||||
@ -32,11 +33,14 @@ errno_t fd_context_default_read(FDContextMapNode *node, /**/
|
|||||||
errno_t fd_context_default_write(FDContextMapNode *node, /**/
|
errno_t fd_context_default_write(FDContextMapNode *node, /**/
|
||||||
void const *buf, size_t nbytes, size_t *bytes_transferred);
|
void const *buf, size_t nbytes, size_t *bytes_transferred);
|
||||||
|
|
||||||
struct fd_context_map_node_ {
|
struct fd_context_map_node_
|
||||||
RB_ENTRY(fd_context_map_node_) entry;
|
{
|
||||||
|
RB_ENTRY(fd_context_map_node_)
|
||||||
|
entry;
|
||||||
int fd;
|
int fd;
|
||||||
int flags;
|
int flags;
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
EpollFDCtx epollfd;
|
EpollFDCtx epollfd;
|
||||||
EventFDCtx eventfd;
|
EventFDCtx eventfd;
|
||||||
TimerFDCtx timerfd;
|
TimerFDCtx timerfd;
|
||||||
@ -51,7 +55,8 @@ errno_t fd_context_map_node_destroy(FDContextMapNode *node);
|
|||||||
|
|
||||||
typedef RB_HEAD(fd_context_map_, fd_context_map_node_) FDContextMap;
|
typedef RB_HEAD(fd_context_map_, fd_context_map_node_) FDContextMap;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
FDContextMap fd_context_map;
|
FDContextMap fd_context_map;
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
} EpollShimCtx;
|
} EpollShimCtx;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -19,12 +19,14 @@
|
|||||||
struct registered_fds_node_;
|
struct registered_fds_node_;
|
||||||
typedef struct registered_fds_node_ RegisteredFDsNode;
|
typedef struct registered_fds_node_ RegisteredFDsNode;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
EOF_STATE_READ_EOF = 0x01,
|
EOF_STATE_READ_EOF = 0x01,
|
||||||
EOF_STATE_WRITE_EOF = 0x02,
|
EOF_STATE_WRITE_EOF = 0x02,
|
||||||
} EOFState;
|
} EOFState;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
NODE_TYPE_FIFO = 1,
|
NODE_TYPE_FIFO = 1,
|
||||||
NODE_TYPE_SOCKET = 2,
|
NODE_TYPE_SOCKET = 2,
|
||||||
NODE_TYPE_KQUEUE = 3,
|
NODE_TYPE_KQUEUE = 3,
|
||||||
@ -32,9 +34,12 @@ typedef enum {
|
|||||||
NODE_TYPE_POLL = 5,
|
NODE_TYPE_POLL = 5,
|
||||||
} NodeType;
|
} NodeType;
|
||||||
|
|
||||||
struct registered_fds_node_ {
|
struct registered_fds_node_
|
||||||
RB_ENTRY(registered_fds_node_) entry;
|
{
|
||||||
TAILQ_ENTRY(registered_fds_node_) pollfd_list_entry;
|
RB_ENTRY(registered_fds_node_)
|
||||||
|
entry;
|
||||||
|
TAILQ_ENTRY(registered_fds_node_)
|
||||||
|
pollfd_list_entry;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
epoll_data_t data;
|
epoll_data_t data;
|
||||||
@ -50,8 +55,10 @@ struct registered_fds_node_ {
|
|||||||
bool got_evfilt_except;
|
bool got_evfilt_except;
|
||||||
|
|
||||||
NodeType node_type;
|
NodeType node_type;
|
||||||
union {
|
union
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
bool readable;
|
bool readable;
|
||||||
bool writable;
|
bool writable;
|
||||||
} fifo;
|
} fifo;
|
||||||
@ -72,7 +79,8 @@ struct registered_fds_node_ {
|
|||||||
typedef TAILQ_HEAD(pollfds_list_, registered_fds_node_) PollFDList;
|
typedef TAILQ_HEAD(pollfds_list_, registered_fds_node_) PollFDList;
|
||||||
typedef RB_HEAD(registered_fds_set_, registered_fds_node_) RegisteredFDsSet;
|
typedef RB_HEAD(registered_fds_set_, registered_fds_node_) RegisteredFDsSet;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int kq; // non owning
|
int kq; // non owning
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
|
|
||||||
#define EVENTFD_CTX_FLAG_SEMAPHORE (1 << 0)
|
#define EVENTFD_CTX_FLAG_SEMAPHORE (1 << 0)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int kq_; // non owning
|
int kq_; // non owning
|
||||||
int flags_;
|
int flags_;
|
||||||
pthread_mutex_t mutex_;
|
pthread_mutex_t mutex_;
|
||||||
|
@ -11,7 +11,8 @@ typedef int errno_t;
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
|
||||||
struct itimerspec {
|
struct itimerspec
|
||||||
|
{
|
||||||
struct timespec it_interval;
|
struct timespec it_interval;
|
||||||
struct timespec it_value;
|
struct timespec it_value;
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int kq; // non owning
|
int kq; // non owning
|
||||||
} SignalFDCtx;
|
} SignalFDCtx;
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int kq; // non owning
|
int kq; // non owning
|
||||||
int flags;
|
int flags;
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
|
12
tpws/gzip.c
12
tpws/gzip.c
@ -21,7 +21,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
bufsize = *size = 0;
|
bufsize = *size = 0;
|
||||||
|
|
||||||
r = inflateInit2(&zs, 47);
|
r = inflateInit2(&zs, 47);
|
||||||
if (r != Z_OK) return r;
|
if (r != Z_OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -31,7 +32,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
r = Z_ERRNO;
|
r = Z_ERRNO;
|
||||||
goto zerr;
|
goto zerr;
|
||||||
}
|
}
|
||||||
if (!zs.avail_in) break;
|
if (!zs.avail_in)
|
||||||
|
break;
|
||||||
zs.next_in = in;
|
zs.next_in = in;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -49,7 +51,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
zs.avail_out = bufsize - *size;
|
zs.avail_out = bufsize - *size;
|
||||||
zs.next_out = (unsigned char *)(*buf + *size);
|
zs.next_out = (unsigned char *)(*buf + *size);
|
||||||
r = inflate(&zs, Z_NO_FLUSH);
|
r = inflate(&zs, Z_NO_FLUSH);
|
||||||
if (r != Z_OK && r != Z_STREAM_END) goto zerr;
|
if (r != Z_OK && r != Z_STREAM_END)
|
||||||
|
goto zerr;
|
||||||
*size = bufsize - zs.avail_out;
|
*size = bufsize - zs.avail_out;
|
||||||
} while (r == Z_OK && zs.avail_in);
|
} while (r == Z_OK && zs.avail_in);
|
||||||
} while (r == Z_OK);
|
} while (r == Z_OK);
|
||||||
@ -57,7 +60,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
|||||||
if (*size < bufsize)
|
if (*size < bufsize)
|
||||||
{
|
{
|
||||||
// free extra space
|
// free extra space
|
||||||
if ((newbuf = realloc(*buf, *size))) *buf = newbuf;
|
if ((newbuf = realloc(*buf, *size)))
|
||||||
|
*buf = newbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
inflateEnd(&zs);
|
inflateEnd(&zs);
|
||||||
|
@ -23,9 +23,11 @@ char *strncasestr(const char *s,const char *find, size_t slen)
|
|||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (slen-- < 1 || (sc = *s++) == '\0') return NULL;
|
if (slen-- < 1 || (sc = *s++) == '\0')
|
||||||
|
return NULL;
|
||||||
} while (toupper(c) != toupper(sc));
|
} while (toupper(c) != toupper(sc));
|
||||||
if (len > slen) return NULL;
|
if (len > slen)
|
||||||
|
return NULL;
|
||||||
} while (strncasecmp(s, find, len) != 0);
|
} while (strncasecmp(s, find, len) != 0);
|
||||||
s--;
|
s--;
|
||||||
}
|
}
|
||||||
@ -35,7 +37,8 @@ char *strncasestr(const char *s,const char *find, size_t slen)
|
|||||||
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;
|
||||||
@ -43,7 +46,8 @@ 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)
|
||||||
{
|
{
|
||||||
@ -81,7 +85,6 @@ void print_sockaddr(const struct sockaddr *sa)
|
|||||||
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)
|
||||||
{
|
{
|
||||||
@ -90,7 +93,8 @@ bool check_local_ip(const struct sockaddr *saddr)
|
|||||||
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;
|
||||||
@ -127,8 +131,6 @@ 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
|
||||||
@ -147,8 +149,8 @@ bool sacmp(const struct sockaddr *sa1,const struct sockaddr *sa2)
|
|||||||
}
|
}
|
||||||
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
|
||||||
sa->sa_family==AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0);
|
: 0);
|
||||||
}
|
}
|
||||||
bool saconvmapped(struct sockaddr_storage *a)
|
bool saconvmapped(struct sockaddr_storage *a)
|
||||||
{
|
{
|
||||||
@ -185,8 +187,6 @@ bool is_private6(const struct sockaddr_in6* a)
|
|||||||
return (a->sin6_addr.s6_addr[0] & 0xFE) == 0xFC;
|
return (a->sin6_addr.s6_addr[0] & 0xFE) == 0xFC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool set_keepalive(int fd)
|
bool set_keepalive(int fd)
|
||||||
{
|
{
|
||||||
int yes = 1;
|
int yes = 1;
|
||||||
@ -242,7 +242,8 @@ 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;
|
||||||
@ -252,13 +253,15 @@ 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 || 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 || v1 > 65535)
|
||||||
|
return false;
|
||||||
pf->to = pf->from = (uint16_t)v1;
|
pf->to = pf->from = (uint16_t)v1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -36,10 +36,12 @@ bool set_ttl_hl(int fd, int ttl);
|
|||||||
int get_so_error(int fd);
|
int get_so_error(int fd);
|
||||||
|
|
||||||
// alignment-safe functions
|
// alignment-safe functions
|
||||||
static inline uint16_t pntoh16(const uint8_t *p) {
|
static inline uint16_t pntoh16(const uint8_t *p)
|
||||||
|
{
|
||||||
return ((uint16_t)p[0] << 8) | (uint16_t)p[1];
|
return ((uint16_t)p[0] << 8) | (uint16_t)p[1];
|
||||||
}
|
}
|
||||||
static inline void phton16(uint8_t *p, uint16_t v) {
|
static inline void phton16(uint8_t *p, uint16_t v)
|
||||||
|
{
|
||||||
p[0] = (uint8_t)(v >> 8);
|
p[0] = (uint8_t)(v >> 8);
|
||||||
p[1] = (uint8_t)v;
|
p[1] = (uint8_t)v;
|
||||||
}
|
}
|
||||||
@ -62,8 +64,7 @@ bool pf_parse(const char *s, port_filter *pf);
|
|||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#define IN6_EXTRACT_MAP4(a) \
|
#define IN6_EXTRACT_MAP4(a) \
|
||||||
(__extension__ \
|
(__extension__({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
|
||||||
({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
|
|
||||||
(((const uint32_t *) (__a))[3]); }))
|
(((const uint32_t *) (__a))[3]); }))
|
||||||
#else
|
#else
|
||||||
#define IN6_EXTRACT_MAP4(a) (((const uint32_t *)(a))[3])
|
#define IN6_EXTRACT_MAP4(a) (((const uint32_t *)(a))[3])
|
||||||
|
@ -10,7 +10,8 @@ static bool addpool(strpool **hostlist, char **s, const char *end)
|
|||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
// advance until eol lowering all chars
|
// advance until eol lowering all chars
|
||||||
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
for (p = *s; p < end && *p && *p != '\r' && *p != '\n'; p++)
|
||||||
|
*p = tolower(*p);
|
||||||
if (!StrPoolAddStrLen(hostlist, *s, p - *s))
|
if (!StrPoolAddStrLen(hostlist, *s, p - *s))
|
||||||
{
|
{
|
||||||
StrPoolDestroy(hostlist);
|
StrPoolDestroy(hostlist);
|
||||||
@ -18,7 +19,8 @@ static bool addpool(strpool **hostlist, char **s, const char *end)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// advance to the next line
|
// advance to the next line
|
||||||
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
|
for (; p < end && (!*p || *p == '\r' || *p == '\n'); p++)
|
||||||
|
;
|
||||||
*s = p;
|
*s = p;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -51,7 +53,8 @@ bool AppendHostList(strpool **hostlist, char *filename)
|
|||||||
e = zbuf + zsize;
|
e = zbuf + zsize;
|
||||||
while (p < e)
|
while (p < e)
|
||||||
{
|
{
|
||||||
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
|
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
|
||||||
|
continue;
|
||||||
if (!addpool(hostlist, &p, e))
|
if (!addpool(hostlist, &p, e))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
||||||
@ -75,7 +78,8 @@ bool AppendHostList(strpool **hostlist, char *filename)
|
|||||||
while (fgets(s, 256, F))
|
while (fgets(s, 256, F))
|
||||||
{
|
{
|
||||||
p = s;
|
p = s;
|
||||||
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
|
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
|
||||||
|
continue;
|
||||||
if (!addpool(hostlist, &p, p + strlen(p)))
|
if (!addpool(hostlist, &p, p + strlen(p)))
|
||||||
{
|
{
|
||||||
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
||||||
@ -103,7 +107,8 @@ bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list)
|
|||||||
|
|
||||||
LIST_FOREACH(file, file_list, next)
|
LIST_FOREACH(file, file_list, next)
|
||||||
{
|
{
|
||||||
if (!AppendHostList(hostlist, file->str)) return false;
|
if (!AppendHostList(hostlist, file->str))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -114,7 +119,6 @@ bool NonEmptyHostlist(strpool **hostlist)
|
|||||||
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
|
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SearchHostList(strpool *hostlist, const char *host)
|
bool SearchHostList(strpool *hostlist, const char *host)
|
||||||
{
|
{
|
||||||
if (hostlist)
|
if (hostlist)
|
||||||
@ -125,9 +129,11 @@ bool SearchHostList(strpool *hostlist, const char *host)
|
|||||||
{
|
{
|
||||||
bInHostList = StrPoolCheckStr(hostlist, p);
|
bInHostList = StrPoolCheckStr(hostlist, p);
|
||||||
VPRINT("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
|
VPRINT("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
|
||||||
if (bInHostList) return true;
|
if (bInHostList)
|
||||||
|
return true;
|
||||||
p = strchr(p, '.');
|
p = strchr(p, '.');
|
||||||
if (p) p++;
|
if (p)
|
||||||
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -136,13 +142,15 @@ bool SearchHostList(strpool *hostlist, const char *host)
|
|||||||
// return : true = apply fooling, false = do not apply
|
// return : true = apply fooling, false = do not apply
|
||||||
static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded)
|
static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded)
|
||||||
{
|
{
|
||||||
if (excluded) *excluded = false;
|
if (excluded)
|
||||||
|
*excluded = false;
|
||||||
if (hostlist_exclude)
|
if (hostlist_exclude)
|
||||||
{
|
{
|
||||||
VPRINT("Checking exclude hostlist\n");
|
VPRINT("Checking exclude hostlist\n");
|
||||||
if (SearchHostList(hostlist_exclude, host))
|
if (SearchHostList(hostlist_exclude, host))
|
||||||
{
|
{
|
||||||
if (excluded) *excluded = true;
|
if (excluded)
|
||||||
|
*excluded = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,18 @@
|
|||||||
|
|
||||||
#define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook)
|
#define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook)
|
||||||
|
|
||||||
enum { PF_INOUT, PF_IN, PF_OUT, PF_FWD };
|
enum
|
||||||
|
{
|
||||||
|
PF_INOUT,
|
||||||
|
PF_IN,
|
||||||
|
PF_OUT,
|
||||||
|
PF_FWD
|
||||||
|
};
|
||||||
|
|
||||||
struct pf_addr {
|
struct pf_addr
|
||||||
union {
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
struct in_addr v4;
|
struct in_addr v4;
|
||||||
struct in6_addr v6;
|
struct in6_addr v6;
|
||||||
u_int8_t addr8[16];
|
u_int8_t addr8[16];
|
||||||
@ -25,13 +33,15 @@ struct pf_addr {
|
|||||||
#define addr32 pfa.addr32
|
#define addr32 pfa.addr32
|
||||||
};
|
};
|
||||||
|
|
||||||
union pf_state_xport {
|
union pf_state_xport
|
||||||
|
{
|
||||||
u_int16_t port;
|
u_int16_t port;
|
||||||
u_int16_t call_id;
|
u_int16_t call_id;
|
||||||
u_int32_t spi;
|
u_int32_t spi;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pfioc_natlook {
|
struct pfioc_natlook
|
||||||
|
{
|
||||||
struct pf_addr saddr;
|
struct pf_addr saddr;
|
||||||
struct pf_addr daddr;
|
struct pf_addr daddr;
|
||||||
struct pf_addr rsaddr;
|
struct pf_addr rsaddr;
|
||||||
|
@ -62,19 +62,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define SPLAY_HEAD(name, type) \
|
#define SPLAY_HEAD(name, type) \
|
||||||
struct name { \
|
struct name \
|
||||||
|
{ \
|
||||||
struct type *sph_root; /* root of the tree */ \
|
struct type *sph_root; /* root of the tree */ \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SPLAY_INITIALIZER(root) \
|
#define SPLAY_INITIALIZER(root) \
|
||||||
{NULL}
|
{NULL}
|
||||||
|
|
||||||
#define SPLAY_INIT(root) do { \
|
#define SPLAY_INIT(root) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
(root)->sph_root = NULL; \
|
(root)->sph_root = NULL; \
|
||||||
} while (/*CONSTCOND*/ 0)
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
#define SPLAY_ENTRY(type) \
|
#define SPLAY_ENTRY(type) \
|
||||||
struct { \
|
struct \
|
||||||
|
{ \
|
||||||
struct type *spe_left; /* left element */ \
|
struct type *spe_left; /* left element */ \
|
||||||
struct type *spe_right; /* right element */ \
|
struct type *spe_right; /* right element */ \
|
||||||
}
|
}
|
||||||
@ -85,31 +89,41 @@ struct { \
|
|||||||
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
|
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
|
||||||
|
|
||||||
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
|
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
|
||||||
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
|
#define SPLAY_ROTATE_RIGHT(head, tmp, field) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
|
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
|
||||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||||
(head)->sph_root = tmp; \
|
(head)->sph_root = tmp; \
|
||||||
} while (/*CONSTCOND*/ 0)
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
|
#define SPLAY_ROTATE_LEFT(head, tmp, field) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
|
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
|
||||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||||
(head)->sph_root = tmp; \
|
(head)->sph_root = tmp; \
|
||||||
} while (/*CONSTCOND*/ 0)
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
#define SPLAY_LINKLEFT(head, tmp, field) do { \
|
#define SPLAY_LINKLEFT(head, tmp, field) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||||
tmp = (head)->sph_root; \
|
tmp = (head)->sph_root; \
|
||||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
} while (/*CONSTCOND*/ 0)
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
|
#define SPLAY_LINKRIGHT(head, tmp, field) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||||
tmp = (head)->sph_root; \
|
tmp = (head)->sph_root; \
|
||||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
} while (/*CONSTCOND*/ 0)
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
|
#define SPLAY_ASSEMBLE(head, node, left, right, field) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
|
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
|
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
|
||||||
@ -140,12 +154,15 @@ static __inline struct type * \
|
|||||||
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
|
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
|
||||||
{ \
|
{ \
|
||||||
name##_SPLAY(head, elm); \
|
name##_SPLAY(head, elm); \
|
||||||
if (SPLAY_RIGHT(elm, field) != NULL) { \
|
if (SPLAY_RIGHT(elm, field) != NULL) \
|
||||||
|
{ \
|
||||||
elm = SPLAY_RIGHT(elm, field); \
|
elm = SPLAY_RIGHT(elm, field); \
|
||||||
while (SPLAY_LEFT(elm, field) != NULL) { \
|
while (SPLAY_LEFT(elm, field) != NULL) \
|
||||||
|
{ \
|
||||||
elm = SPLAY_LEFT(elm, field); \
|
elm = SPLAY_LEFT(elm, field); \
|
||||||
} \
|
} \
|
||||||
} else \
|
} \
|
||||||
|
else \
|
||||||
elm = NULL; \
|
elm = NULL; \
|
||||||
return (elm); \
|
return (elm); \
|
||||||
} \
|
} \
|
||||||
@ -164,21 +181,28 @@ name##_SPLAY_MIN_MAX(struct name *head, int val) \
|
|||||||
struct type * \
|
struct type * \
|
||||||
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
|
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
|
||||||
{ \
|
{ \
|
||||||
if (SPLAY_EMPTY(head)) { \
|
if (SPLAY_EMPTY(head)) \
|
||||||
|
{ \
|
||||||
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
|
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
|
||||||
} else { \
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
int __comp; \
|
int __comp; \
|
||||||
name##_SPLAY(head, elm); \
|
name##_SPLAY(head, elm); \
|
||||||
__comp = (cmp)(elm, (head)->sph_root); \
|
__comp = (cmp)(elm, (head)->sph_root); \
|
||||||
if(__comp < 0) { \
|
if (__comp < 0) \
|
||||||
|
{ \
|
||||||
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
|
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
|
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
|
||||||
SPLAY_LEFT((head)->sph_root, field) = NULL; \
|
SPLAY_LEFT((head)->sph_root, field) = NULL; \
|
||||||
} else if (__comp > 0) { \
|
} \
|
||||||
|
else if (__comp > 0) \
|
||||||
|
{ \
|
||||||
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
SPLAY_LEFT(elm, field) = (head)->sph_root; \
|
SPLAY_LEFT(elm, field) = (head)->sph_root; \
|
||||||
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
|
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
|
||||||
} else \
|
} \
|
||||||
|
else \
|
||||||
return ((head)->sph_root); \
|
return ((head)->sph_root); \
|
||||||
} \
|
} \
|
||||||
(head)->sph_root = (elm); \
|
(head)->sph_root = (elm); \
|
||||||
@ -192,10 +216,14 @@ name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
|
|||||||
if (SPLAY_EMPTY(head)) \
|
if (SPLAY_EMPTY(head)) \
|
||||||
return (NULL); \
|
return (NULL); \
|
||||||
name##_SPLAY(head, elm); \
|
name##_SPLAY(head, elm); \
|
||||||
if ((cmp)(elm, (head)->sph_root) == 0) { \
|
if ((cmp)(elm, (head)->sph_root) == 0) \
|
||||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
|
{ \
|
||||||
|
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
||||||
|
{ \
|
||||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
} else { \
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
name##_SPLAY(head, elm); \
|
name##_SPLAY(head, elm); \
|
||||||
@ -215,22 +243,28 @@ name##_SPLAY(struct name *head, struct type *elm) \
|
|||||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
||||||
__left = __right = &__node; \
|
__left = __right = &__node; \
|
||||||
\
|
\
|
||||||
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
|
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) \
|
||||||
if (__comp < 0) { \
|
{ \
|
||||||
|
if (__comp < 0) \
|
||||||
|
{ \
|
||||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
if (__tmp == NULL) \
|
if (__tmp == NULL) \
|
||||||
break; \
|
break; \
|
||||||
if ((cmp)(elm, __tmp) < 0){ \
|
if ((cmp)(elm, __tmp) < 0) \
|
||||||
|
{ \
|
||||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
SPLAY_LINKLEFT(head, __right, field); \
|
SPLAY_LINKLEFT(head, __right, field); \
|
||||||
} else if (__comp > 0) { \
|
} \
|
||||||
|
else if (__comp > 0) \
|
||||||
|
{ \
|
||||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
if (__tmp == NULL) \
|
if (__tmp == NULL) \
|
||||||
break; \
|
break; \
|
||||||
if ((cmp)(elm, __tmp) > 0){ \
|
if ((cmp)(elm, __tmp) > 0) \
|
||||||
|
{ \
|
||||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
||||||
break; \
|
break; \
|
||||||
@ -251,22 +285,28 @@ void name##_SPLAY_MINMAX(struct name *head, int __comp) \
|
|||||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
||||||
__left = __right = &__node; \
|
__left = __right = &__node; \
|
||||||
\
|
\
|
||||||
while (1) { \
|
while (1) \
|
||||||
if (__comp < 0) { \
|
{ \
|
||||||
|
if (__comp < 0) \
|
||||||
|
{ \
|
||||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||||
if (__tmp == NULL) \
|
if (__tmp == NULL) \
|
||||||
break; \
|
break; \
|
||||||
if (__comp < 0){ \
|
if (__comp < 0) \
|
||||||
|
{ \
|
||||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
SPLAY_LINKLEFT(head, __right, field); \
|
SPLAY_LINKLEFT(head, __right, field); \
|
||||||
} else if (__comp > 0) { \
|
} \
|
||||||
|
else if (__comp > 0) \
|
||||||
|
{ \
|
||||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||||
if (__tmp == NULL) \
|
if (__tmp == NULL) \
|
||||||
break; \
|
break; \
|
||||||
if (__comp > 0) { \
|
if (__comp > 0) \
|
||||||
|
{ \
|
||||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
||||||
break; \
|
break; \
|
||||||
@ -296,21 +336,25 @@ void name##_SPLAY_MINMAX(struct name *head, int __comp) \
|
|||||||
|
|
||||||
/* Macros that define a red-black tree */
|
/* Macros that define a red-black tree */
|
||||||
#define RB_HEAD(name, type) \
|
#define RB_HEAD(name, type) \
|
||||||
struct name { \
|
struct name \
|
||||||
|
{ \
|
||||||
struct type *rbh_root; /* root of the tree */ \
|
struct type *rbh_root; /* root of the tree */ \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RB_INITIALIZER(root) \
|
#define RB_INITIALIZER(root) \
|
||||||
{NULL}
|
{NULL}
|
||||||
|
|
||||||
#define RB_INIT(root) do { \
|
#define RB_INIT(root) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
(root)->rbh_root = NULL; \
|
(root)->rbh_root = NULL; \
|
||||||
} while (/*CONSTCOND*/ 0)
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
#define RB_BLACK 0
|
#define RB_BLACK 0
|
||||||
#define RB_RED 1
|
#define RB_RED 1
|
||||||
#define RB_ENTRY(type) \
|
#define RB_ENTRY(type) \
|
||||||
struct { \
|
struct \
|
||||||
|
{ \
|
||||||
struct type *rbe_left; /* left element */ \
|
struct type *rbe_left; /* left element */ \
|
||||||
struct type *rbe_right; /* right element */ \
|
struct type *rbe_right; /* right element */ \
|
||||||
struct type *rbe_parent; /* parent element */ \
|
struct type *rbe_parent; /* parent element */ \
|
||||||
@ -324,33 +368,45 @@ struct { \
|
|||||||
#define RB_ROOT(head) (head)->rbh_root
|
#define RB_ROOT(head) (head)->rbh_root
|
||||||
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
|
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
|
||||||
|
|
||||||
#define RB_SET(elm, parent, field) do { \
|
#define RB_SET(elm, parent, field) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
RB_PARENT(elm, field) = parent; \
|
RB_PARENT(elm, field) = parent; \
|
||||||
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
|
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
|
||||||
RB_COLOR(elm, field) = RB_RED; \
|
RB_COLOR(elm, field) = RB_RED; \
|
||||||
} while (/*CONSTCOND*/ 0)
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
#define RB_SET_BLACKRED(black, red, field) do { \
|
#define RB_SET_BLACKRED(black, red, field) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
RB_COLOR(black, field) = RB_BLACK; \
|
RB_COLOR(black, field) = RB_BLACK; \
|
||||||
RB_COLOR(red, field) = RB_RED; \
|
RB_COLOR(red, field) = RB_RED; \
|
||||||
} while (/*CONSTCOND*/ 0)
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
#ifndef RB_AUGMENT
|
#ifndef RB_AUGMENT
|
||||||
#define RB_AUGMENT(x) do {} while (0)
|
#define RB_AUGMENT(x) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
|
#define RB_ROTATE_LEFT(head, elm, tmp, field) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
(tmp) = RB_RIGHT(elm, field); \
|
(tmp) = RB_RIGHT(elm, field); \
|
||||||
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
|
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) \
|
||||||
|
{ \
|
||||||
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
|
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
|
||||||
} \
|
} \
|
||||||
RB_AUGMENT(elm); \
|
RB_AUGMENT(elm); \
|
||||||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) \
|
||||||
|
{ \
|
||||||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||||
else \
|
else \
|
||||||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||||
} else \
|
} \
|
||||||
|
else \
|
||||||
(head)->rbh_root = (tmp); \
|
(head)->rbh_root = (tmp); \
|
||||||
RB_LEFT(tmp, field) = (elm); \
|
RB_LEFT(tmp, field) = (elm); \
|
||||||
RB_PARENT(elm, field) = (tmp); \
|
RB_PARENT(elm, field) = (tmp); \
|
||||||
@ -359,18 +415,23 @@ struct { \
|
|||||||
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
||||||
} while (/*CONSTCOND*/ 0)
|
} while (/*CONSTCOND*/ 0)
|
||||||
|
|
||||||
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
|
#define RB_ROTATE_RIGHT(head, elm, tmp, field) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
(tmp) = RB_LEFT(elm, field); \
|
(tmp) = RB_LEFT(elm, field); \
|
||||||
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
|
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) \
|
||||||
|
{ \
|
||||||
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
|
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
|
||||||
} \
|
} \
|
||||||
RB_AUGMENT(elm); \
|
RB_AUGMENT(elm); \
|
||||||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) \
|
||||||
|
{ \
|
||||||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||||
else \
|
else \
|
||||||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||||
} else \
|
} \
|
||||||
|
else \
|
||||||
(head)->rbh_root = (tmp); \
|
(head)->rbh_root = (tmp); \
|
||||||
RB_RIGHT(tmp, field) = (elm); \
|
RB_RIGHT(tmp, field) = (elm); \
|
||||||
RB_PARENT(elm, field) = (tmp); \
|
RB_PARENT(elm, field) = (tmp); \
|
||||||
@ -437,17 +498,21 @@ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
|
|||||||
{ \
|
{ \
|
||||||
struct type *parent, *gparent, *tmp; \
|
struct type *parent, *gparent, *tmp; \
|
||||||
while ((parent = RB_PARENT(elm, field)) != NULL && \
|
while ((parent = RB_PARENT(elm, field)) != NULL && \
|
||||||
RB_COLOR(parent, field) == RB_RED) { \
|
RB_COLOR(parent, field) == RB_RED) \
|
||||||
|
{ \
|
||||||
gparent = RB_PARENT(parent, field); \
|
gparent = RB_PARENT(parent, field); \
|
||||||
if (parent == RB_LEFT(gparent, field)) { \
|
if (parent == RB_LEFT(gparent, field)) \
|
||||||
|
{ \
|
||||||
tmp = RB_RIGHT(gparent, field); \
|
tmp = RB_RIGHT(gparent, field); \
|
||||||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
if (tmp && RB_COLOR(tmp, field) == RB_RED) \
|
||||||
|
{ \
|
||||||
RB_COLOR(tmp, field) = RB_BLACK; \
|
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||||
RB_SET_BLACKRED(parent, gparent, field); \
|
RB_SET_BLACKRED(parent, gparent, field); \
|
||||||
elm = gparent; \
|
elm = gparent; \
|
||||||
continue; \
|
continue; \
|
||||||
} \
|
} \
|
||||||
if (RB_RIGHT(parent, field) == elm) { \
|
if (RB_RIGHT(parent, field) == elm) \
|
||||||
|
{ \
|
||||||
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
||||||
tmp = parent; \
|
tmp = parent; \
|
||||||
parent = elm; \
|
parent = elm; \
|
||||||
@ -455,15 +520,19 @@ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
|
|||||||
} \
|
} \
|
||||||
RB_SET_BLACKRED(parent, gparent, field); \
|
RB_SET_BLACKRED(parent, gparent, field); \
|
||||||
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
|
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
|
||||||
} else { \
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
tmp = RB_LEFT(gparent, field); \
|
tmp = RB_LEFT(gparent, field); \
|
||||||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
if (tmp && RB_COLOR(tmp, field) == RB_RED) \
|
||||||
|
{ \
|
||||||
RB_COLOR(tmp, field) = RB_BLACK; \
|
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||||
RB_SET_BLACKRED(parent, gparent, field); \
|
RB_SET_BLACKRED(parent, gparent, field); \
|
||||||
elm = gparent; \
|
elm = gparent; \
|
||||||
continue; \
|
continue; \
|
||||||
} \
|
} \
|
||||||
if (RB_LEFT(parent, field) == elm) { \
|
if (RB_LEFT(parent, field) == elm) \
|
||||||
|
{ \
|
||||||
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
||||||
tmp = parent; \
|
tmp = parent; \
|
||||||
parent = elm; \
|
parent = elm; \
|
||||||
@ -482,10 +551,13 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm)
|
|||||||
{ \
|
{ \
|
||||||
struct type *tmp; \
|
struct type *tmp; \
|
||||||
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
|
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
|
||||||
elm != RB_ROOT(head)) { \
|
elm != RB_ROOT(head)) \
|
||||||
if (RB_LEFT(parent, field) == elm) { \
|
{ \
|
||||||
|
if (RB_LEFT(parent, field) == elm) \
|
||||||
|
{ \
|
||||||
tmp = RB_RIGHT(parent, field); \
|
tmp = RB_RIGHT(parent, field); \
|
||||||
if (RB_COLOR(tmp, field) == RB_RED) { \
|
if (RB_COLOR(tmp, field) == RB_RED) \
|
||||||
|
{ \
|
||||||
RB_SET_BLACKRED(tmp, parent, field); \
|
RB_SET_BLACKRED(tmp, parent, field); \
|
||||||
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
||||||
tmp = RB_RIGHT(parent, field); \
|
tmp = RB_RIGHT(parent, field); \
|
||||||
@ -493,16 +565,19 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm)
|
|||||||
if ((RB_LEFT(tmp, field) == NULL || \
|
if ((RB_LEFT(tmp, field) == NULL || \
|
||||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
|
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
|
||||||
(RB_RIGHT(tmp, field) == NULL || \
|
(RB_RIGHT(tmp, field) == NULL || \
|
||||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
|
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) \
|
||||||
|
{ \
|
||||||
RB_COLOR(tmp, field) = RB_RED; \
|
RB_COLOR(tmp, field) = RB_RED; \
|
||||||
elm = parent; \
|
elm = parent; \
|
||||||
parent = RB_PARENT(elm, field); \
|
parent = RB_PARENT(elm, field); \
|
||||||
} else { \
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
if (RB_RIGHT(tmp, field) == NULL || \
|
if (RB_RIGHT(tmp, field) == NULL || \
|
||||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
|
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) \
|
||||||
|
{ \
|
||||||
struct type *oleft; \
|
struct type *oleft; \
|
||||||
if ((oleft = RB_LEFT(tmp, field)) \
|
if ((oleft = RB_LEFT(tmp, field)) != NULL) \
|
||||||
!= NULL) \
|
|
||||||
RB_COLOR(oleft, field) = RB_BLACK; \
|
RB_COLOR(oleft, field) = RB_BLACK; \
|
||||||
RB_COLOR(tmp, field) = RB_RED; \
|
RB_COLOR(tmp, field) = RB_RED; \
|
||||||
RB_ROTATE_RIGHT(head, tmp, oleft, field); \
|
RB_ROTATE_RIGHT(head, tmp, oleft, field); \
|
||||||
@ -516,9 +591,12 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm)
|
|||||||
elm = RB_ROOT(head); \
|
elm = RB_ROOT(head); \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
} else { \
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
tmp = RB_LEFT(parent, field); \
|
tmp = RB_LEFT(parent, field); \
|
||||||
if (RB_COLOR(tmp, field) == RB_RED) { \
|
if (RB_COLOR(tmp, field) == RB_RED) \
|
||||||
|
{ \
|
||||||
RB_SET_BLACKRED(tmp, parent, field); \
|
RB_SET_BLACKRED(tmp, parent, field); \
|
||||||
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
||||||
tmp = RB_LEFT(parent, field); \
|
tmp = RB_LEFT(parent, field); \
|
||||||
@ -526,16 +604,19 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm)
|
|||||||
if ((RB_LEFT(tmp, field) == NULL || \
|
if ((RB_LEFT(tmp, field) == NULL || \
|
||||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
|
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
|
||||||
(RB_RIGHT(tmp, field) == NULL || \
|
(RB_RIGHT(tmp, field) == NULL || \
|
||||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
|
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) \
|
||||||
|
{ \
|
||||||
RB_COLOR(tmp, field) = RB_RED; \
|
RB_COLOR(tmp, field) = RB_RED; \
|
||||||
elm = parent; \
|
elm = parent; \
|
||||||
parent = RB_PARENT(elm, field); \
|
parent = RB_PARENT(elm, field); \
|
||||||
} else { \
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
if (RB_LEFT(tmp, field) == NULL || \
|
if (RB_LEFT(tmp, field) == NULL || \
|
||||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
|
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) \
|
||||||
|
{ \
|
||||||
struct type *oright; \
|
struct type *oright; \
|
||||||
if ((oright = RB_RIGHT(tmp, field)) \
|
if ((oright = RB_RIGHT(tmp, field)) != NULL) \
|
||||||
!= NULL) \
|
|
||||||
RB_COLOR(oright, field) = RB_BLACK; \
|
RB_COLOR(oright, field) = RB_BLACK; \
|
||||||
RB_COLOR(tmp, field) = RB_RED; \
|
RB_COLOR(tmp, field) = RB_RED; \
|
||||||
RB_ROTATE_LEFT(head, tmp, oright, field); \
|
RB_ROTATE_LEFT(head, tmp, oright, field); \
|
||||||
@ -565,7 +646,8 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \
|
|||||||
child = RB_RIGHT(elm, field); \
|
child = RB_RIGHT(elm, field); \
|
||||||
else if (RB_RIGHT(elm, field) == NULL) \
|
else if (RB_RIGHT(elm, field) == NULL) \
|
||||||
child = RB_LEFT(elm, field); \
|
child = RB_LEFT(elm, field); \
|
||||||
else { \
|
else \
|
||||||
|
{ \
|
||||||
struct type *left; \
|
struct type *left; \
|
||||||
elm = RB_RIGHT(elm, field); \
|
elm = RB_RIGHT(elm, field); \
|
||||||
while ((left = RB_LEFT(elm, field)) != NULL) \
|
while ((left = RB_LEFT(elm, field)) != NULL) \
|
||||||
@ -575,31 +657,37 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \
|
|||||||
color = RB_COLOR(elm, field); \
|
color = RB_COLOR(elm, field); \
|
||||||
if (child) \
|
if (child) \
|
||||||
RB_PARENT(child, field) = parent; \
|
RB_PARENT(child, field) = parent; \
|
||||||
if (parent) { \
|
if (parent) \
|
||||||
|
{ \
|
||||||
if (RB_LEFT(parent, field) == elm) \
|
if (RB_LEFT(parent, field) == elm) \
|
||||||
RB_LEFT(parent, field) = child; \
|
RB_LEFT(parent, field) = child; \
|
||||||
else \
|
else \
|
||||||
RB_RIGHT(parent, field) = child; \
|
RB_RIGHT(parent, field) = child; \
|
||||||
RB_AUGMENT(parent); \
|
RB_AUGMENT(parent); \
|
||||||
} else \
|
} \
|
||||||
|
else \
|
||||||
RB_ROOT(head) = child; \
|
RB_ROOT(head) = child; \
|
||||||
if (RB_PARENT(elm, field) == old) \
|
if (RB_PARENT(elm, field) == old) \
|
||||||
parent = elm; \
|
parent = elm; \
|
||||||
(elm)->field = (old)->field; \
|
(elm)->field = (old)->field; \
|
||||||
if (RB_PARENT(old, field)) { \
|
if (RB_PARENT(old, field)) \
|
||||||
|
{ \
|
||||||
if (RB_LEFT(RB_PARENT(old, field), field) == old) \
|
if (RB_LEFT(RB_PARENT(old, field), field) == old) \
|
||||||
RB_LEFT(RB_PARENT(old, field), field) = elm; \
|
RB_LEFT(RB_PARENT(old, field), field) = elm; \
|
||||||
else \
|
else \
|
||||||
RB_RIGHT(RB_PARENT(old, field), field) = elm; \
|
RB_RIGHT(RB_PARENT(old, field), field) = elm; \
|
||||||
RB_AUGMENT(RB_PARENT(old, field)); \
|
RB_AUGMENT(RB_PARENT(old, field)); \
|
||||||
} else \
|
} \
|
||||||
|
else \
|
||||||
RB_ROOT(head) = elm; \
|
RB_ROOT(head) = elm; \
|
||||||
RB_PARENT(RB_LEFT(old, field), field) = elm; \
|
RB_PARENT(RB_LEFT(old, field), field) = elm; \
|
||||||
if (RB_RIGHT(old, field)) \
|
if (RB_RIGHT(old, field)) \
|
||||||
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
|
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
|
||||||
if (parent) { \
|
if (parent) \
|
||||||
|
{ \
|
||||||
left = parent; \
|
left = parent; \
|
||||||
do { \
|
do \
|
||||||
|
{ \
|
||||||
RB_AUGMENT(left); \
|
RB_AUGMENT(left); \
|
||||||
} while ((left = RB_PARENT(left, field)) != NULL); \
|
} while ((left = RB_PARENT(left, field)) != NULL); \
|
||||||
} \
|
} \
|
||||||
@ -609,19 +697,21 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \
|
|||||||
color = RB_COLOR(elm, field); \
|
color = RB_COLOR(elm, field); \
|
||||||
if (child) \
|
if (child) \
|
||||||
RB_PARENT(child, field) = parent; \
|
RB_PARENT(child, field) = parent; \
|
||||||
if (parent) { \
|
if (parent) \
|
||||||
|
{ \
|
||||||
if (RB_LEFT(parent, field) == elm) \
|
if (RB_LEFT(parent, field) == elm) \
|
||||||
RB_LEFT(parent, field) = child; \
|
RB_LEFT(parent, field) = child; \
|
||||||
else \
|
else \
|
||||||
RB_RIGHT(parent, field) = child; \
|
RB_RIGHT(parent, field) = child; \
|
||||||
RB_AUGMENT(parent); \
|
RB_AUGMENT(parent); \
|
||||||
} else \
|
} \
|
||||||
|
else \
|
||||||
RB_ROOT(head) = child; \
|
RB_ROOT(head) = child; \
|
||||||
color: \
|
color: \
|
||||||
if (color == RB_BLACK) \
|
if (color == RB_BLACK) \
|
||||||
name##_RB_REMOVE_COLOR(head, parent, child); \
|
name##_RB_REMOVE_COLOR(head, parent, child); \
|
||||||
return (old); \
|
return (old); \
|
||||||
} \
|
}
|
||||||
|
|
||||||
#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \
|
#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \
|
||||||
/* Inserts a node into the RB tree */ \
|
/* Inserts a node into the RB tree */ \
|
||||||
@ -632,7 +722,8 @@ name##_RB_INSERT(struct name *head, struct type *elm) \
|
|||||||
struct type *parent = NULL; \
|
struct type *parent = NULL; \
|
||||||
int comp = 0; \
|
int comp = 0; \
|
||||||
tmp = RB_ROOT(head); \
|
tmp = RB_ROOT(head); \
|
||||||
while (tmp) { \
|
while (tmp) \
|
||||||
|
{ \
|
||||||
parent = tmp; \
|
parent = tmp; \
|
||||||
comp = (cmp)(elm, parent); \
|
comp = (cmp)(elm, parent); \
|
||||||
if (comp < 0) \
|
if (comp < 0) \
|
||||||
@ -643,13 +734,15 @@ name##_RB_INSERT(struct name *head, struct type *elm) \
|
|||||||
return (tmp); \
|
return (tmp); \
|
||||||
} \
|
} \
|
||||||
RB_SET(elm, parent, field); \
|
RB_SET(elm, parent, field); \
|
||||||
if (parent != NULL) { \
|
if (parent != NULL) \
|
||||||
|
{ \
|
||||||
if (comp < 0) \
|
if (comp < 0) \
|
||||||
RB_LEFT(parent, field) = elm; \
|
RB_LEFT(parent, field) = elm; \
|
||||||
else \
|
else \
|
||||||
RB_RIGHT(parent, field) = elm; \
|
RB_RIGHT(parent, field) = elm; \
|
||||||
RB_AUGMENT(parent); \
|
RB_AUGMENT(parent); \
|
||||||
} else \
|
} \
|
||||||
|
else \
|
||||||
RB_ROOT(head) = elm; \
|
RB_ROOT(head) = elm; \
|
||||||
name##_RB_INSERT_COLOR(head, elm); \
|
name##_RB_INSERT_COLOR(head, elm); \
|
||||||
return (NULL); \
|
return (NULL); \
|
||||||
@ -662,7 +755,8 @@ name##_RB_FIND(struct name *head, struct type *elm) \
|
|||||||
{ \
|
{ \
|
||||||
struct type *tmp = RB_ROOT(head); \
|
struct type *tmp = RB_ROOT(head); \
|
||||||
int comp; \
|
int comp; \
|
||||||
while (tmp) { \
|
while (tmp) \
|
||||||
|
{ \
|
||||||
comp = cmp(elm, tmp); \
|
comp = cmp(elm, tmp); \
|
||||||
if (comp < 0) \
|
if (comp < 0) \
|
||||||
tmp = RB_LEFT(tmp, field); \
|
tmp = RB_LEFT(tmp, field); \
|
||||||
@ -682,9 +776,11 @@ name##_RB_NFIND(struct name *head, struct type *elm) \
|
|||||||
struct type *tmp = RB_ROOT(head); \
|
struct type *tmp = RB_ROOT(head); \
|
||||||
struct type *res = NULL; \
|
struct type *res = NULL; \
|
||||||
int comp; \
|
int comp; \
|
||||||
while (tmp) { \
|
while (tmp) \
|
||||||
|
{ \
|
||||||
comp = cmp(elm, tmp); \
|
comp = cmp(elm, tmp); \
|
||||||
if (comp < 0) { \
|
if (comp < 0) \
|
||||||
|
{ \
|
||||||
res = tmp; \
|
res = tmp; \
|
||||||
tmp = RB_LEFT(tmp, field); \
|
tmp = RB_LEFT(tmp, field); \
|
||||||
} \
|
} \
|
||||||
@ -701,15 +797,19 @@ name##_RB_NFIND(struct name *head, struct type *elm) \
|
|||||||
attr struct type * \
|
attr struct type * \
|
||||||
name##_RB_NEXT(struct type *elm) \
|
name##_RB_NEXT(struct type *elm) \
|
||||||
{ \
|
{ \
|
||||||
if (RB_RIGHT(elm, field)) { \
|
if (RB_RIGHT(elm, field)) \
|
||||||
|
{ \
|
||||||
elm = RB_RIGHT(elm, field); \
|
elm = RB_RIGHT(elm, field); \
|
||||||
while (RB_LEFT(elm, field)) \
|
while (RB_LEFT(elm, field)) \
|
||||||
elm = RB_LEFT(elm, field); \
|
elm = RB_LEFT(elm, field); \
|
||||||
} else { \
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
if (RB_PARENT(elm, field) && \
|
if (RB_PARENT(elm, field) && \
|
||||||
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
||||||
elm = RB_PARENT(elm, field); \
|
elm = RB_PARENT(elm, field); \
|
||||||
else { \
|
else \
|
||||||
|
{ \
|
||||||
while (RB_PARENT(elm, field) && \
|
while (RB_PARENT(elm, field) && \
|
||||||
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
||||||
elm = RB_PARENT(elm, field); \
|
elm = RB_PARENT(elm, field); \
|
||||||
@ -724,15 +824,19 @@ name##_RB_NEXT(struct type *elm) \
|
|||||||
attr struct type * \
|
attr struct type * \
|
||||||
name##_RB_PREV(struct type *elm) \
|
name##_RB_PREV(struct type *elm) \
|
||||||
{ \
|
{ \
|
||||||
if (RB_LEFT(elm, field)) { \
|
if (RB_LEFT(elm, field)) \
|
||||||
|
{ \
|
||||||
elm = RB_LEFT(elm, field); \
|
elm = RB_LEFT(elm, field); \
|
||||||
while (RB_RIGHT(elm, field)) \
|
while (RB_RIGHT(elm, field)) \
|
||||||
elm = RB_RIGHT(elm, field); \
|
elm = RB_RIGHT(elm, field); \
|
||||||
} else { \
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
if (RB_PARENT(elm, field) && \
|
if (RB_PARENT(elm, field) && \
|
||||||
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
||||||
elm = RB_PARENT(elm, field); \
|
elm = RB_PARENT(elm, field); \
|
||||||
else { \
|
else \
|
||||||
|
{ \
|
||||||
while (RB_PARENT(elm, field) && \
|
while (RB_PARENT(elm, field) && \
|
||||||
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
||||||
elm = RB_PARENT(elm, field); \
|
elm = RB_PARENT(elm, field); \
|
||||||
@ -748,7 +852,8 @@ name##_RB_MINMAX(struct name *head, int val) \
|
|||||||
{ \
|
{ \
|
||||||
struct type *tmp = RB_ROOT(head); \
|
struct type *tmp = RB_ROOT(head); \
|
||||||
struct type *parent = NULL; \
|
struct type *parent = NULL; \
|
||||||
while (tmp) { \
|
while (tmp) \
|
||||||
|
{ \
|
||||||
parent = tmp; \
|
parent = tmp; \
|
||||||
if (val < 0) \
|
if (val < 0) \
|
||||||
tmp = RB_LEFT(tmp, field); \
|
tmp = RB_LEFT(tmp, field); \
|
||||||
|
@ -105,7 +105,6 @@ int DLOG_PERROR(const char *s)
|
|||||||
return DLOG_ERR("%s: %s\n", s, strerror(errno));
|
return DLOG_ERR("%s: %s\n", s, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int LOG_APPEND(const char *filename, const char *format, va_list args)
|
int LOG_APPEND(const char *filename, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
@ -14,7 +14,13 @@
|
|||||||
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
|
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
|
||||||
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
||||||
|
|
||||||
enum bindll { unwanted=0, no, prefer, force };
|
enum bindll
|
||||||
|
{
|
||||||
|
unwanted = 0,
|
||||||
|
no,
|
||||||
|
prefer,
|
||||||
|
force
|
||||||
|
};
|
||||||
|
|
||||||
#define MAX_BINDS 32
|
#define MAX_BINDS 32
|
||||||
struct bind_s
|
struct bind_s
|
||||||
@ -25,7 +31,12 @@ struct bind_s
|
|||||||
int bind_wait_ifup, bind_wait_ip, bind_wait_ip_ll;
|
int bind_wait_ifup, bind_wait_ip, bind_wait_ip_ll;
|
||||||
};
|
};
|
||||||
|
|
||||||
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 params_s
|
||||||
{
|
{
|
||||||
|
20
tpws/pools.c
20
tpws/pools.c
@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
#define DESTROY_STR_POOL(etype, ppool) \
|
#define DESTROY_STR_POOL(etype, ppool) \
|
||||||
etype *elem, *tmp; \
|
etype *elem, *tmp; \
|
||||||
HASH_ITER(hh, *ppool, elem, tmp) { \
|
HASH_ITER(hh, *ppool, elem, tmp) \
|
||||||
|
{ \
|
||||||
free(elem->str); \
|
free(elem->str); \
|
||||||
HASH_DEL(*ppool, elem); \
|
HASH_DEL(*ppool, elem); \
|
||||||
free(elem); \
|
free(elem); \
|
||||||
@ -32,7 +33,6 @@
|
|||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef uthash_nonfatal_oom
|
#undef uthash_nonfatal_oom
|
||||||
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
|
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
|
||||||
static bool oom = false;
|
static bool oom = false;
|
||||||
@ -65,13 +65,8 @@ void StrPoolDestroy(strpool **pp)
|
|||||||
DESTROY_STR_POOL(strpool, pp)
|
DESTROY_STR_POOL(strpool, pp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HostFailPoolDestroy(hostfail_pool **pp){
|
||||||
|
DESTROY_STR_POOL(hostfail_pool, pp)} hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time)
|
||||||
void HostFailPoolDestroy(hostfail_pool **pp)
|
|
||||||
{
|
|
||||||
DESTROY_STR_POOL(hostfail_pool, pp)
|
|
||||||
}
|
|
||||||
hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
|
|
||||||
{
|
{
|
||||||
size_t slen = strlen(s);
|
size_t slen = strlen(s);
|
||||||
ADD_STR_POOL(hostfail_pool, pp, s, slen)
|
ADD_STR_POOL(hostfail_pool, pp, s, slen)
|
||||||
@ -123,11 +118,11 @@ void HostFailPoolDump(hostfail_pool *p)
|
|||||||
printf("host=%s counter=%d time_left=%lld\n", elem->str, elem->counter, (long long int)elem->expire - now);
|
printf("host=%s counter=%d time_left=%lld\n", elem->str, elem->counter, (long long int)elem->expire - now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool strlist_add(struct str_list_head *head, const char *filename)
|
bool strlist_add(struct str_list_head *head, const char *filename)
|
||||||
{
|
{
|
||||||
struct str_list *entry = malloc(sizeof(struct str_list));
|
struct str_list *entry = malloc(sizeof(struct str_list));
|
||||||
if (!entry) return false;
|
if (!entry)
|
||||||
|
return false;
|
||||||
entry->str = strdup(filename);
|
entry->str = strdup(filename);
|
||||||
if (!entry->str)
|
if (!entry->str)
|
||||||
{
|
{
|
||||||
@ -139,7 +134,8 @@ bool strlist_add(struct str_list_head *head, const char *filename)
|
|||||||
}
|
}
|
||||||
static void strlist_entry_destroy(struct str_list *entry)
|
static void strlist_entry_destroy(struct str_list *entry)
|
||||||
{
|
{
|
||||||
if (entry->str) free(entry->str);
|
if (entry->str)
|
||||||
|
free(entry->str);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
void strlist_destroy(struct str_list_head *head)
|
void strlist_destroy(struct str_list_head *head)
|
||||||
|
13
tpws/pools.h
13
tpws/pools.h
@ -10,7 +10,8 @@
|
|||||||
#define HASH_FUNCTION HASH_BER
|
#define HASH_FUNCTION HASH_BER
|
||||||
#include "uthash.h"
|
#include "uthash.h"
|
||||||
|
|
||||||
typedef struct strpool {
|
typedef struct strpool
|
||||||
|
{
|
||||||
char *str; /* key */
|
char *str; /* key */
|
||||||
UT_hash_handle hh; /* makes this structure hashable */
|
UT_hash_handle hh; /* makes this structure hashable */
|
||||||
} strpool;
|
} strpool;
|
||||||
@ -20,14 +21,16 @@ bool StrPoolAddStr(strpool **pp,const char *s);
|
|||||||
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen);
|
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen);
|
||||||
bool StrPoolCheckStr(strpool *p, const char *s);
|
bool StrPoolCheckStr(strpool *p, const char *s);
|
||||||
|
|
||||||
struct str_list {
|
struct str_list
|
||||||
|
{
|
||||||
char *str;
|
char *str;
|
||||||
LIST_ENTRY(str_list) next;
|
LIST_ENTRY(str_list)
|
||||||
|
next;
|
||||||
};
|
};
|
||||||
LIST_HEAD(str_list_head, str_list);
|
LIST_HEAD(str_list_head, str_list);
|
||||||
|
|
||||||
|
typedef struct hostfail_pool
|
||||||
typedef struct hostfail_pool {
|
{
|
||||||
char *str; /* key */
|
char *str; /* key */
|
||||||
int counter; /* value */
|
int counter; /* value */
|
||||||
time_t expire; /* when to expire record (unixtime) */
|
time_t expire; /* when to expire record (unixtime) */
|
||||||
|
128
tpws/protocol.c
128
tpws/protocol.c
@ -7,7 +7,6 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
const char *http_methods[] = {"GET /", "POST /", "HEAD /", "OPTIONS /", "PUT /", "DELETE /", "CONNECT /", "TRACE /", NULL};
|
const char *http_methods[] = {"GET /", "POST /", "HEAD /", "OPTIONS /", "PUT /", "DELETE /", "CONNECT /", "TRACE /", NULL};
|
||||||
const char *HttpMethod(const uint8_t *data, size_t len)
|
const char *HttpMethod(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
@ -31,7 +30,8 @@ bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs)
|
|||||||
if (!*pHost)
|
if (!*pHost)
|
||||||
{
|
{
|
||||||
*pHost = memmem(buf, bs, "\nHost:", 6);
|
*pHost = memmem(buf, bs, "\nHost:", 6);
|
||||||
if (*pHost) (*pHost)++;
|
if (*pHost)
|
||||||
|
(*pHost)++;
|
||||||
}
|
}
|
||||||
return !!*pHost;
|
return !!*pHost;
|
||||||
}
|
}
|
||||||
@ -40,7 +40,8 @@ bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs)
|
|||||||
if (!*pHost)
|
if (!*pHost)
|
||||||
{
|
{
|
||||||
*pHost = memmem(buf, bs, "\nHost:", 6);
|
*pHost = memmem(buf, bs, "\nHost:", 6);
|
||||||
if (*pHost) (*pHost)++;
|
if (*pHost)
|
||||||
|
(*pHost)++;
|
||||||
}
|
}
|
||||||
return !!*pHost;
|
return !!*pHost;
|
||||||
}
|
}
|
||||||
@ -61,18 +62,23 @@ bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char
|
|||||||
const uint8_t *p, *s, *e = data + len;
|
const uint8_t *p, *s, *e = data + len;
|
||||||
|
|
||||||
p = (uint8_t *)strncasestr((char *)data, header, len);
|
p = (uint8_t *)strncasestr((char *)data, header, len);
|
||||||
if (!p) return false;
|
if (!p)
|
||||||
|
return false;
|
||||||
p += strlen(header);
|
p += strlen(header);
|
||||||
while (p < e && (*p == ' ' || *p == '\t')) p++;
|
while (p < e && (*p == ' ' || *p == '\t'))
|
||||||
|
p++;
|
||||||
s = p;
|
s = p;
|
||||||
while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t')) s++;
|
while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t'))
|
||||||
|
s++;
|
||||||
if (s > p)
|
if (s > p)
|
||||||
{
|
{
|
||||||
size_t slen = s - p;
|
size_t slen = s - p;
|
||||||
if (buf && len_buf)
|
if (buf && len_buf)
|
||||||
{
|
{
|
||||||
if (slen >= len_buf) slen = len_buf - 1;
|
if (slen >= len_buf)
|
||||||
for (size_t i = 0; i < slen; i++) buf[i] = tolower(p[i]);
|
slen = len_buf - 1;
|
||||||
|
for (size_t i = 0; i < slen; i++)
|
||||||
|
buf[i] = tolower(p[i]);
|
||||||
buf[slen] = 0;
|
buf[slen] = 0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -88,9 +94,13 @@ const char *HttpFind2ndLevelDomain(const char *host)
|
|||||||
const char *p = NULL;
|
const char *p = NULL;
|
||||||
if (*host)
|
if (*host)
|
||||||
{
|
{
|
||||||
for (p = host + strlen(host)-1; p>host && *p!='.'; p--);
|
for (p = host + strlen(host) - 1; p > host && *p != '.'; p--)
|
||||||
if (*p=='.') for (p--; p>host && *p!='.'; p--);
|
;
|
||||||
if (*p=='.') p++;
|
if (*p == '.')
|
||||||
|
for (p--; p > host && *p != '.'; p--)
|
||||||
|
;
|
||||||
|
if (*p == '.')
|
||||||
|
p++;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -100,11 +110,13 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
|||||||
char loc[256], *redirect_host, *p;
|
char loc[256], *redirect_host, *p;
|
||||||
int code;
|
int code;
|
||||||
|
|
||||||
if (!host || !*host) return false;
|
if (!host || !*host)
|
||||||
|
return false;
|
||||||
|
|
||||||
code = HttpReplyCode(data, len);
|
code = HttpReplyCode(data, len);
|
||||||
|
|
||||||
if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false;
|
if ((code != 302 && code != 307) || !HttpExtractHeader(data, len, "\nLocation:", loc, sizeof(loc)))
|
||||||
|
return false;
|
||||||
|
|
||||||
// something like : https://censor.net/badpage.php?reason=denied&source=RKN
|
// something like : https://censor.net/badpage.php?reason=denied&source=RKN
|
||||||
|
|
||||||
@ -117,9 +129,11 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
|||||||
|
|
||||||
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
|
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
|
||||||
|
|
||||||
for(p=redirect_host; *p && *p!='/' ; p++);
|
for (p = redirect_host; *p && *p != '/'; p++)
|
||||||
|
;
|
||||||
*p = 0;
|
*p = 0;
|
||||||
if (!*redirect_host) return false;
|
if (!*redirect_host)
|
||||||
|
return false;
|
||||||
|
|
||||||
// somethinkg like : censor.net
|
// somethinkg like : censor.net
|
||||||
|
|
||||||
@ -140,17 +154,24 @@ size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http,
|
|||||||
case httpreqpos_method:
|
case httpreqpos_method:
|
||||||
// recognize some tpws pre-applied hacks
|
// recognize some tpws pre-applied hacks
|
||||||
method = http;
|
method = http;
|
||||||
if (sz<10) break;
|
if (sz < 10)
|
||||||
if (*method=='\n' || *method=='\r') method++;
|
break;
|
||||||
if (*method=='\n' || *method=='\r') method++;
|
if (*method == '\n' || *method == '\r')
|
||||||
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
|
method++;
|
||||||
if (i<3 || *method!=' ') break;
|
if (*method == '\n' || *method == '\r')
|
||||||
|
method++;
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
if (*method >= 'A' && *method <= 'Z')
|
||||||
|
method++;
|
||||||
|
if (i < 3 || *method != ' ')
|
||||||
|
break;
|
||||||
return method - http - 1;
|
return method - http - 1;
|
||||||
case httpreqpos_host:
|
case httpreqpos_host:
|
||||||
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
|
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
|
||||||
{
|
{
|
||||||
host += 5;
|
host += 5;
|
||||||
if (*host==' ') host++;
|
if (*host == ' ')
|
||||||
|
host++;
|
||||||
return host - http;
|
return host - http;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -162,8 +183,6 @@ size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http,
|
|||||||
return hpos_pos < sz ? hpos_pos : 0;
|
return hpos_pos < sz ? hpos_pos : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t TLSRecordDataLen(const uint8_t *data)
|
uint16_t TLSRecordDataLen(const uint8_t *data)
|
||||||
{
|
{
|
||||||
return pntoh16(data + 3);
|
return pntoh16(data + 3);
|
||||||
@ -201,41 +220,52 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
|
|||||||
|
|
||||||
l = 1 + 3 + 2 + 32;
|
l = 1 + 3 + 2 + 32;
|
||||||
// SessionIDLength
|
// SessionIDLength
|
||||||
if (len < (l + 1)) return false;
|
if (len < (l + 1))
|
||||||
|
return false;
|
||||||
if (!bPartialIsOK)
|
if (!bPartialIsOK)
|
||||||
{
|
{
|
||||||
ll = data[1] << 16 | data[2] << 8 | data[3]; // HandshakeProtocol length
|
ll = data[1] << 16 | data[2] << 8 | data[3]; // HandshakeProtocol length
|
||||||
if (len < (ll + 4)) return false;
|
if (len < (ll + 4))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
l += data[l] + 1;
|
l += data[l] + 1;
|
||||||
// CipherSuitesLength
|
// CipherSuitesLength
|
||||||
if (len < (l + 2)) return false;
|
if (len < (l + 2))
|
||||||
|
return false;
|
||||||
l += pntoh16(data + l) + 2;
|
l += pntoh16(data + l) + 2;
|
||||||
// CompressionMethodsLength
|
// CompressionMethodsLength
|
||||||
if (len < (l + 1)) return false;
|
if (len < (l + 1))
|
||||||
|
return false;
|
||||||
l += data[l] + 1;
|
l += data[l] + 1;
|
||||||
// ExtensionsLength
|
// ExtensionsLength
|
||||||
if (len < (l + 2)) return false;
|
if (len < (l + 2))
|
||||||
|
return false;
|
||||||
|
|
||||||
data += l; len -= l;
|
data += l;
|
||||||
|
len -= l;
|
||||||
l = pntoh16(data);
|
l = pntoh16(data);
|
||||||
data += 2; len -= 2;
|
data += 2;
|
||||||
|
len -= 2;
|
||||||
|
|
||||||
if (bPartialIsOK)
|
if (bPartialIsOK)
|
||||||
{
|
{
|
||||||
if (len < l) l = len;
|
if (len < l)
|
||||||
|
l = len;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (len < l) return false;
|
if (len < l)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (l >= 4)
|
while (l >= 4)
|
||||||
{
|
{
|
||||||
uint16_t etype = pntoh16(data);
|
uint16_t etype = pntoh16(data);
|
||||||
size_t elen = pntoh16(data + 2);
|
size_t elen = pntoh16(data + 2);
|
||||||
data += 4; l -= 4;
|
data += 4;
|
||||||
if (l < elen) break;
|
l -= 4;
|
||||||
|
if (l < elen)
|
||||||
|
break;
|
||||||
if (etype == type)
|
if (etype == type)
|
||||||
{
|
{
|
||||||
if (ext && len_ext)
|
if (ext && len_ext)
|
||||||
@ -245,7 +275,8 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
data += elen; l -= elen;
|
data += elen;
|
||||||
|
l -= elen;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -257,9 +288,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
|||||||
// u16 Version: TLS1.0
|
// u16 Version: TLS1.0
|
||||||
// u16 Length
|
// u16 Length
|
||||||
size_t reclen;
|
size_t reclen;
|
||||||
if (!IsTLSClientHello(data, len, bPartialIsOK)) return false;
|
if (!IsTLSClientHello(data, len, bPartialIsOK))
|
||||||
|
return false;
|
||||||
reclen = TLSRecordLen(data);
|
reclen = TLSRecordLen(data);
|
||||||
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
|
if (reclen < len)
|
||||||
|
len = reclen; // correct len if it has more data than the first tls record has
|
||||||
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
||||||
}
|
}
|
||||||
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
|
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
|
||||||
@ -267,14 +300,19 @@ static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, s
|
|||||||
// u16 data+0 - name list length
|
// u16 data+0 - name list length
|
||||||
// u8 data+2 - server name type. 0=host_name
|
// u8 data+2 - server name type. 0=host_name
|
||||||
// u16 data+3 - server name length
|
// u16 data+3 - server name length
|
||||||
if (elen < 5 || ext[2] != 0) return false;
|
if (elen < 5 || ext[2] != 0)
|
||||||
|
return false;
|
||||||
size_t slen = pntoh16(ext + 3);
|
size_t slen = pntoh16(ext + 3);
|
||||||
ext += 5; elen -= 5;
|
ext += 5;
|
||||||
if (slen < elen) return false;
|
elen -= 5;
|
||||||
|
if (slen < elen)
|
||||||
|
return false;
|
||||||
if (host && len_host)
|
if (host && len_host)
|
||||||
{
|
{
|
||||||
if (slen >= len_host) slen = len_host - 1;
|
if (slen >= len_host)
|
||||||
for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]);
|
slen = len_host - 1;
|
||||||
|
for (size_t i = 0; i < slen; i++)
|
||||||
|
host[i] = tolower(ext[i]);
|
||||||
host[slen] = 0;
|
host[slen] = 0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -284,7 +322,8 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len
|
|||||||
const uint8_t *ext;
|
const uint8_t *ext;
|
||||||
size_t elen;
|
size_t elen;
|
||||||
|
|
||||||
if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK))
|
||||||
|
return false;
|
||||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||||
}
|
}
|
||||||
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK)
|
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK)
|
||||||
@ -292,7 +331,8 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
|||||||
const uint8_t *ext;
|
const uint8_t *ext;
|
||||||
size_t elen;
|
size_t elen;
|
||||||
|
|
||||||
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK))
|
||||||
|
return false;
|
||||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||||
}
|
}
|
||||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
||||||
|
@ -18,7 +18,13 @@ const char *HttpFind2ndLevelDomain(const char *host);
|
|||||||
int HttpReplyCode(const uint8_t *data, size_t len);
|
int HttpReplyCode(const uint8_t *data, size_t len);
|
||||||
// must be pre-checked by IsHttpReply
|
// must be pre-checked by IsHttpReply
|
||||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
||||||
enum httpreqpos { httpreqpos_none = 0, httpreqpos_method, httpreqpos_host, httpreqpos_pos };
|
enum httpreqpos
|
||||||
|
{
|
||||||
|
httpreqpos_none = 0,
|
||||||
|
httpreqpos_method,
|
||||||
|
httpreqpos_host,
|
||||||
|
httpreqpos_pos
|
||||||
|
};
|
||||||
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);
|
||||||
|
|
||||||
uint16_t TLSRecordDataLen(const uint8_t *data);
|
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||||
@ -29,5 +35,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
|||||||
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
||||||
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||||
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||||
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_pos };
|
enum tlspos
|
||||||
|
{
|
||||||
|
tlspos_none = 0,
|
||||||
|
tlspos_sni,
|
||||||
|
tlspos_sniext,
|
||||||
|
tlspos_pos
|
||||||
|
};
|
||||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(BSD)
|
#if defined(BSD)
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
@ -56,13 +55,16 @@ static bool destination_from_pf(const struct sockaddr *accept_sa, struct sockadd
|
|||||||
struct pfioc_natlook nl;
|
struct pfioc_natlook nl;
|
||||||
struct sockaddr_storage asa2;
|
struct sockaddr_storage asa2;
|
||||||
|
|
||||||
if (redirector_fd==-1) return false;
|
if (redirector_fd == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (params.debug >= 2)
|
if (params.debug >= 2)
|
||||||
{
|
{
|
||||||
char s[48], s2[48];
|
char s[48], s2[48];
|
||||||
*s=0; ntop46_port(accept_sa, s, sizeof(s));
|
*s = 0;
|
||||||
*s2=0; ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2));
|
ntop46_port(accept_sa, s, sizeof(s));
|
||||||
|
*s2 = 0;
|
||||||
|
ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2));
|
||||||
DBGPRINT("destination_from_pf %s %s\n", s, s2);
|
DBGPRINT("destination_from_pf %s %s\n", s, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,8 +79,10 @@ static bool destination_from_pf(const struct sockaddr *accept_sa, struct sockadd
|
|||||||
if (params.debug >= 2)
|
if (params.debug >= 2)
|
||||||
{
|
{
|
||||||
char s[48], s2[48];
|
char s[48], s2[48];
|
||||||
*s=0; ntop46_port(accept_sa, s, sizeof(s));
|
*s = 0;
|
||||||
*s2=0; ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2));
|
ntop46_port(accept_sa, s, sizeof(s));
|
||||||
|
*s2 = 0;
|
||||||
|
ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2));
|
||||||
DBGPRINT("destination_from_pf (saconvmapped) %s %s\n", s, s2);
|
DBGPRINT("destination_from_pf (saconvmapped) %s %s\n", s, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +166,6 @@ static bool destination_from_pf(const struct sockaddr *accept_sa, struct sockadd
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
bool redir_init(void) { return true; }
|
bool redir_init(void) { return true; }
|
||||||
@ -170,8 +173,6 @@ void redir_close(void) {};
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Store the original destination address in orig_dst
|
// Store the original destination address in orig_dst
|
||||||
bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr_storage *orig_dst)
|
bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr_storage *orig_dst)
|
||||||
{
|
{
|
||||||
@ -202,7 +203,7 @@ bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (orig_dst->ss_family == AF_INET6)
|
if (orig_dst->ss_family == AF_INET6)
|
||||||
((struct sockaddr_in6*)orig_dst)->sin6_scope_id=0; // or MacOS will not connect()
|
((struct sockaddr_in6 *)orig_dst)->sin6_scope_id = 0; // or macOS will not connect()
|
||||||
#ifdef BSD
|
#ifdef BSD
|
||||||
if (params.pf_enable && !destination_from_pf(accept_sa, orig_dst))
|
if (params.pf_enable && !destination_from_pf(accept_sa, orig_dst))
|
||||||
DBGPRINT("pf filter destination_from_pf failed\n");
|
DBGPRINT("pf filter destination_from_pf failed\n");
|
||||||
|
@ -47,7 +47,8 @@ static void resolver_clear_list(void)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
ri = TAILQ_FIRST(&resolver.resolve_list);
|
ri = TAILQ_FIRST(&resolver.resolve_list);
|
||||||
if (!ri) break;
|
if (!ri)
|
||||||
|
break;
|
||||||
TAILQ_REMOVE(&resolver.resolve_list, ri, next);
|
TAILQ_REMOVE(&resolver.resolve_list, ri, next);
|
||||||
free(ri);
|
free(ri);
|
||||||
}
|
}
|
||||||
@ -69,9 +70,11 @@ static void *resolver_thread(void *arg)
|
|||||||
// printf("resolver_thread %d start\n",syscall(SYS_gettid));
|
// printf("resolver_thread %d start\n",syscall(SYS_gettid));
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (resolver.bStop) break;
|
if (resolver.bStop)
|
||||||
|
break;
|
||||||
r = sem_wait(resolver.sem);
|
r = sem_wait(resolver.sem);
|
||||||
if (resolver.bStop) break;
|
if (resolver.bStop)
|
||||||
|
break;
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
@ -87,7 +90,8 @@ static void *resolver_thread(void *arg)
|
|||||||
|
|
||||||
rlist_lock;
|
rlist_lock;
|
||||||
ri = TAILQ_FIRST(&resolver.resolve_list);
|
ri = TAILQ_FIRST(&resolver.resolve_list);
|
||||||
if (ri) TAILQ_REMOVE(&resolver.resolve_list, ri, next);
|
if (ri)
|
||||||
|
TAILQ_REMOVE(&resolver.resolve_list, ri, next);
|
||||||
rlist_unlock;
|
rlist_unlock;
|
||||||
|
|
||||||
if (ri)
|
if (ri)
|
||||||
@ -170,7 +174,8 @@ bool resolver_init(int threads, int fd_signal_pipe)
|
|||||||
int t;
|
int t;
|
||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
|
|
||||||
if (threads<1 || resolver.bInit) return false;
|
if (threads < 1 || resolver.bInit)
|
||||||
|
return false;
|
||||||
|
|
||||||
memset(&resolver, 0, sizeof(resolver));
|
memset(&resolver, 0, sizeof(resolver));
|
||||||
resolver.bInit = true;
|
resolver.bInit = true;
|
||||||
@ -197,22 +202,24 @@ bool resolver_init(int threads, int fd_signal_pipe)
|
|||||||
resolver.sem = &resolver._sem;
|
resolver.sem = &resolver._sem;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pthread_mutex_init(&resolver.resolve_list_lock, NULL)) goto ex;
|
if (pthread_mutex_init(&resolver.resolve_list_lock, NULL))
|
||||||
|
goto ex;
|
||||||
|
|
||||||
resolver.fd_signal_pipe = fd_signal_pipe;
|
resolver.fd_signal_pipe = fd_signal_pipe;
|
||||||
TAILQ_INIT(&resolver.resolve_list);
|
TAILQ_INIT(&resolver.resolve_list);
|
||||||
|
|
||||||
// start as many threads as we can up to specified number
|
// start as many threads as we can up to specified number
|
||||||
resolver.thread = malloc(sizeof(pthread_t) * threads);
|
resolver.thread = malloc(sizeof(pthread_t) * threads);
|
||||||
if (!resolver.thread) goto ex;
|
if (!resolver.thread)
|
||||||
|
goto ex;
|
||||||
|
|
||||||
memset(&action, 0, sizeof(action));
|
memset(&action, 0, sizeof(action));
|
||||||
action.sa_handler = sigbreak;
|
action.sa_handler = sigbreak;
|
||||||
sigaction(SIG_BREAK, &action, NULL);
|
sigaction(SIG_BREAK, &action, NULL);
|
||||||
|
|
||||||
|
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
if (pthread_attr_init(&attr)) goto ex;
|
if (pthread_attr_init(&attr))
|
||||||
|
goto ex;
|
||||||
// set minimum thread stack size
|
// set minimum thread stack size
|
||||||
|
|
||||||
if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN > 20480 ? PTHREAD_STACK_MIN : 20480))
|
if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN > 20480 ? PTHREAD_STACK_MIN : 20480))
|
||||||
@ -230,7 +237,8 @@ bool resolver_init(int threads, int fd_signal_pipe)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_attr_destroy(&attr);
|
pthread_attr_destroy(&attr);
|
||||||
if (!resolver.threads) goto ex;
|
if (!resolver.threads)
|
||||||
|
goto ex;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -239,12 +247,11 @@ ex:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr)
|
struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr)
|
||||||
{
|
{
|
||||||
struct resolve_item *ri = calloc(1, sizeof(struct resolve_item));
|
struct resolve_item *ri = calloc(1, sizeof(struct resolve_item));
|
||||||
if (!ri) return NULL;
|
if (!ri)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
strncpy(ri->dom, dom, sizeof(ri->dom));
|
strncpy(ri->dom, dom, sizeof(ri->dom));
|
||||||
ri->dom[sizeof(ri->dom) - 1] = 0;
|
ri->dom[sizeof(ri->dom) - 1] = 0;
|
||||||
|
@ -13,7 +13,8 @@ struct resolve_item
|
|||||||
int ga_res; // getaddrinfo result code
|
int ga_res; // getaddrinfo result code
|
||||||
uint16_t port; // request port
|
uint16_t port; // request port
|
||||||
void *ptr;
|
void *ptr;
|
||||||
TAILQ_ENTRY(resolve_item) next;
|
TAILQ_ENTRY(resolve_item)
|
||||||
|
next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr);
|
struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr);
|
||||||
|
15
tpws/sec.c
15
tpws/sec.c
@ -117,8 +117,7 @@ SYS_process_vm_writev,
|
|||||||
#ifdef SYS_process_madvise
|
#ifdef SYS_process_madvise
|
||||||
SYS_process_madvise,
|
SYS_process_madvise,
|
||||||
#endif
|
#endif
|
||||||
SYS_kill, SYS_ptrace
|
SYS_kill, SYS_ptrace};
|
||||||
};
|
|
||||||
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls))
|
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls))
|
||||||
|
|
||||||
static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k)
|
static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k)
|
||||||
@ -178,19 +177,18 @@ bool sec_harden(void)
|
|||||||
if (!set_seccomp())
|
if (!set_seccomp())
|
||||||
{
|
{
|
||||||
DLOG_PERROR("seccomp");
|
DLOG_PERROR("seccomp");
|
||||||
if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
|
if (errno == EINVAL)
|
||||||
|
DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool checkpcap(uint64_t caps)
|
bool checkpcap(uint64_t caps)
|
||||||
{
|
{
|
||||||
if (!caps) return true; // no special caps reqd
|
if (!caps)
|
||||||
|
return true; // no special caps reqd
|
||||||
|
|
||||||
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
|
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
|
||||||
struct __user_cap_data_struct cd[2];
|
struct __user_cap_data_struct cd[2];
|
||||||
@ -221,7 +219,6 @@ int getmaxcap(void)
|
|||||||
fclose(F);
|
fclose(F);
|
||||||
}
|
}
|
||||||
return maxcap;
|
return maxcap;
|
||||||
|
|
||||||
}
|
}
|
||||||
bool dropcaps(void)
|
bool dropcaps(void)
|
||||||
{
|
{
|
||||||
@ -257,8 +254,6 @@ bool sec_harden(void)
|
|||||||
|
|
||||||
#endif // __linux__
|
#endif // __linux__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool can_drop_root(void)
|
bool can_drop_root(void)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
@ -55,7 +55,7 @@ bool dropcaps(void);
|
|||||||
#define ARCH_NR AUDIT_ARCH_MIPS64
|
#define ARCH_NR AUDIT_ARCH_MIPS64
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
# error "Unsupported mips abi"
|
#error "Unsupported MIPS ABI"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(__PPC64__)
|
#elif defined(__PPC64__)
|
||||||
|
20
tpws/socks.h
20
tpws/socks.h
@ -25,8 +25,6 @@ typedef struct
|
|||||||
uint32_t ip;
|
uint32_t ip;
|
||||||
} s4_rep;
|
} s4_rep;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define S5_AUTH_NONE 0
|
#define S5_AUTH_NONE 0
|
||||||
#define S5_AUTH_GSSAPI 1
|
#define S5_AUTH_GSSAPI 1
|
||||||
#define S5_AUTH_USERPASS 2
|
#define S5_AUTH_USERPASS 2
|
||||||
@ -50,16 +48,20 @@ typedef struct
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8_t ver, cmd, rsv, atyp;
|
uint8_t ver, cmd, rsv, atyp;
|
||||||
union {
|
union
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
} d4;
|
} d4;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
struct in6_addr addr;
|
struct in6_addr addr;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
} d6;
|
} d6;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
char domport[255 + 2]; // max hostname + binary port
|
char domport[255 + 2]; // max hostname + binary port
|
||||||
} dd;
|
} dd;
|
||||||
@ -82,8 +84,10 @@ typedef struct
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8_t ver, rep, rsv, atyp;
|
uint8_t ver, rep, rsv, atyp;
|
||||||
union {
|
union
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
} d4;
|
} d4;
|
||||||
|
@ -25,20 +25,24 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
if ((method = HttpMethod(segment, *size)))
|
if ((method = HttpMethod(segment, *size)))
|
||||||
{
|
{
|
||||||
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;
|
if (!ctrack->l7proto)
|
||||||
|
ctrack->l7proto = HTTP;
|
||||||
// cpu saving : we search host only if and when required. we do not research host every time we need its position
|
// cpu saving : we search host only if and when required. we do not research host every time we need its position
|
||||||
if ((params.hostlist || params.hostlist_exclude) && 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++;
|
||||||
pp = p;
|
pp = p;
|
||||||
while (pp < (segment + *size) && (pp - p) < (sizeof(Host) - 1) && *pp != '\r' && *pp != '\n') pp++;
|
while (pp < (segment + *size) && (pp - p) < (sizeof(Host) - 1) && *pp != '\r' && *pp != '\n')
|
||||||
|
pp++;
|
||||||
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);
|
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);
|
bBypass = !HostlistCheck(Host, &bHostExcluded);
|
||||||
}
|
}
|
||||||
if (!bBypass)
|
if (!bBypass)
|
||||||
@ -48,7 +52,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
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)))
|
||||||
{
|
{
|
||||||
*p = '\n'; p++;
|
*p = '\n';
|
||||||
|
p++;
|
||||||
memmove(p, p + 1, segment + *size - p - 1);
|
memmove(p, p + 1, segment + *size - p - 1);
|
||||||
(*size)--;
|
(*size)--;
|
||||||
if (pp == (p - 1))
|
if (pp == (p - 1))
|
||||||
@ -67,7 +72,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
if (params.unixeol)
|
if (params.unixeol)
|
||||||
{
|
{
|
||||||
memmove(segment + 1, segment, *size);
|
memmove(segment + 1, segment, *size);
|
||||||
(*size)++;;
|
(*size)++;
|
||||||
|
;
|
||||||
segment[0] = '\n';
|
segment[0] = '\n';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -88,12 +94,14 @@ 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);
|
||||||
*p = ' '; // insert extra space
|
*p = ' '; // insert extra space
|
||||||
(*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 ((params.hostdot || params.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;
|
||||||
@ -151,9 +159,11 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
{
|
{
|
||||||
#define MAX_HDR_SIZE 2048
|
#define MAX_HDR_SIZE 2048
|
||||||
size_t padsize = hostpad > hsize ? hostpad - hsize : 0;
|
size_t padsize = hostpad > hsize ? hostpad - hsize : 0;
|
||||||
if (padsize>MAX_HDR_SIZE) padsize=MAX_HDR_SIZE;
|
if (padsize > MAX_HDR_SIZE)
|
||||||
|
padsize = MAX_HDR_SIZE;
|
||||||
// if next header would be too small then add extra padding to the current one
|
// if next header would be too small then add extra padding to the current one
|
||||||
if ((hostpad-padsize-hsize)<hsize) padsize+=hostpad-padsize-hsize;
|
if ((hostpad - padsize - hsize) < hsize)
|
||||||
|
padsize += hostpad - padsize - hsize;
|
||||||
snprintf(s, sizeof(s), "%c%04x: ", 'a' + rand() % ('z' - 'a' + 1), rand() & 0xFFFF);
|
snprintf(s, sizeof(s), "%c%04x: ", 'a' + rand() % ('z' - 'a' + 1), rand() & 0xFFFF);
|
||||||
memcpy(p, s, 7);
|
memcpy(p, s, 7);
|
||||||
p += 7;
|
p += 7;
|
||||||
@ -172,8 +182,10 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*split_pos = HttpPos(params.split_http_req, params.split_pos, segment, *size);
|
*split_pos = HttpPos(params.split_http_req, params.split_pos, segment, *size);
|
||||||
if (params.disorder_http) *split_flags |= SPLIT_FLAG_DISORDER;
|
if (params.disorder_http)
|
||||||
if (params.oob_http) *split_flags |= SPLIT_FLAG_OOB;
|
*split_flags |= SPLIT_FLAG_DISORDER;
|
||||||
|
if (params.oob_http)
|
||||||
|
*split_flags |= SPLIT_FLAG_OOB;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -184,7 +196,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
{
|
{
|
||||||
size_t tpos = 0, spos = 0;
|
size_t tpos = 0, spos = 0;
|
||||||
|
|
||||||
if (!ctrack->l7proto) ctrack->l7proto=TLS;
|
if (!ctrack->l7proto)
|
||||||
|
ctrack->l7proto = TLS;
|
||||||
|
|
||||||
VPRINT("packet contains TLS ClientHello\n");
|
VPRINT("packet contains TLS ClientHello\n");
|
||||||
// we need host only if hostlist is present
|
// we need host only if hostlist is present
|
||||||
@ -212,7 +225,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
if (l >= 2)
|
if (l >= 2)
|
||||||
{
|
{
|
||||||
// length is checked in IsTLSClientHello and cannot exceed buffer size
|
// length is checked in IsTLSClientHello and cannot exceed buffer size
|
||||||
if ((tpos-5)>=l) tpos=5+1;
|
if ((tpos - 5) >= l)
|
||||||
|
tpos = 5 + 1;
|
||||||
VPRINT("making 2 TLS records at pos %zu\n", tpos);
|
VPRINT("making 2 TLS records at pos %zu\n", tpos);
|
||||||
memmove(segment + tpos + 5, segment + tpos, *size - tpos);
|
memmove(segment + tpos + 5, segment + tpos, *size - tpos);
|
||||||
segment[tpos] = segment[0];
|
segment[tpos] = segment[0];
|
||||||
@ -222,7 +236,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
phton16(segment + 3, tpos - 5);
|
phton16(segment + 3, tpos - 5);
|
||||||
*size += 5;
|
*size += 5;
|
||||||
// split pos present and it is not before tlsrec split. increase split pos by tlsrec header size (5 bytes)
|
// split pos present and it is not before tlsrec split. increase split pos by tlsrec header size (5 bytes)
|
||||||
if (spos && spos>=tpos) spos+=5;
|
if (spos && spos >= tpos)
|
||||||
|
spos += 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -233,8 +248,10 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
*split_pos = spos;
|
*split_pos = spos;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER;
|
if (params.disorder_tls)
|
||||||
if (params.oob_tls) *split_flags |= SPLIT_FLAG_OOB;
|
*split_flags |= SPLIT_FLAG_DISORDER;
|
||||||
|
if (params.oob_tls)
|
||||||
|
*split_flags |= SPLIT_FLAG_OOB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (params.split_any_protocol && params.split_pos < *size)
|
else if (params.split_any_protocol && params.split_pos < *size)
|
||||||
@ -243,11 +260,14 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
|||||||
if (bHaveHost && bBypass && !bHostExcluded && *params.hostlist_auto_filename)
|
if (bHaveHost && bBypass && !bHostExcluded && *params.hostlist_auto_filename)
|
||||||
{
|
{
|
||||||
DBGPRINT("tamper_out put hostname : %s\n", Host);
|
DBGPRINT("tamper_out put hostname : %s\n", Host);
|
||||||
if (ctrack->hostname) free(ctrack->hostname);
|
if (ctrack->hostname)
|
||||||
|
free(ctrack->hostname);
|
||||||
ctrack->hostname = strdup(Host);
|
ctrack->hostname = strdup(Host);
|
||||||
}
|
}
|
||||||
if (params.disorder) *split_flags |= SPLIT_FLAG_DISORDER;
|
if (params.disorder)
|
||||||
if (params.oob) *split_flags |= SPLIT_FLAG_OOB;
|
*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(const char *hostname)
|
||||||
@ -343,11 +363,11 @@ 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->hostname);
|
||||||
}
|
}
|
||||||
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->hostname);
|
if (!bFail)
|
||||||
|
auto_hostlist_reset_fail_counter(ctrack->hostname);
|
||||||
}
|
}
|
||||||
ctrack->bTamperInCutoff = true;
|
ctrack->bTamperInCutoff = true;
|
||||||
}
|
}
|
||||||
@ -356,7 +376,8 @@ 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 (!*params.hostlist_auto_filename)
|
||||||
|
return;
|
||||||
|
|
||||||
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
||||||
|
|
||||||
@ -371,7 +392,8 @@ 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 (!*params.hostlist_auto_filename)
|
||||||
|
return;
|
||||||
|
|
||||||
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
||||||
|
|
||||||
|
@ -7,7 +7,12 @@
|
|||||||
#define SPLIT_FLAG_DISORDER 0x01
|
#define SPLIT_FLAG_DISORDER 0x01
|
||||||
#define SPLIT_FLAG_OOB 0x02
|
#define SPLIT_FLAG_OOB 0x02
|
||||||
|
|
||||||
typedef enum {UNKNOWN=0, HTTP, TLS} t_l7proto;
|
typedef enum
|
||||||
|
{
|
||||||
|
UNKNOWN = 0,
|
||||||
|
HTTP,
|
||||||
|
TLS
|
||||||
|
} t_l7proto;
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
// common state
|
// common state
|
||||||
|
127
tpws/tpws.c
127
tpws/tpws.c
@ -71,24 +71,26 @@ static void onusr2(int sig)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int8_t block_sigpipe(void)
|
static int8_t block_sigpipe(void)
|
||||||
{
|
{
|
||||||
sigset_t sigset;
|
sigset_t sigset;
|
||||||
memset(&sigset, 0, sizeof(sigset));
|
memset(&sigset, 0, sizeof(sigset));
|
||||||
|
|
||||||
// Get the old sigset, add SIGPIPE and update sigset
|
// Get the old sigset, add SIGPIPE and update sigset
|
||||||
if (sigprocmask(SIG_BLOCK, NULL, &sigset) == -1) {
|
if (sigprocmask(SIG_BLOCK, NULL, &sigset) == -1)
|
||||||
|
{
|
||||||
DLOG_PERROR("sigprocmask (get)");
|
DLOG_PERROR("sigprocmask (get)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigaddset(&sigset, SIGPIPE) == -1) {
|
if (sigaddset(&sigset, SIGPIPE) == -1)
|
||||||
|
{
|
||||||
DLOG_PERROR("sigaddset");
|
DLOG_PERROR("sigaddset");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigprocmask(SIG_BLOCK, &sigset, NULL) == -1) {
|
if (sigprocmask(SIG_BLOCK, &sigset, NULL) == -1)
|
||||||
|
{
|
||||||
DLOG_PERROR("sigprocmask (set)");
|
DLOG_PERROR("sigprocmask (set)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -96,7 +98,6 @@ static int8_t block_sigpipe(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool is_interface_online(const char *ifname)
|
static bool is_interface_online(const char *ifname)
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
@ -124,7 +125,6 @@ static int get_default_ttl(void)
|
|||||||
return ttl;
|
return ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void exithelp(void)
|
static void exithelp(void)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
@ -210,8 +210,7 @@ static void exithelp(void)
|
|||||||
#if defined(__linux__) || defined(__APPLE__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
DEFAULT_TCP_USER_TIMEOUT_LOCAL, DEFAULT_TCP_USER_TIMEOUT_REMOTE,
|
DEFAULT_TCP_USER_TIMEOUT_LOCAL, DEFAULT_TCP_USER_TIMEOUT_REMOTE,
|
||||||
#endif
|
#endif
|
||||||
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT
|
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT);
|
||||||
);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
static void cleanup_params(void)
|
static void cleanup_params(void)
|
||||||
@ -250,7 +249,6 @@ static void checkbind_clean(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void save_default_ttl(void)
|
void save_default_ttl(void)
|
||||||
{
|
{
|
||||||
if (!params.ttl_default)
|
if (!params.ttl_default)
|
||||||
@ -258,7 +256,7 @@ void save_default_ttl(void)
|
|||||||
params.ttl_default = get_default_ttl();
|
params.ttl_default = get_default_ttl();
|
||||||
if (!params.ttl_default)
|
if (!params.ttl_default)
|
||||||
{
|
{
|
||||||
DLOG_ERR("could not get default ttl\n");
|
DLOG_ERR("could not get default TTL\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,7 +283,6 @@ bool parse_tlspos(const char *s, enum tlspos *pos)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void parse_params(int argc, char *argv[])
|
void parse_params(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
@ -386,11 +383,11 @@ void parse_params(int argc, char *argv[])
|
|||||||
#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
|
||||||
{ NULL,0,NULL,0 }
|
{NULL, 0, NULL, 0}};
|
||||||
};
|
|
||||||
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
|
||||||
{
|
{
|
||||||
if (v) exithelp_clean();
|
if (v)
|
||||||
|
exithelp_clean();
|
||||||
switch (option_index)
|
switch (option_index)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -575,8 +572,10 @@ void parse_params(int argc, char *argv[])
|
|||||||
case 27: /* disorder */
|
case 27: /* disorder */
|
||||||
if (optarg)
|
if (optarg)
|
||||||
{
|
{
|
||||||
if (!strcmp(optarg,"http")) params.disorder_http=true;
|
if (!strcmp(optarg, "http"))
|
||||||
else if (!strcmp(optarg,"tls")) params.disorder_tls=true;
|
params.disorder_http = true;
|
||||||
|
else if (!strcmp(optarg, "tls"))
|
||||||
|
params.disorder_tls = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for disorder\n");
|
DLOG_ERR("Invalid argument for disorder\n");
|
||||||
@ -590,8 +589,10 @@ void parse_params(int argc, char *argv[])
|
|||||||
case 28: /* oob */
|
case 28: /* oob */
|
||||||
if (optarg)
|
if (optarg)
|
||||||
{
|
{
|
||||||
if (!strcmp(optarg,"http")) params.oob_http=true;
|
if (!strcmp(optarg, "http"))
|
||||||
else if (!strcmp(optarg,"tls")) params.oob_tls=true;
|
params.oob_http = true;
|
||||||
|
else if (!strcmp(optarg, "tls"))
|
||||||
|
params.oob_tls = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for oob\n");
|
DLOG_ERR("Invalid argument for oob\n");
|
||||||
@ -605,13 +606,15 @@ void parse_params(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
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)
|
||||||
|
params.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
|
||||||
|
params.oob_byte = (uint8_t)bt;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 30: /* methodspace */
|
case 30: /* methodspace */
|
||||||
@ -746,12 +749,14 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
if (params.droproot && chown(params.debug_logfile, params.uid, -1))
|
if (params.droproot && chown(params.debug_logfile, params.uid, -1))
|
||||||
fprintf(stderr, "could not chown %s. log file may not be writable after privilege drop\n", params.debug_logfile);
|
fprintf(stderr, "could not chown %s. log file may not be writable after privilege drop\n", params.debug_logfile);
|
||||||
if (!params.debug) params.debug = 1;
|
if (!params.debug)
|
||||||
|
params.debug = 1;
|
||||||
params.debug_target = LOG_TARGET_FILE;
|
params.debug_target = LOG_TARGET_FILE;
|
||||||
}
|
}
|
||||||
else if (!strcmp(optarg, "syslog"))
|
else if (!strcmp(optarg, "syslog"))
|
||||||
{
|
{
|
||||||
if (!params.debug) params.debug = 1;
|
if (!params.debug)
|
||||||
|
params.debug = 1;
|
||||||
params.debug_target = LOG_TARGET_SYSLOG;
|
params.debug_target = LOG_TARGET_SYSLOG;
|
||||||
openlog("tpws", LOG_PID, LOG_USER);
|
openlog("tpws", LOG_PID, LOG_USER);
|
||||||
}
|
}
|
||||||
@ -844,7 +849,8 @@ void parse_params(int argc, char *argv[])
|
|||||||
case 55: /* connect-bind-addr */
|
case 55: /* connect-bind-addr */
|
||||||
{
|
{
|
||||||
char *p = strchr(optarg, '%');
|
char *p = strchr(optarg, '%');
|
||||||
if (p) *p++=0;
|
if (p)
|
||||||
|
*p++ = 0;
|
||||||
if (inet_pton(AF_INET, optarg, ¶ms.connect_bind4.sin_addr))
|
if (inet_pton(AF_INET, optarg, ¶ms.connect_bind4.sin_addr))
|
||||||
{
|
{
|
||||||
params.connect_bind4.sin_family = AF_INET;
|
params.connect_bind4.sin_family = AF_INET;
|
||||||
@ -858,7 +864,6 @@ void parse_params(int argc, char *argv[])
|
|||||||
strncpy(params.connect_bind6_ifname, p, sizeof(params.connect_bind6_ifname));
|
strncpy(params.connect_bind6_ifname, p, sizeof(params.connect_bind6_ifname));
|
||||||
params.connect_bind6_ifname[sizeof(params.connect_bind6_ifname) - 1] = 0;
|
params.connect_bind6_ifname[sizeof(params.connect_bind6_ifname) - 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -930,17 +935,22 @@ void parse_params(int argc, char *argv[])
|
|||||||
DLOG_ERR("Cannot split with --skip-nodelay\n");
|
DLOG_ERR("Cannot split with --skip-nodelay\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
if (!params.resolver_threads) params.resolver_threads = 5 + params.maxconn/50;
|
if (!params.resolver_threads)
|
||||||
if (params.split_tls==tlspos_none && params.split_pos) params.split_tls=tlspos_pos;
|
params.resolver_threads = 5 + params.maxconn / 50;
|
||||||
if (params.split_http_req==httpreqpos_none && params.split_pos) params.split_http_req=httpreqpos_pos;
|
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);
|
if (*params.hostlist_auto_filename)
|
||||||
|
params.hostlist_auto_mod_time = file_mod_time(params.hostlist_auto_filename);
|
||||||
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 (*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");
|
||||||
@ -948,7 +958,6 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool find_listen_addr(struct sockaddr_storage *salisten, const char *bindiface, bool bind_if6, enum bindll bindll, int *if_index)
|
static bool find_listen_addr(struct sockaddr_storage *salisten, const char *bindiface, bool bind_if6, enum bindll bindll, int *if_index)
|
||||||
{
|
{
|
||||||
struct ifaddrs *addrs, *a;
|
struct ifaddrs *addrs, *a;
|
||||||
@ -975,21 +984,19 @@ static bool find_listen_addr(struct sockaddr_storage *salisten, const char *bind
|
|||||||
found = true;
|
found = true;
|
||||||
goto ex;
|
goto ex;
|
||||||
}
|
}
|
||||||
// ipv6 links locals are fe80::/10
|
// IPv6 links locals are fe80::/10
|
||||||
else if (a->ifa_addr->sa_family==AF_INET6
|
else if (a->ifa_addr->sa_family == AF_INET6 &&
|
||||||
&&
|
|
||||||
((!*bindiface && (bindll == prefer || bindll == force)) ||
|
((!*bindiface && (bindll == prefer || bindll == force)) ||
|
||||||
(*bindiface && bind_if6 && !strcmp(a->ifa_name, bindiface)))
|
(*bindiface && bind_if6 && !strcmp(a->ifa_name, bindiface))) &&
|
||||||
&&
|
|
||||||
((bindll == force && is_linklocal((struct sockaddr_in6 *)a->ifa_addr)) ||
|
((bindll == force && is_linklocal((struct sockaddr_in6 *)a->ifa_addr)) ||
|
||||||
(bindll == prefer && ((pass == 0 && is_linklocal((struct sockaddr_in6 *)a->ifa_addr)) || (pass == 1 && is_private6((struct sockaddr_in6 *)a->ifa_addr)) || pass == 2)) ||
|
(bindll == prefer && ((pass == 0 && is_linklocal((struct sockaddr_in6 *)a->ifa_addr)) || (pass == 1 && is_private6((struct sockaddr_in6 *)a->ifa_addr)) || pass == 2)) ||
|
||||||
(bindll == no && ((pass == 0 && is_private6((struct sockaddr_in6 *)a->ifa_addr)) || (pass == 1 && !is_linklocal((struct sockaddr_in6 *)a->ifa_addr)))) ||
|
(bindll == no && ((pass == 0 && is_private6((struct sockaddr_in6 *)a->ifa_addr)) || (pass == 1 && !is_linklocal((struct sockaddr_in6 *)a->ifa_addr)))) ||
|
||||||
(bindll==unwanted && ((pass==0 && is_private6((struct sockaddr_in6*)a->ifa_addr)) || (pass==1 && !is_linklocal((struct sockaddr_in6*)a->ifa_addr)) || pass==2)))
|
(bindll == unwanted && ((pass == 0 && is_private6((struct sockaddr_in6 *)a->ifa_addr)) || (pass == 1 && !is_linklocal((struct sockaddr_in6 *)a->ifa_addr)) || pass == 2))))
|
||||||
)
|
|
||||||
{
|
{
|
||||||
salisten->ss_family = AF_INET6;
|
salisten->ss_family = AF_INET6;
|
||||||
memcpy(&((struct sockaddr_in6 *)salisten)->sin6_addr, &((struct sockaddr_in6 *)a->ifa_addr)->sin6_addr, sizeof(struct in6_addr));
|
memcpy(&((struct sockaddr_in6 *)salisten)->sin6_addr, &((struct sockaddr_in6 *)a->ifa_addr)->sin6_addr, sizeof(struct in6_addr));
|
||||||
if (if_index) *if_index = if_nametoindex(a->ifa_name);
|
if (if_index)
|
||||||
|
*if_index = if_nametoindex(a->ifa_name);
|
||||||
found = true;
|
found = true;
|
||||||
goto ex;
|
goto ex;
|
||||||
}
|
}
|
||||||
@ -1012,7 +1019,8 @@ static bool read_system_maxfiles(rlim_t *maxfile)
|
|||||||
return false;
|
return false;
|
||||||
n = fscanf(F, "%ju", &um);
|
n = fscanf(F, "%ju", &um);
|
||||||
fclose(F);
|
fclose(F);
|
||||||
if (!n) return false;
|
if (!n)
|
||||||
|
return false;
|
||||||
*maxfile = (rlim_t)um;
|
*maxfile = (rlim_t)um;
|
||||||
return true;
|
return true;
|
||||||
#elif defined(BSD)
|
#elif defined(BSD)
|
||||||
@ -1083,7 +1091,8 @@ static bool set_ulimit(void)
|
|||||||
|
|
||||||
struct rlimit rlim = {fdmax, fdmax};
|
struct rlimit rlim = {fdmax, fdmax};
|
||||||
n = setrlimit(RLIMIT_NOFILE, &rlim);
|
n = setrlimit(RLIMIT_NOFILE, &rlim);
|
||||||
if (n==-1) DLOG_PERROR("setrlimit");
|
if (n == -1)
|
||||||
|
DLOG_PERROR("setrlimit");
|
||||||
return n != -1;
|
return n != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1104,7 +1113,8 @@ int main(int argc, char *argv[])
|
|||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
parse_params(argc, argv);
|
parse_params(argc, argv);
|
||||||
|
|
||||||
if (params.daemon) daemonize();
|
if (params.daemon)
|
||||||
|
daemonize();
|
||||||
|
|
||||||
if (*params.pidfile && !writepid(params.pidfile))
|
if (*params.pidfile && !writepid(params.pidfile))
|
||||||
{
|
{
|
||||||
@ -1113,7 +1123,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(&list, 0, sizeof(list));
|
memset(&list, 0, sizeof(list));
|
||||||
for(i=0;i<=params.binds_last;i++) listen_fd[i]=-1;
|
for (i = 0; i <= params.binds_last; i++)
|
||||||
|
listen_fd[i] = -1;
|
||||||
|
|
||||||
for (i = 0; i <= params.binds_last; i++)
|
for (i = 0; i <= params.binds_last; i++)
|
||||||
{
|
{
|
||||||
@ -1133,8 +1144,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
sleep(1);
|
sleep(1);
|
||||||
sec++;
|
sec++;
|
||||||
}
|
} while (!is_interface_online(params.binds[i].bindiface) && sec < params.binds[i].bind_wait_ifup);
|
||||||
while (!is_interface_online(params.binds[i].bindiface) && sec<params.binds[i].bind_wait_ifup);
|
|
||||||
if (sec >= params.binds[i].bind_wait_ifup)
|
if (sec >= params.binds[i].bind_wait_ifup)
|
||||||
{
|
{
|
||||||
DLOG_CONDUP("wait timed out\n");
|
DLOG_CONDUP("wait timed out\n");
|
||||||
@ -1182,25 +1192,25 @@ int main(int argc, char *argv[])
|
|||||||
if (params.binds[i].bindll == prefer)
|
if (params.binds[i].bindll == prefer)
|
||||||
DLOG_CONDUP("during the first %d second(s) accepting only link locals...\n", params.binds[i].bind_wait_ip_ll);
|
DLOG_CONDUP("during the first %d second(s) accepting only link locals...\n", params.binds[i].bind_wait_ip_ll);
|
||||||
else if (params.binds[i].bindll == unwanted)
|
else if (params.binds[i].bindll == unwanted)
|
||||||
DLOG_CONDUP("during the first %d second(s) accepting only ipv6 globals...\n", params.binds[i].bind_wait_ip_ll);
|
DLOG_CONDUP("during the first %d second(s) accepting only IPv6 globals...\n", params.binds[i].bind_wait_ip_ll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
// allow, no, prefer, force
|
// allow, no, prefer, force
|
||||||
bindll_1 = (params.binds[i].bindll==prefer && sec<params.binds[i].bind_wait_ip_ll) ? force :
|
bindll_1 = (params.binds[i].bindll == prefer && sec < params.binds[i].bind_wait_ip_ll) ? force : (params.binds[i].bindll == unwanted && sec < params.binds[i].bind_wait_ip_ll) ? no
|
||||||
(params.binds[i].bindll==unwanted && sec<params.binds[i].bind_wait_ip_ll) ? no :
|
: params.binds[i].bindll;
|
||||||
params.binds[i].bindll;
|
|
||||||
if (sec && sec == params.binds[i].bind_wait_ip_ll)
|
if (sec && sec == params.binds[i].bind_wait_ip_ll)
|
||||||
{
|
{
|
||||||
if (params.binds[i].bindll == prefer)
|
if (params.binds[i].bindll == prefer)
|
||||||
DLOG_CONDUP("link local address wait timeout. now accepting globals\n");
|
DLOG_CONDUP("link local address wait timeout. now accepting globals\n");
|
||||||
else if (params.binds[i].bindll == unwanted)
|
else if (params.binds[i].bindll == unwanted)
|
||||||
DLOG_CONDUP("global ipv6 address wait timeout. now accepting link locals\n");
|
DLOG_CONDUP("global IPv6 address wait timeout. now accepting link locals\n");
|
||||||
}
|
}
|
||||||
found = find_listen_addr(&list[i].salisten, params.binds[i].bindiface, params.binds[i].bind_if6, bindll_1, &if_index);
|
found = find_listen_addr(&list[i].salisten, params.binds[i].bindiface, params.binds[i].bind_if6, bindll_1, &if_index);
|
||||||
if (found) break;
|
if (found)
|
||||||
|
break;
|
||||||
|
|
||||||
if (sec >= params.binds[i].bind_wait_ip)
|
if (sec >= params.binds[i].bind_wait_ip)
|
||||||
break;
|
break;
|
||||||
@ -1258,7 +1268,8 @@ int main(int argc, char *argv[])
|
|||||||
VPRINT("Binding %d to %s\n", i, ip_port);
|
VPRINT("Binding %d to %s\n", i, ip_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((listen_fd[i] = socket(list[i].salisten.ss_family, SOCK_STREAM, 0)) == -1) {
|
if ((listen_fd[i] = socket(list[i].salisten.ss_family, SOCK_STREAM, 0)) == -1)
|
||||||
|
{
|
||||||
DLOG_PERROR("socket");
|
DLOG_PERROR("socket");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
@ -1318,7 +1329,7 @@ int main(int argc, char *argv[])
|
|||||||
// in linux strange behaviour was observed
|
// in linux strange behaviour was observed
|
||||||
// just after ifup and address assignment there's short window when bind() can't bind to addresses got from getifaddrs()
|
// just after ifup and address assignment there's short window when bind() can't bind to addresses got from getifaddrs()
|
||||||
// it does not happen to transparent sockets because they can bind to any non-existend ip
|
// it does not happen to transparent sockets because they can bind to any non-existend ip
|
||||||
// also only ipv6 seem to be buggy this way
|
// also only IPv6 seem to be buggy this way
|
||||||
if (errno == EADDRNOTAVAIL && params.proxy_type != CONN_TYPE_TRANSPARENT && list[i].bind_wait_ip_left)
|
if (errno == EADDRNOTAVAIL && params.proxy_type != CONN_TYPE_TRANSPARENT && list[i].bind_wait_ip_left)
|
||||||
{
|
{
|
||||||
if (!bBindBug)
|
if (!bBindBug)
|
||||||
@ -1352,13 +1363,15 @@ int main(int argc, char *argv[])
|
|||||||
// splice() causes the process to receive the SIGPIPE-signal if one part (for
|
// splice() causes the process to receive the SIGPIPE-signal if one part (for
|
||||||
// example a socket) is closed during splice(). I would rather have splice()
|
// example a socket) is closed during splice(). I would rather have splice()
|
||||||
// fail and return -1, so blocking SIGPIPE.
|
// fail and return -1, so blocking SIGPIPE.
|
||||||
if (block_sigpipe() == -1) {
|
if (block_sigpipe() == -1)
|
||||||
|
{
|
||||||
DLOG_ERR("Could not block SIGPIPE signal\n");
|
DLOG_ERR("Could not block SIGPIPE signal\n");
|
||||||
goto exiterr;
|
goto exiterr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLOG_CONDUP(params.proxy_type==CONN_TYPE_SOCKS ? "socks mode\n" : "transparent proxy mode\n");
|
DLOG_CONDUP(params.proxy_type == CONN_TYPE_SOCKS ? "SOCKS mode\n" : "transparent proxy mode\n");
|
||||||
if (!params.tamper) DLOG_CONDUP("TCP proxy mode (no tampering)\n");
|
if (!params.tamper)
|
||||||
|
DLOG_CONDUP("TCP proxy mode (no tampering)\n");
|
||||||
|
|
||||||
signal(SIGHUP, onhup);
|
signal(SIGHUP, onhup);
|
||||||
signal(SIGUSR2, onusr2);
|
signal(SIGUSR2, onusr2);
|
||||||
@ -1369,7 +1382,9 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
exiterr:
|
exiterr:
|
||||||
redir_close();
|
redir_close();
|
||||||
for(i=0;i<=params.binds_last;i++) if (listen_fd[i]!=-1) close(listen_fd[i]);
|
for (i = 0; i <= params.binds_last; i++)
|
||||||
|
if (listen_fd[i] != -1)
|
||||||
|
close(listen_fd[i]);
|
||||||
cleanup_params();
|
cleanup_params();
|
||||||
return exit_v;
|
return exit_v;
|
||||||
}
|
}
|
||||||
|
234
tpws/tpws_conn.c
234
tpws/tpws_conn.c
@ -24,7 +24,6 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "hostlist.h"
|
#include "hostlist.h"
|
||||||
|
|
||||||
|
|
||||||
// keep separate legs counter. counting every time thousands of legs can consume cpu
|
// keep separate legs counter. counting every time thousands of legs can consume cpu
|
||||||
static int legs_local, legs_remote;
|
static int legs_local, legs_remote;
|
||||||
/*
|
/*
|
||||||
@ -43,7 +42,6 @@ static void print_legs(void)
|
|||||||
VPRINT("Legs : local:%d remote:%d\n", legs_local, legs_remote);
|
VPRINT("Legs : local:%d remote:%d\n", legs_local, legs_remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool socks5_send_rep(int fd, uint8_t rep)
|
static bool socks5_send_rep(int fd, uint8_t rep)
|
||||||
{
|
{
|
||||||
s5_rep s5rep;
|
s5_rep s5rep;
|
||||||
@ -59,14 +57,18 @@ static bool socks5_send_rep_errno(int fd,int errn)
|
|||||||
switch (errn)
|
switch (errn)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
rep=S5_REP_OK; break;
|
rep = S5_REP_OK;
|
||||||
|
break;
|
||||||
case ECONNREFUSED:
|
case ECONNREFUSED:
|
||||||
rep=S5_REP_CONN_REFUSED; break;
|
rep = S5_REP_CONN_REFUSED;
|
||||||
|
break;
|
||||||
case ENETUNREACH:
|
case ENETUNREACH:
|
||||||
rep=S5_REP_NETWORK_UNREACHABLE; break;
|
rep = S5_REP_NETWORK_UNREACHABLE;
|
||||||
|
break;
|
||||||
case ETIMEDOUT:
|
case ETIMEDOUT:
|
||||||
case EHOSTUNREACH:
|
case EHOSTUNREACH:
|
||||||
rep=S5_REP_HOST_UNREACHABLE; break;
|
rep = S5_REP_HOST_UNREACHABLE;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
rep = S5_REP_GENERAL_FAILURE;
|
rep = S5_REP_GENERAL_FAILURE;
|
||||||
}
|
}
|
||||||
@ -92,7 +94,6 @@ static bool socks_send_rep_errno(uint8_t ver, int fd, int errn)
|
|||||||
return ver == 5 ? socks5_send_rep_errno(fd, errn) : socks4_send_rep_errno(fd, errn);
|
return ver == 5 ? socks5_send_rep_errno(fd, errn) : socks4_send_rep_errno(fd, errn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ssize_t send_with_ttl(int fd, const void *buf, size_t len, int flags, int ttl)
|
ssize_t send_with_ttl(int fd, const void *buf, size_t len, int flags, int ttl)
|
||||||
{
|
{
|
||||||
ssize_t wr;
|
ssize_t wr;
|
||||||
@ -101,21 +102,20 @@ ssize_t send_with_ttl(int fd, const void *buf, size_t len, int flags, int ttl)
|
|||||||
{
|
{
|
||||||
DBGPRINT("send_with_ttl %d fd=%d\n", ttl, fd);
|
DBGPRINT("send_with_ttl %d fd=%d\n", ttl, fd);
|
||||||
if (!set_ttl_hl(fd, ttl))
|
if (!set_ttl_hl(fd, ttl))
|
||||||
//DLOG_ERR("could not set ttl %d to fd=%d\n",ttl,fd);
|
// DLOG_ERR("could not set TTL %d to fd=%d\n",ttl,fd);
|
||||||
DLOG_ERR("could not set ttl %d to fd=%d\n",ttl,fd);
|
DLOG_ERR("could not set TTL %d to fd=%d\n", ttl, fd);
|
||||||
}
|
}
|
||||||
wr = send(fd, buf, len, flags);
|
wr = send(fd, buf, len, flags);
|
||||||
if (ttl)
|
if (ttl)
|
||||||
{
|
{
|
||||||
int e = errno;
|
int e = errno;
|
||||||
if (!set_ttl_hl(fd, params.ttl_default))
|
if (!set_ttl_hl(fd, params.ttl_default))
|
||||||
DLOG_ERR("could not set ttl %d to fd=%d\n",params.ttl_default,fd);
|
DLOG_ERR("could not set TTL %d to fd=%d\n", params.ttl_default, fd);
|
||||||
errno = e;
|
errno = e;
|
||||||
}
|
}
|
||||||
return wr;
|
return wr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool send_buffer_create(send_buffer_t *sb, const void *data, size_t len, size_t extra_bytes, int flags, int ttl)
|
static bool send_buffer_create(send_buffer_t *sb, const void *data, size_t len, size_t extra_bytes, int flags, int ttl)
|
||||||
{
|
{
|
||||||
if (sb->data)
|
if (sb->data)
|
||||||
@ -129,7 +129,8 @@ static bool send_buffer_create(send_buffer_t *sb, const void *data, size_t len,
|
|||||||
DBGPRINT("send_buffer_create failed\n");
|
DBGPRINT("send_buffer_create failed\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (data) memcpy(sb->data,data,len);
|
if (data)
|
||||||
|
memcpy(sb->data, data, len);
|
||||||
sb->len = len;
|
sb->len = len;
|
||||||
sb->pos = 0;
|
sb->pos = 0;
|
||||||
sb->ttl = ttl;
|
sb->ttl = ttl;
|
||||||
@ -197,7 +198,8 @@ static ssize_t send_buffer_send(send_buffer_t *sb, int fd)
|
|||||||
send_buffer_free(sb);
|
send_buffer_free(sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (wr<0 && errno==EAGAIN) wr=0;
|
else if (wr < 0 && errno == EAGAIN)
|
||||||
|
wr = 0;
|
||||||
|
|
||||||
return wr;
|
return wr;
|
||||||
}
|
}
|
||||||
@ -213,7 +215,8 @@ static ssize_t send_buffers_send(send_buffer_t *sb_array, int count, int fd, siz
|
|||||||
DBGPRINT("send_buffers_send(%d) wr=%zd err=%d\n", i, wr, errno);
|
DBGPRINT("send_buffers_send(%d) wr=%zd err=%d\n", i, wr, errno);
|
||||||
if (wr < 0)
|
if (wr < 0)
|
||||||
{
|
{
|
||||||
if (real_wr) *real_wr = twr;
|
if (real_wr)
|
||||||
|
*real_wr = twr;
|
||||||
return wr; // send error
|
return wr; // send error
|
||||||
}
|
}
|
||||||
twr += wr;
|
twr += wr;
|
||||||
@ -221,7 +224,8 @@ static ssize_t send_buffers_send(send_buffer_t *sb_array, int count, int fd, siz
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (real_wr) *real_wr = twr;
|
if (real_wr)
|
||||||
|
*real_wr = twr;
|
||||||
return twr;
|
return twr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +281,8 @@ static ssize_t send_or_buffer(send_buffer_t *sb, int fd, const void *buf, size_t
|
|||||||
if (len)
|
if (len)
|
||||||
{
|
{
|
||||||
wr = send_with_ttl(fd, buf, len, flags, ttl);
|
wr = send_with_ttl(fd, buf, len, flags, ttl);
|
||||||
if (wr<0 && errno==EAGAIN) wr=0;
|
if (wr < 0 && errno == EAGAIN)
|
||||||
|
wr = 0;
|
||||||
if (wr >= 0 && wr < len)
|
if (wr >= 0 && wr < len)
|
||||||
{
|
{
|
||||||
if (!send_buffer_create(sb, buf + wr, len - wr, 0, flags, ttl))
|
if (!send_buffer_create(sb, buf + wr, len - wr, 0, flags, ttl))
|
||||||
@ -325,7 +330,8 @@ static bool proxy_remote_conn_ack(tproxy_conn_t *conn, int sock_err)
|
|||||||
{
|
{
|
||||||
// if proxy mode acknowledge connection request
|
// if proxy mode acknowledge connection request
|
||||||
// conn = remote. conn->partner = local
|
// conn = remote. conn->partner = local
|
||||||
if (!conn->remote || !conn_partner_alive(conn)) return false;
|
if (!conn->remote || !conn_partner_alive(conn))
|
||||||
|
return false;
|
||||||
bool bres = true;
|
bool bres = true;
|
||||||
switch (conn->partner->conn_type)
|
switch (conn->partner->conn_type)
|
||||||
{
|
{
|
||||||
@ -334,7 +340,7 @@ static bool proxy_remote_conn_ack(tproxy_conn_t *conn, int sock_err)
|
|||||||
{
|
{
|
||||||
conn->partner->socks_state = S_TCP;
|
conn->partner->socks_state = S_TCP;
|
||||||
bres = socks_send_rep_errno(conn->partner->socks_ver, conn->partner->fd, sock_err);
|
bres = socks_send_rep_errno(conn->partner->socks_ver, conn->partner->fd, sock_err);
|
||||||
DBGPRINT("socks connection acknowledgement. bres=%d remote_errn=%d remote_fd=%d local_fd=%d\n",bres,sock_err,conn->fd,conn->partner->fd);
|
DBGPRINT("SOCKS connection acknowledgement. bres=%d remote_errn=%d remote_fd=%d local_fd=%d\n", bres, sock_err, conn->fd, conn->partner->fd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -364,22 +370,20 @@ static void set_user_timeout(int fd, int timeout)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Creates 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, bool bApplyConnectionFooling)
|
||||||
{
|
{
|
||||||
int remote_fd = 0, yes = 1, no = 0;
|
int remote_fd = 0, yes = 1, no = 0;
|
||||||
|
|
||||||
|
|
||||||
if ((remote_fd = socket(remote_addr->sa_family, SOCK_STREAM, 0)) < 0)
|
if ((remote_fd = socket(remote_addr->sa_family, SOCK_STREAM, 0)) < 0)
|
||||||
{
|
{
|
||||||
DLOG_PERROR("socket (connect_remote)");
|
DLOG_PERROR("socket (connect_remote)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Use NONBLOCK to avoid slow connects affecting the performance of other connections
|
// Use NONBLOCK to avoid slow connects affecting the performance of other connections
|
||||||
// separate fcntl call to comply with macos
|
// separate fcntl call to comply with macOS
|
||||||
if (fcntl(remote_fd, F_SETFL, O_NONBLOCK) < 0)
|
if (fcntl(remote_fd, F_SETFL, O_NONBLOCK) < 0)
|
||||||
{
|
{
|
||||||
DLOG_PERROR("socket set O_NONBLOCK (connect_remote)");
|
DLOG_PERROR("socket set O_NONBLOCK (connect_remote)");
|
||||||
@ -472,21 +476,25 @@ static int connect_remote(const struct sockaddr *remote_addr, bool bApplyConnect
|
|||||||
return remote_fd;
|
return remote_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Free resources occupied by this connection
|
// Free resources occupied by this connection
|
||||||
static void free_conn(tproxy_conn_t *conn)
|
static void free_conn(tproxy_conn_t *conn)
|
||||||
{
|
{
|
||||||
if (!conn) return;
|
if (!conn)
|
||||||
if (conn->fd) close(conn->fd);
|
return;
|
||||||
|
if (conn->fd)
|
||||||
|
close(conn->fd);
|
||||||
if (conn->splice_pipe[0])
|
if (conn->splice_pipe[0])
|
||||||
{
|
{
|
||||||
close(conn->splice_pipe[0]);
|
close(conn->splice_pipe[0]);
|
||||||
close(conn->splice_pipe[1]);
|
close(conn->splice_pipe[1]);
|
||||||
}
|
}
|
||||||
conn_free_buffers(conn);
|
conn_free_buffers(conn);
|
||||||
if (conn->partner) conn->partner->partner=NULL;
|
if (conn->partner)
|
||||||
if (conn->track.hostname) free(conn->track.hostname);
|
conn->partner->partner = NULL;
|
||||||
if (conn->socks_ri) conn->socks_ri->ptr = NULL; // detach conn
|
if (conn->track.hostname)
|
||||||
|
free(conn->track.hostname);
|
||||||
|
if (conn->socks_ri)
|
||||||
|
conn->socks_ri->ptr = NULL; // detach conn
|
||||||
free(conn);
|
free(conn);
|
||||||
}
|
}
|
||||||
static tproxy_conn_t *new_conn(int fd, bool remote)
|
static tproxy_conn_t *new_conn(int fd, bool remote)
|
||||||
@ -616,7 +624,8 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
|
|||||||
|
|
||||||
if (!(conn = new_conn(local_fd, false)))
|
if (!(conn = new_conn(local_fd, false)))
|
||||||
{
|
{
|
||||||
if (remote_fd) close(remote_fd);
|
if (remote_fd)
|
||||||
|
close(remote_fd);
|
||||||
close(local_fd);
|
close(local_fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -647,8 +656,8 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
|
|||||||
|
|
||||||
// Transparent proxy mode :
|
// Transparent proxy mode :
|
||||||
// Local socket can be closed while waiting for connection attempt. I need
|
// Local socket can be closed while waiting for connection attempt. I need
|
||||||
// to detect this when waiting for connect() to complete. However, I dont
|
// to detect this when waiting for connect() to complete. However, I don't
|
||||||
// want to get EPOLLIN-events, as I dont want to receive any data before
|
// want to get EPOLLIN-events, as I don't want to receive any data before
|
||||||
// remote connection is established
|
// remote connection is established
|
||||||
// Proxy mode : I need to service proxy protocol
|
// Proxy mode : I need to service proxy protocol
|
||||||
// remote connection not started until proxy handshake is complete
|
// remote connection not started until proxy handshake is complete
|
||||||
@ -714,9 +723,6 @@ static bool check_connection_attempt(tproxy_conn_t *conn, int efd)
|
|||||||
return !errn;
|
return !errn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool epoll_set_flow_pair(tproxy_conn_t *conn)
|
static bool epoll_set_flow_pair(tproxy_conn_t *conn)
|
||||||
{
|
{
|
||||||
bool bHasUnsent = conn_has_unsent(conn);
|
bool bHasUnsent = conn_has_unsent(conn);
|
||||||
@ -747,8 +753,10 @@ static bool handle_unsent(tproxy_conn_t *conn)
|
|||||||
DBGPRINT("splice unsent=%zd wr=%zd err=%d\n", conn->wr_unsent, wr, errno);
|
DBGPRINT("splice unsent=%zd wr=%zd err=%d\n", conn->wr_unsent, wr, errno);
|
||||||
if (wr < 0)
|
if (wr < 0)
|
||||||
{
|
{
|
||||||
if (errno==EAGAIN) wr=0;
|
if (errno == EAGAIN)
|
||||||
else return false;
|
wr = 0;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
conn->twr += wr;
|
conn->twr += wr;
|
||||||
conn->wr_unsent -= wr;
|
conn->wr_unsent -= wr;
|
||||||
@ -758,7 +766,8 @@ static bool handle_unsent(tproxy_conn_t *conn)
|
|||||||
{
|
{
|
||||||
wr = conn_buffers_send(conn);
|
wr = conn_buffers_send(conn);
|
||||||
DBGPRINT("conn_buffers_send wr=%zd\n", wr);
|
DBGPRINT("conn_buffers_send wr=%zd\n", wr);
|
||||||
if (wr<0) return false;
|
if (wr < 0)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (!conn_has_unsent(conn) && conn_partner_alive(conn) && conn->partner->state == CONN_RDHUP)
|
if (!conn_has_unsent(conn) && conn_partner_alive(conn) && conn->partner->state == CONN_RDHUP)
|
||||||
{
|
{
|
||||||
@ -781,7 +790,6 @@ static bool handle_unsent(tproxy_conn_t *conn)
|
|||||||
return epoll_set_flow_pair(conn);
|
return epoll_set_flow_pair(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool proxy_mode_connect_remote(const struct sockaddr *sa, tproxy_conn_t *conn, struct tailhead *conn_list)
|
bool proxy_mode_connect_remote(const struct sockaddr *sa, tproxy_conn_t *conn, struct tailhead *conn_list)
|
||||||
{
|
{
|
||||||
int remote_fd;
|
int remote_fd;
|
||||||
@ -790,7 +798,7 @@ bool proxy_mode_connect_remote(const struct sockaddr *sa, tproxy_conn_t *conn, s
|
|||||||
{
|
{
|
||||||
char ip_port[48];
|
char ip_port[48];
|
||||||
ntop46_port(sa, ip_port, sizeof(ip_port));
|
ntop46_port(sa, 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 *)sa))
|
||||||
{
|
{
|
||||||
@ -850,7 +858,8 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
|
|||||||
// 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);
|
||||||
DBGPRINT("handle_proxy_mode rd=%zd\n", rd);
|
DBGPRINT("handle_proxy_mode rd=%zd\n", rd);
|
||||||
if (rd<1) return false; // hangup
|
if (rd < 1)
|
||||||
|
return false; // hangup
|
||||||
switch (conn->conn_type)
|
switch (conn->conn_type)
|
||||||
{
|
{
|
||||||
case CONN_TYPE_SOCKS:
|
case CONN_TYPE_SOCKS:
|
||||||
@ -858,9 +867,10 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
|
|||||||
{
|
{
|
||||||
case S_WAIT_HANDSHAKE:
|
case S_WAIT_HANDSHAKE:
|
||||||
DBGPRINT("S_WAIT_HANDSHAKE\n");
|
DBGPRINT("S_WAIT_HANDSHAKE\n");
|
||||||
if (buf[0] != 5 && buf[0] != 4) return false; // unknown socks version
|
if (buf[0] != 5 && buf[0] != 4)
|
||||||
|
return false; // unknown SOCKS version
|
||||||
conn->socks_ver = buf[0];
|
conn->socks_ver = buf[0];
|
||||||
DBGPRINT("socks version %u\n", conn->socks_ver);
|
DBGPRINT("SOCKS version %u\n", conn->socks_ver);
|
||||||
if (conn->socks_ver == 5)
|
if (conn->socks_ver == 5)
|
||||||
{
|
{
|
||||||
s5_handshake *m = (s5_handshake *)buf;
|
s5_handshake *m = (s5_handshake *)buf;
|
||||||
@ -873,10 +883,12 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
|
|||||||
DBGPRINT("socks5 proxy handshake invalid\n");
|
DBGPRINT("socks5 proxy handshake invalid\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (k=0;k<m->nmethods;k++) if (m->methods[k]==S5_AUTH_NONE) break;
|
for (k = 0; k < m->nmethods; k++)
|
||||||
|
if (m->methods[k] == S5_AUTH_NONE)
|
||||||
|
break;
|
||||||
if (k >= m->nmethods)
|
if (k >= m->nmethods)
|
||||||
{
|
{
|
||||||
DBGPRINT("socks5 client wants authentication but we dont support\n");
|
DBGPRINT("socks5 client wants authentication but we don't support\n");
|
||||||
ack.method = S5_AUTH_UNACCEPTABLE;
|
ack.method = S5_AUTH_UNACCEPTABLE;
|
||||||
wr = send(conn->fd, &ack, sizeof(ack), MSG_DONTWAIT);
|
wr = send(conn->fd, &ack, sizeof(ack), MSG_DONTWAIT);
|
||||||
return false;
|
return false;
|
||||||
@ -895,8 +907,8 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// socks4 does not have separate handshake phase. it starts with connect request
|
// SOCKS4 does not have separate handshake phase. it starts with connect request
|
||||||
// ipv6 and domain resolving are not supported
|
// v6 and domain resolving are not supported
|
||||||
s4_req *m = (s4_req *)buf;
|
s4_req *m = (s4_req *)buf;
|
||||||
if (!S4_REQ_HEADER_VALID(m, rd))
|
if (!S4_REQ_HEADER_VALID(m, rd))
|
||||||
{
|
{
|
||||||
@ -1004,19 +1016,18 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
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((struct sockaddr *)&ss, conn, conn_list);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case S_WAIT_RESOLVE:
|
case S_WAIT_RESOLVE:
|
||||||
DBGPRINT("socks received message while in S_WAIT_RESOLVE. hanging up\n");
|
DBGPRINT("SOCKS received message while in S_WAIT_RESOLVE. hanging up\n");
|
||||||
break;
|
break;
|
||||||
case S_WAIT_CONNECTION:
|
case S_WAIT_CONNECTION:
|
||||||
DBGPRINT("socks received message while in S_WAIT_CONNECTION. hanging up\n");
|
DBGPRINT("SOCKS received message while in S_WAIT_CONNECTION. hanging up\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DBGPRINT("socks received message while in an unexpected connection state\n");
|
DBGPRINT("SOCKS received message while in an unexpected connection state\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1036,7 +1047,8 @@ static bool resolve_complete(struct resolve_item *ri, struct tailhead *conn_list
|
|||||||
if (ri->ga_res)
|
if (ri->ga_res)
|
||||||
{
|
{
|
||||||
socks5_send_rep(conn->fd, S5_REP_HOST_UNREACHABLE);
|
socks5_send_rep(conn->fd, S5_REP_HOST_UNREACHABLE);
|
||||||
return false;;
|
return false;
|
||||||
|
;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1057,7 +1069,6 @@ static bool resolve_complete(struct resolve_item *ri, struct tailhead *conn_list
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 &&
|
return (params.tamper_start_n ? (conn->tnrd + 1) : conn->trd) >= params.tamper_start &&
|
||||||
@ -1084,7 +1095,8 @@ static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_
|
|||||||
params.tamper_start_n ? "n" : "", params.tamper_start,
|
params.tamper_start_n ? "n" : "", params.tamper_start,
|
||||||
params.tamper_cutoff_n ? "n" : "", params.tamper_cutoff,
|
params.tamper_cutoff_n ? "n" : "", params.tamper_cutoff,
|
||||||
in_range ? "IN RANGE" : "OUT OF RANGE");
|
in_range ? "IN RANGE" : "OUT OF RANGE");
|
||||||
if (in_range) tamper_out(&conn->track,segment,segment_buffer_size,segment_size,split_pos,split_flags);
|
if (in_range)
|
||||||
|
tamper_out(&conn->track, segment, segment_buffer_size, segment_size, split_pos, split_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1107,7 +1119,6 @@ static ssize_t send_or_buffer_oob(send_buffer_t *sb, int fd, uint8_t *buf, size_
|
|||||||
return wr;
|
return wr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define RD_BLOCK_SIZE 65536
|
#define RD_BLOCK_SIZE 65536
|
||||||
#define MAX_WASTE (1024 * 1024)
|
#define MAX_WASTE (1024 * 1024)
|
||||||
static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32_t evt)
|
static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32_t evt)
|
||||||
@ -1116,7 +1127,6 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
|||||||
ssize_t rd = 0, wr = 0;
|
ssize_t rd = 0, wr = 0;
|
||||||
size_t bs;
|
size_t bs;
|
||||||
|
|
||||||
|
|
||||||
DBGPRINT("+handle_epoll\n");
|
DBGPRINT("+handle_epoll\n");
|
||||||
|
|
||||||
if (!conn_in_tcp_mode(conn))
|
if (!conn_in_tcp_mode(conn))
|
||||||
@ -1169,7 +1179,8 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
|||||||
|
|
||||||
rd = splice(conn->fd, NULL, conn->partner->splice_pipe[1], NULL, SPLICE_LEN, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
|
rd = splice(conn->fd, NULL, conn->partner->splice_pipe[1], NULL, SPLICE_LEN, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
|
||||||
DBGPRINT("splice fd=%d remote=%d len=%d rd=%zd err=%d\n", conn->fd, conn->remote, SPLICE_LEN, rd, errno);
|
DBGPRINT("splice fd=%d remote=%d len=%d rd=%zd err=%d\n", conn->fd, conn->remote, SPLICE_LEN, rd, errno);
|
||||||
if (rd<0 && errno==EAGAIN) rd=0;
|
if (rd < 0 && errno == EAGAIN)
|
||||||
|
rd = 0;
|
||||||
if (rd > 0)
|
if (rd > 0)
|
||||||
{
|
{
|
||||||
conn->tnrd++;
|
conn->tnrd++;
|
||||||
@ -1177,7 +1188,8 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
|||||||
conn->partner->wr_unsent += rd;
|
conn->partner->wr_unsent += rd;
|
||||||
wr = splice(conn->partner->splice_pipe[0], NULL, conn->partner->fd, NULL, conn->partner->wr_unsent, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
|
wr = splice(conn->partner->splice_pipe[0], NULL, conn->partner->fd, NULL, conn->partner->wr_unsent, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
|
||||||
DBGPRINT("splice fd=%d remote=%d wr=%zd err=%d\n", conn->partner->fd, conn->partner->remote, wr, errno);
|
DBGPRINT("splice fd=%d remote=%d wr=%zd err=%d\n", conn->partner->fd, conn->partner->remote, wr, errno);
|
||||||
if (wr<0 && errno==EAGAIN) wr=0;
|
if (wr < 0 && errno == EAGAIN)
|
||||||
|
wr = 0;
|
||||||
if (wr > 0)
|
if (wr > 0)
|
||||||
{
|
{
|
||||||
conn->partner->wr_unsent -= wr;
|
conn->partner->wr_unsent -= wr;
|
||||||
@ -1193,7 +1205,8 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
|||||||
|
|
||||||
rd = recv(conn->fd, buf, RD_BLOCK_SIZE, MSG_DONTWAIT);
|
rd = recv(conn->fd, buf, RD_BLOCK_SIZE, MSG_DONTWAIT);
|
||||||
DBGPRINT("recv fd=%d rd=%zd err=%d\n", conn->fd, rd, errno);
|
DBGPRINT("recv fd=%d rd=%zd err=%d\n", conn->fd, rd, errno);
|
||||||
if (rd<0 && errno==EAGAIN) rd=0;
|
if (rd < 0 && errno == EAGAIN)
|
||||||
|
rd = 0;
|
||||||
if (rd > 0)
|
if (rd > 0)
|
||||||
{
|
{
|
||||||
size_t split_pos;
|
size_t split_pos;
|
||||||
@ -1218,16 +1231,19 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
|||||||
conn->partner->twr += wr;
|
conn->partner->twr += wr;
|
||||||
wr = send_or_buffer(conn->partner->wr_buf + 1, conn->partner->fd, buf + split_pos, bs - split_pos, 0, 0);
|
wr = send_or_buffer(conn->partner->wr_buf + 1, conn->partner->fd, buf + split_pos, bs - split_pos, 0, 0);
|
||||||
DBGPRINT("send_or_buffer(2) fd=%d wr=%zd err=%d\n", conn->partner->fd, wr, errno);
|
DBGPRINT("send_or_buffer(2) fd=%d wr=%zd err=%d\n", conn->partner->fd, wr, errno);
|
||||||
if (wr>0) conn->partner->twr += wr;
|
if (wr > 0)
|
||||||
|
conn->partner->twr += wr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
wr = send_or_buffer(conn->partner->wr_buf, conn->partner->fd, buf, bs, 0, 0);
|
wr = send_or_buffer(conn->partner->wr_buf, conn->partner->fd, buf, bs, 0, 0);
|
||||||
DBGPRINT("send_or_buffer(3) fd=%d wr=%zd err=%d\n", conn->partner->fd, wr, errno);
|
DBGPRINT("send_or_buffer(3) fd=%d wr=%zd err=%d\n", conn->partner->fd, wr, errno);
|
||||||
if (wr>0) conn->partner->twr += wr;
|
if (wr > 0)
|
||||||
|
conn->partner->twr += wr;
|
||||||
}
|
}
|
||||||
if (wr<0 && errno==ENOMEM) oom=true;
|
if (wr < 0 && errno == ENOMEM)
|
||||||
|
oom = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1236,7 +1252,8 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
|||||||
}
|
}
|
||||||
|
|
||||||
DBGPRINT("-handle_epoll rd=%zd wr=%zd\n", rd, wr);
|
DBGPRINT("-handle_epoll rd=%zd wr=%zd\n", rd, wr);
|
||||||
if (oom) DBGPRINT("handle_epoll: OUT_OF_MEMORY\n");
|
if (oom)
|
||||||
|
DBGPRINT("handle_epoll: OUT_OF_MEMORY\n");
|
||||||
|
|
||||||
// do not fail if partner fails.
|
// do not fail if partner fails.
|
||||||
// if partner fails there will be another epoll event with EPOLLHUP or EPOLLERR
|
// if partner fails there will be another epoll event with EPOLLHUP or EPOLLERR
|
||||||
@ -1255,7 +1272,10 @@ static bool remove_closed_connections(int efd, struct tailhead *close_list)
|
|||||||
epoll_del(conn);
|
epoll_del(conn);
|
||||||
VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) closed, connection removed. total_read=%" PRIu64 " total_write=%" PRIu64 " event_count=%u\n",
|
VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) closed, connection removed. total_read=%" PRIu64 " total_write=%" PRIu64 " event_count=%u\n",
|
||||||
conn->fd, conn->partner ? conn->partner->fd : 0, conn->remote, conn->trd, conn->twr, conn->event_count);
|
conn->fd, conn->partner ? conn->partner->fd : 0, conn->remote, conn->trd, conn->twr, conn->event_count);
|
||||||
if (conn->remote) legs_remote--; else legs_local--;
|
if (conn->remote)
|
||||||
|
legs_remote--;
|
||||||
|
else
|
||||||
|
legs_local--;
|
||||||
free_conn(conn);
|
free_conn(conn);
|
||||||
bRemoved = true;
|
bRemoved = true;
|
||||||
}
|
}
|
||||||
@ -1273,7 +1293,6 @@ static void close_tcp_conn(struct tailhead *conn_list, struct tailhead *close_li
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool read_all_and_buffer(tproxy_conn_t *conn, int buffer_number)
|
static bool read_all_and_buffer(tproxy_conn_t *conn, int buffer_number)
|
||||||
{
|
{
|
||||||
if (conn_partner_alive(conn))
|
if (conn_partner_alive(conn))
|
||||||
@ -1299,7 +1318,6 @@ static bool read_all_and_buffer(tproxy_conn_t *conn, int buffer_number)
|
|||||||
|
|
||||||
if (epoll_update_flow(conn->partner))
|
if (epoll_update_flow(conn->partner))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
send_buffer_free(conn->partner->wr_buf + buffer_number);
|
send_buffer_free(conn->partner->wr_buf + buffer_number);
|
||||||
}
|
}
|
||||||
@ -1308,7 +1326,6 @@ static bool read_all_and_buffer(tproxy_conn_t *conn, int buffer_number)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool conn_timed_out(tproxy_conn_t *conn)
|
static bool conn_timed_out(tproxy_conn_t *conn)
|
||||||
{
|
{
|
||||||
if (conn->orphan_since && conn->state == CONN_UNAVAILABLE)
|
if (conn->orphan_since && conn->state == CONN_UNAVAILABLE)
|
||||||
@ -1340,7 +1357,8 @@ static void conn_close_timed_out(struct tailhead *conn_list, struct tailhead *cl
|
|||||||
|
|
||||||
static void conn_close_both(struct tailhead *conn_list, struct tailhead *close_list, tproxy_conn_t *conn)
|
static void conn_close_both(struct tailhead *conn_list, struct tailhead *close_list, tproxy_conn_t *conn)
|
||||||
{
|
{
|
||||||
if (conn_partner_alive(conn)) close_tcp_conn(conn_list,close_list,conn->partner);
|
if (conn_partner_alive(conn))
|
||||||
|
close_tcp_conn(conn_list, close_list, conn->partner);
|
||||||
close_tcp_conn(conn_list, close_list, conn);
|
close_tcp_conn(conn_list, close_list, conn);
|
||||||
}
|
}
|
||||||
static void conn_close_with_partner_check(struct tailhead *conn_list, struct tailhead *close_list, tproxy_conn_t *conn)
|
static void conn_close_with_partner_check(struct tailhead *conn_list, struct tailhead *close_list, tproxy_conn_t *conn)
|
||||||
@ -1356,7 +1374,6 @@ static void conn_close_with_partner_check(struct tailhead *conn_list, struct tai
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool handle_resolve_pipe(tproxy_conn_t **conn, struct tailhead *conn_list, int fd)
|
static bool handle_resolve_pipe(tproxy_conn_t **conn, struct tailhead *conn_list, int fd)
|
||||||
{
|
{
|
||||||
ssize_t rd;
|
ssize_t rd;
|
||||||
@ -1377,7 +1394,8 @@ static bool handle_resolve_pipe(tproxy_conn_t **conn, struct tailhead *conn_list
|
|||||||
}
|
}
|
||||||
b = resolve_complete(ri, conn_list);
|
b = resolve_complete(ri, conn_list);
|
||||||
*conn = (tproxy_conn_t *)ri->ptr;
|
*conn = (tproxy_conn_t *)ri->ptr;
|
||||||
if (*conn) (*conn)->socks_ri = NULL;
|
if (*conn)
|
||||||
|
(*conn)->socks_ri = NULL;
|
||||||
free(ri);
|
free(ri);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
@ -1397,7 +1415,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
socklen_t accept_salen;
|
socklen_t accept_salen;
|
||||||
int resolve_pipe[2];
|
int resolve_pipe[2];
|
||||||
|
|
||||||
if (!listen_fd_ct) return -1;
|
if (!listen_fd_ct)
|
||||||
|
return -1;
|
||||||
|
|
||||||
resolve_pipe[0] = resolve_pipe[1] = 0;
|
resolve_pipe[0] = resolve_pipe[1] = 0;
|
||||||
|
|
||||||
@ -1406,7 +1425,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
TAILQ_INIT(&conn_list);
|
TAILQ_INIT(&conn_list);
|
||||||
TAILQ_INIT(&close_list);
|
TAILQ_INIT(&close_list);
|
||||||
|
|
||||||
if ((efd = epoll_create(1)) == -1) {
|
if ((efd = epoll_create(1)) == -1)
|
||||||
|
{
|
||||||
DLOG_PERROR("epoll_create");
|
DLOG_PERROR("epoll_create");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1425,7 +1445,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
listen_conn[sct].listener = true;
|
listen_conn[sct].listener = true;
|
||||||
listen_conn[sct].fd = listen_fd[sct];
|
listen_conn[sct].fd = listen_fd[sct];
|
||||||
ev.data.ptr = listen_conn + sct;
|
ev.data.ptr = listen_conn + sct;
|
||||||
if (epoll_ctl(efd, EPOLL_CTL_ADD, listen_conn[sct].fd, &ev) == -1) {
|
if (epoll_ctl(efd, EPOLL_CTL_ADD, listen_conn[sct].fd, &ev) == -1)
|
||||||
|
{
|
||||||
DLOG_PERROR("epoll_ctl (listen socket)");
|
DLOG_PERROR("epoll_ctl (listen socket)");
|
||||||
retval = -1;
|
retval = -1;
|
||||||
goto ex;
|
goto ex;
|
||||||
@ -1446,7 +1467,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
goto ex;
|
goto ex;
|
||||||
}
|
}
|
||||||
ev.data.ptr = NULL;
|
ev.data.ptr = NULL;
|
||||||
if (epoll_ctl(efd, EPOLL_CTL_ADD, resolve_pipe[0], &ev) == -1) {
|
if (epoll_ctl(efd, EPOLL_CTL_ADD, resolve_pipe[0], &ev) == -1)
|
||||||
|
{
|
||||||
DLOG_PERROR("epoll_ctl (listen socket)");
|
DLOG_PERROR("epoll_ctl (listen socket)");
|
||||||
retval = -1;
|
retval = -1;
|
||||||
goto ex;
|
goto ex;
|
||||||
@ -1466,7 +1488,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
|
|
||||||
if ((num_events = epoll_wait(efd, events, MAX_EPOLL_EVENTS, -1)) == -1)
|
if ((num_events = epoll_wait(efd, events, MAX_EPOLL_EVENTS, -1)) == -1)
|
||||||
{
|
{
|
||||||
if (errno == EINTR) continue; // system call was interrupted
|
if (errno == EINTR)
|
||||||
|
continue; // system call was interrupted
|
||||||
DLOG_PERROR("epoll_wait");
|
DLOG_PERROR("epoll_wait");
|
||||||
retval = -1;
|
retval = -1;
|
||||||
break;
|
break;
|
||||||
@ -1486,7 +1509,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
if (!handle_resolve_pipe(&conn, &conn_list, resolve_pipe[0]))
|
if (!handle_resolve_pipe(&conn, &conn_list, resolve_pipe[0]))
|
||||||
{
|
{
|
||||||
DBGPRINT("handle_resolve_pipe false\n");
|
DBGPRINT("handle_resolve_pipe false\n");
|
||||||
if (conn) close_tcp_conn(&conn_list,&close_list,conn);
|
if (conn)
|
||||||
|
close_tcp_conn(&conn_list, &close_list, conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -1499,7 +1523,7 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
accept_salen = sizeof(accept_sa);
|
accept_salen = sizeof(accept_sa);
|
||||||
// Accept new connection
|
// Accept new connection
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
// macos does not have accept4()
|
// macOS does not have accept4()
|
||||||
tmp_fd = accept(conn->fd, (struct sockaddr *)&accept_sa, &accept_salen);
|
tmp_fd = accept(conn->fd, (struct sockaddr *)&accept_sa, &accept_salen);
|
||||||
#else
|
#else
|
||||||
tmp_fd = accept4(conn->fd, (struct sockaddr *)&accept_sa, &accept_salen, SOCK_NONBLOCK);
|
tmp_fd = accept4(conn->fd, (struct sockaddr *)&accept_sa, &accept_salen, SOCK_NONBLOCK);
|
||||||
@ -1514,7 +1538,7 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
VPRINT("Too many local legs : %d\n", legs_local);
|
VPRINT("Too many local legs : %d\n", legs_local);
|
||||||
}
|
}
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
// separate fcntl call to comply with macos
|
// separate fcntl call to comply with macOS
|
||||||
else if (fcntl(tmp_fd, F_SETFL, O_NONBLOCK) < 0)
|
else if (fcntl(tmp_fd, F_SETFL, O_NONBLOCK) < 0)
|
||||||
{
|
{
|
||||||
DLOG_PERROR("socket set O_NONBLOCK (accept)");
|
DLOG_PERROR("socket set O_NONBLOCK (accept)");
|
||||||
@ -1558,17 +1582,25 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
const char *se;
|
const char *se;
|
||||||
switch (events[i].events & (EPOLLHUP | EPOLLERR))
|
switch (events[i].events & (EPOLLHUP | EPOLLERR))
|
||||||
{
|
{
|
||||||
case EPOLLERR: se="EPOLLERR"; break;
|
case EPOLLERR:
|
||||||
case EPOLLHUP: se="EPOLLHUP"; break;
|
se = "EPOLLERR";
|
||||||
case EPOLLHUP|EPOLLERR: se="EPOLLERR EPOLLHUP"; break;
|
break;
|
||||||
default: se=NULL;
|
case EPOLLHUP:
|
||||||
|
se = "EPOLLHUP";
|
||||||
|
break;
|
||||||
|
case EPOLLHUP | EPOLLERR:
|
||||||
|
se = "EPOLLERR EPOLLHUP";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
se = NULL;
|
||||||
}
|
}
|
||||||
VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) %s so_error=%d (%s)\n", conn->fd, conn->partner ? conn->partner->fd : 0, conn->remote, se, errn, strerror(errn));
|
VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) %s so_error=%d (%s)\n", conn->fd, conn->partner ? conn->partner->fd : 0, conn->remote, se, errn, strerror(errn));
|
||||||
proxy_remote_conn_ack(conn, errn);
|
proxy_remote_conn_ack(conn, errn);
|
||||||
read_all_and_buffer(conn, 3);
|
read_all_and_buffer(conn, 3);
|
||||||
if (errn == ECONNRESET && conn_partner_alive(conn))
|
if (errn == ECONNRESET && conn_partner_alive(conn))
|
||||||
{
|
{
|
||||||
if (conn->remote && params.tamper) rst_in(&conn->partner->track);
|
if (conn->remote && params.tamper)
|
||||||
|
rst_in(&conn->partner->track);
|
||||||
|
|
||||||
struct linger lin;
|
struct linger lin;
|
||||||
lin.l_onoff = 1;
|
lin.l_onoff = 1;
|
||||||
@ -1593,7 +1625,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
{
|
{
|
||||||
DBGPRINT("EPOLLRDHUP\n");
|
DBGPRINT("EPOLLRDHUP\n");
|
||||||
read_all_and_buffer(conn, 2);
|
read_all_and_buffer(conn, 2);
|
||||||
if (!conn->remote && params.tamper) hup_out(&conn->track);
|
if (!conn->remote && params.tamper)
|
||||||
|
hup_out(&conn->track);
|
||||||
|
|
||||||
conn->state = CONN_RDHUP; // only writes. do not receive RDHUP anymore
|
conn->state = CONN_RDHUP; // only writes. do not receive RDHUP anymore
|
||||||
if (conn_has_unsent(conn))
|
if (conn_has_unsent(conn))
|
||||||
@ -1640,12 +1673,20 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
const char *se;
|
const char *se;
|
||||||
switch (events[i].events & (EPOLLIN | EPOLLOUT))
|
switch (events[i].events & (EPOLLIN | EPOLLOUT))
|
||||||
{
|
{
|
||||||
case EPOLLIN: se="EPOLLIN"; break;
|
case EPOLLIN:
|
||||||
case EPOLLOUT: se="EPOLLOUT"; break;
|
se = "EPOLLIN";
|
||||||
case EPOLLIN|EPOLLOUT: se="EPOLLIN EPOLLOUT"; break;
|
break;
|
||||||
default: se=NULL;
|
case EPOLLOUT:
|
||||||
|
se = "EPOLLOUT";
|
||||||
|
break;
|
||||||
|
case EPOLLIN | EPOLLOUT:
|
||||||
|
se = "EPOLLIN EPOLLOUT";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
se = NULL;
|
||||||
}
|
}
|
||||||
if (se) DBGPRINT("%s\n",se);
|
if (se)
|
||||||
|
DBGPRINT("%s\n", se);
|
||||||
// will not receive this until successful check_connection_attempt()
|
// will not receive this until successful check_connection_attempt()
|
||||||
if (!handle_epoll(conn, &conn_list, events[i].events))
|
if (!handle_epoll(conn, &conn_list, events[i].events))
|
||||||
{
|
{
|
||||||
@ -1663,10 +1704,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tm = time(NULL);
|
tm = time(NULL);
|
||||||
@ -1682,14 +1721,19 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
|
|||||||
print_legs();
|
print_legs();
|
||||||
}
|
}
|
||||||
|
|
||||||
fflush(stderr); fflush(stdout); // for console messages
|
fflush(stderr);
|
||||||
|
fflush(stdout); // for console messages
|
||||||
}
|
}
|
||||||
|
|
||||||
ex:
|
ex:
|
||||||
if (efd) close(efd);
|
if (efd)
|
||||||
if (listen_conn) free(listen_conn);
|
close(efd);
|
||||||
|
if (listen_conn)
|
||||||
|
free(listen_conn);
|
||||||
resolver_deinit();
|
resolver_deinit();
|
||||||
if (resolve_pipe[0]) close(resolve_pipe[0]);
|
if (resolve_pipe[0])
|
||||||
if (resolve_pipe[1]) close(resolve_pipe[1]);
|
close(resolve_pipe[0]);
|
||||||
|
if (resolve_pipe[1])
|
||||||
|
close(resolve_pipe[1]);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#define BACKLOG 10
|
#define BACKLOG 10
|
||||||
#define MAX_EPOLL_EVENTS 64
|
#define MAX_EPOLL_EVENTS 64
|
||||||
#define IP_TRANSPARENT 19 //So that application compiles on OpenWRT
|
#define IP_TRANSPARENT 19 // So that application compiles on OpenWrt
|
||||||
#define SPLICE_LEN 65536
|
#define SPLICE_LEN 65536
|
||||||
#define DEFAULT_MAX_CONN 512
|
#define DEFAULT_MAX_CONN 512
|
||||||
#define DEFAULT_MAX_ORPHAN_TIME 5
|
#define DEFAULT_MAX_ORPHAN_TIME 5
|
||||||
@ -20,7 +20,8 @@
|
|||||||
int event_loop(const int *listen_fd, size_t listen_fd_ct);
|
int event_loop(const int *listen_fd, size_t listen_fd_ct);
|
||||||
|
|
||||||
// Three different states of a connection
|
// Three different states of a connection
|
||||||
enum{
|
enum
|
||||||
|
{
|
||||||
CONN_UNAVAILABLE = 0, // connecting
|
CONN_UNAVAILABLE = 0, // connecting
|
||||||
CONN_AVAILABLE, // operational
|
CONN_AVAILABLE, // operational
|
||||||
CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked
|
CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked
|
||||||
@ -39,7 +40,8 @@ struct send_buffer
|
|||||||
};
|
};
|
||||||
typedef struct send_buffer send_buffer_t;
|
typedef struct send_buffer send_buffer_t;
|
||||||
|
|
||||||
enum{
|
enum
|
||||||
|
{
|
||||||
CONN_TYPE_TRANSPARENT = 0,
|
CONN_TYPE_TRANSPARENT = 0,
|
||||||
CONN_TYPE_SOCKS
|
CONN_TYPE_SOCKS
|
||||||
};
|
};
|
||||||
@ -59,7 +61,8 @@ struct tproxy_conn
|
|||||||
time_t orphan_since;
|
time_t orphan_since;
|
||||||
|
|
||||||
// socks5 state machine
|
// socks5 state machine
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
S_WAIT_HANDSHAKE = 0,
|
S_WAIT_HANDSHAKE = 0,
|
||||||
S_WAIT_REQUEST,
|
S_WAIT_REQUEST,
|
||||||
S_WAIT_RESOLVE,
|
S_WAIT_RESOLVE,
|
||||||
@ -70,7 +73,7 @@ struct tproxy_conn
|
|||||||
struct resolve_item *socks_ri;
|
struct resolve_item *socks_ri;
|
||||||
|
|
||||||
// these value are used in flow control. we do not use ET (edge triggered) polling
|
// these value are used in flow control. we do not use ET (edge triggered) polling
|
||||||
// if we dont disable notifications they will come endlessly until condition becomes false and will eat all cpu time
|
// if we don't disable notifications they will come endlessly until condition becomes false and will eat all cpu time
|
||||||
bool bFlowIn, bFlowOut, bShutdown, bFlowInPrev, bFlowOutPrev, bPrevRdhup;
|
bool bFlowIn, bFlowOut, bShutdown, bFlowInPrev, bFlowOutPrev, bPrevRdhup;
|
||||||
|
|
||||||
// total read,write
|
// total read,write
|
||||||
@ -95,7 +98,8 @@ struct tproxy_conn
|
|||||||
t_ctrack track;
|
t_ctrack track;
|
||||||
|
|
||||||
// Create the struct which contains ptrs to next/prev element
|
// Create the struct which contains ptrs to next/prev element
|
||||||
TAILQ_ENTRY(tproxy_conn) conn_ptrs;
|
TAILQ_ENTRY(tproxy_conn)
|
||||||
|
conn_ptrs;
|
||||||
};
|
};
|
||||||
typedef struct tproxy_conn tproxy_conn_t;
|
typedef struct tproxy_conn tproxy_conn_t;
|
||||||
|
|
||||||
@ -103,5 +107,4 @@ typedef struct tproxy_conn tproxy_conn_t;
|
|||||||
// Use tail queue for efficient delete
|
// Use tail queue for efficient delete
|
||||||
TAILQ_HEAD(tailhead, tproxy_conn);
|
TAILQ_HEAD(tailhead, tproxy_conn);
|
||||||
|
|
||||||
|
|
||||||
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);
|
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);
|
||||||
|
600
tpws/uthash.h
600
tpws/uthash.h
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user