Linting and formatting of .c and .h with C/C++ IntelliSence

This commit is contained in:
conc3rned 2024-09-17 16:19:54 +03:00
parent 8c94e3230e
commit c1db09b19e
80 changed files with 9996 additions and 8587 deletions

View File

@ -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

View File

@ -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,

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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) ^

View File

@ -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
******************************************************************************/ ******************************************************************************/

View File

@ -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
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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.) */

View File

@ -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.

View File

@ -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;
} }

View File

@ -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;
} }
} }

View File

@ -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

View File

@ -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);

View File

@ -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(&params.conntrack); // ConntrackPoolDump(&params.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;

View File

@ -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,

View File

@ -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);

View File

@ -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)
{ {

View File

@ -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];
} }

View File

@ -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;
} }
} }

View File

@ -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, &params); qh = nfq_create_queue(h, params.qnum, &nfq_cb, &params);
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(&params.conntrack); ConntrackPoolDestroy(&params.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", &params.desync_fwmark)<=0) sscanf(optarg, "%u", &params.desync_fwmark); if (sscanf(optarg, "0x%X", &params.desync_fwmark) <= 0)
sscanf(optarg, "%u", &params.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(&params.ssid_filter, p)) if (*p && !strlist_add(&params.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(&params.nlm_filter, p)) if (*p && !strlist_add(&params.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))
{ {

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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
{ {

View File

@ -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)

View File

@ -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) */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -7,4 +7,3 @@
bool service_run(); bool service_run();
#endif #endif

View File

@ -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
{ {

View File

@ -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

View File

@ -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, /**/
&current_time) < 0) { &current_time) < 0)
{
return errno; return errno;
} }
timespecsub(deadline, &current_time, &timeout); timespecsub(deadline, &current_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);
} }

View File

@ -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;
} }

View File

@ -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

View File

@ -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;

View File

@ -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_;

View File

@ -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;
}; };

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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])

View File

@ -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;
} }
} }

View File

@ -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;

View File

@ -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); \

View File

@ -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;

View File

@ -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
{ {

View File

@ -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)

View File

@ -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) */

View File

@ -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)

View File

@ -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);

View File

@ -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");

View File

@ -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;

View File

@ -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);

View File

@ -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__

View File

@ -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__)

View File

@ -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;

View File

@ -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(&params.hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&params.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(&params.hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters);

View File

@ -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

View File

@ -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, &params.connect_bind4.sin_addr)) if (inet_pton(AF_INET, optarg, &params.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(&params.hostlist); if (*params.hostlist_auto_filename)
NonEmptyHostlist(&params.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;
} }

View File

@ -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;
} }

View File

@ -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);

File diff suppressed because it is too large Load Diff