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

@ -27,29 +27,29 @@
#define ALLOC_STEP 16384
// minimum subnet fill percent is PCTMULT/PCTDIV (for example 3/4)
#define DEFAULT_PCTMULT 3
#define DEFAULT_PCTDIV 4
#define DEFAULT_PCTMULT 3
#define DEFAULT_PCTDIV 4
// subnet search range in "zero bit count"
// means search start from /(32-ZCT_MAX) to /(32-ZCT_MIN)
#define DEFAULT_V4_ZCT_MAX 10 // /22
#define DEFAULT_V4_ZCT_MIN 2 // /30
#define DEFAULT_V6_ZCT_MAX 72 // /56
#define DEFAULT_V6_ZCT_MIN 64 // /64
// must be no less than N ipv6 in subnet
#define DEFAULT_V6_THRESHOLD 5
// must be no less than N IPv6 in subnet
#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)
{
if (*(uint32_t*)a < *(uint32_t*)b)
if (*(uint32_t *)a < *(uint32_t *)b)
return -1;
else if (*(uint32_t*)a > *(uint32_t*)b)
else if (*(uint32_t *)a > *(uint32_t *)b)
return 1;
else
return 0;
}
static uint32_t mask_from_bitcount(uint32_t zct)
{
return zct<32 ? ~((1 << zct) - 1) : 0;
return zct < 32 ? ~((1 << zct) - 1) : 0;
}
// make presorted array unique. return number of unique items.
// 1,1,2,3,3,0,0,0 (ct=8) => 1,2,3,0 (ct=4)
@ -59,18 +59,18 @@ static uint32_t unique(uint32_t *pu, uint32_t ct)
for (i = j = 0; j < ct; i++)
{
u = pu[j++];
for (; j < ct && pu[j] == u; j++);
for (; j < ct && pu[j] == u; j++)
;
pu[i] = u;
}
return i;
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
__attribute__((optimize("no-strict-aliasing")))
#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
// on big endian systems cpu byte order is equal to network byte order
@ -79,15 +79,15 @@ static int cmp6(const void * a, const void * b, void *arg)
// 64-bit archs often have cpu command to reverse byte order
// assume that a and b are properly aligned
#if defined(__BYTE_ORDER__) && ((__BYTE_ORDER__==__ORDER_BIG_ENDIAN__) || (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__))
#if defined(__BYTE_ORDER__) && ((__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
uint64_t aa,bb;
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
aa = __builtin_bswap64(((uint64_t*)((struct in6_addr *)a)->s6_addr)[0]);
bb = __builtin_bswap64(((uint64_t*)((struct in6_addr *)b)->s6_addr)[0]);
uint64_t aa, bb;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
aa = __builtin_bswap64(((uint64_t *)((struct in6_addr *)a)->s6_addr)[0]);
bb = __builtin_bswap64(((uint64_t *)((struct in6_addr *)b)->s6_addr)[0]);
#else
aa = ((uint64_t*)((struct in6_addr *)a)->s6_addr)[0];
bb = ((uint64_t*)((struct in6_addr *)b)->s6_addr)[0];
aa = ((uint64_t *)((struct in6_addr *)a)->s6_addr)[0];
bb = ((uint64_t *)((struct in6_addr *)b)->s6_addr)[0];
#endif
if (aa < bb)
return -1;
@ -95,16 +95,17 @@ static int cmp6(const void * a, const void * b, void *arg)
return 1;
else
{
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
aa = __builtin_bswap64(((uint64_t*)((struct in6_addr *)a)->s6_addr)[1]);
bb = __builtin_bswap64(((uint64_t*)((struct in6_addr *)b)->s6_addr)[1]);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
aa = __builtin_bswap64(((uint64_t *)((struct in6_addr *)a)->s6_addr)[1]);
bb = __builtin_bswap64(((uint64_t *)((struct in6_addr *)b)->s6_addr)[1]);
#else
aa = ((uint64_t*)((struct in6_addr *)a)->s6_addr)[1];
bb = ((uint64_t*)((struct in6_addr *)b)->s6_addr)[1];
aa = ((uint64_t *)((struct in6_addr *)a)->s6_addr)[1];
bb = ((uint64_t *)((struct in6_addr *)b)->s6_addr)[1];
#endif
return aa < bb ? -1 : aa > bb ? 1 : 0;
return aa < bb ? -1 : aa > bb ? 1
: 0;
}
#else
// fallback case
for (uint8_t i = 0; i < sizeof(((struct in6_addr *)0)->s6_addr); i++)
@ -124,7 +125,8 @@ static uint32_t unique6(struct in6_addr *pu, uint32_t ct)
uint32_t i, j, k;
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];
}
return i;
@ -132,26 +134,26 @@ static uint32_t unique6(struct in6_addr *pu, uint32_t ct)
static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a)
{
if (zct >= 128)
memset(a->s6_addr,0x00,16);
memset(a->s6_addr, 0x00, 16);
else
{
int32_t n = (127 - zct) >> 3;
memset(a->s6_addr,0xFF,n);
memset(a->s6_addr+n,0x00,16-n);
memset(a->s6_addr, 0xFF, n);
memset(a->s6_addr + n, 0x00, 16 - n);
a->s6_addr[n] = ~((1 << (zct & 7)) - 1);
}
}
static struct in6_addr ip6_mask[129];
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)
{
return ip6_mask+zct;
return ip6_mask + zct;
}
/*
// this is "correct" solution for strict aliasing feature
// but I don't like this style of coding
@ -176,44 +178,43 @@ static void ip6_and(const struct in6_addr *a, const struct in6_addr *b, struct i
// result = a & b
// assume that a and b are properly aligned
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
__attribute__((optimize("no-strict-aliasing")))
#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__
// gcc and clang have 128 bit int types on some 64-bit archs. take some advantage
*((unsigned __int128*)result->s6_addr) = *((unsigned __int128*)a->s6_addr) & *((unsigned __int128*)b->s6_addr);
*((unsigned __int128 *)result->s6_addr) = *((unsigned __int128 *)a->s6_addr) & *((unsigned __int128 *)b->s6_addr);
#else
((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0];
((uint64_t*)result->s6_addr)[1] = ((uint64_t*)a->s6_addr)[1] & ((uint64_t*)b->s6_addr)[1];
((uint64_t *)result->s6_addr)[0] = ((uint64_t *)a->s6_addr)[0] & ((uint64_t *)b->s6_addr)[0];
((uint64_t *)result->s6_addr)[1] = ((uint64_t *)a->s6_addr)[1] & ((uint64_t *)b->s6_addr)[1];
#endif
}
static void rtrim(char *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
{
bool ipv6;
uint32_t pctmult, pctdiv; // for v4
uint32_t pctmult, pctdiv; // for v4
uint32_t zct_min, zct_max; // for v4 and v6
uint32_t v6_threshold; // for v6
uint32_t v6_threshold; // for v6
} params;
static void exithelp(void)
{
printf(
" -4\t\t\t\t; ipv4 list (default)\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"
" --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"
);
" -4\t\t\t\t; IPv4 list (default)\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"
" --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");
exit(1);
}
@ -221,7 +222,7 @@ static void parse_params(int argc, char *argv[])
{
int option_index = 0;
int v, i;
uint32_t plen1=-1, plen2=-1;
uint32_t plen1 = -1, plen2 = -1;
memset(&params, 0, sizeof(params));
params.pctmult = DEFAULT_PCTMULT;
@ -229,18 +230,18 @@ static void parse_params(int argc, char *argv[])
params.v6_threshold = DEFAULT_V6_THRESHOLD;
const struct option long_options[] = {
{ "help",no_argument,0,0 },// optidx=0
{ "h",no_argument,0,0 },// optidx=1
{ "4",no_argument,0,0 },// optidx=2
{ "6",no_argument,0,0 },// optidx=3
{ "prefix-length",required_argument,0,0 },// optidx=4
{ "v4-threshold",required_argument,0,0 },// optidx=5
{ "v6-threshold",required_argument,0,0 },// optidx=6
{ NULL,0,NULL,0 }
};
{"help", no_argument, 0, 0}, // optidx=0
{"h", no_argument, 0, 0}, // optidx=1
{"4", no_argument, 0, 0}, // optidx=2
{"6", no_argument, 0, 0}, // optidx=3
{"prefix-length", required_argument, 0, 0}, // optidx=4
{"v4-threshold", required_argument, 0, 0}, // optidx=5
{"v6-threshold", required_argument, 0, 0}, // optidx=6
{NULL, 0, NULL, 0}};
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{
if (v) exithelp();
if (v)
exithelp();
switch (option_index)
{
case 0:
@ -254,9 +255,10 @@ static void parse_params(int argc, char *argv[])
params.ipv6 = true;
break;
case 4:
i = sscanf(optarg,"%u-%u",&plen1,&plen2);
if (i == 1) plen2 = plen1;
if (i<=0 || plen2<plen1 || !plen1 || !plen2)
i = sscanf(optarg, "%u-%u", &plen1, &plen2);
if (i == 1)
plen2 = plen1;
if (i <= 0 || plen2 < plen1 || !plen1 || !plen2)
{
fprintf(stderr, "invalid parameter for prefix-length : %s\n", optarg);
exit(1);
@ -264,7 +266,7 @@ static void parse_params(int argc, char *argv[])
break;
case 5:
i = sscanf(optarg, "%u/%u", &params.pctmult, &params.pctdiv);
if (i!=2 || params.pctdiv<2 || params.pctmult<1 || params.pctmult>=params.pctdiv)
if (i != 2 || params.pctdiv < 2 || params.pctmult < 1 || params.pctmult >= params.pctdiv)
{
fprintf(stderr, "invalid parameter for v4-threshold : %s\n", optarg);
exit(1);
@ -272,7 +274,7 @@ static void parse_params(int argc, char *argv[])
break;
case 6:
i = sscanf(optarg, "%u", &params.v6_threshold);
if (i != 1 || params.v6_threshold<1)
if (i != 1 || params.v6_threshold < 1)
{
fprintf(stderr, "invalid parameter for v6-threshold : %s\n", optarg);
exit(1);
@ -280,19 +282,20 @@ static void parse_params(int argc, char *argv[])
break;
}
}
if (plen1 != -1 && ((!params.ipv6 && (plen1>31 || plen2>31)) || (params.ipv6 && (plen1>127 || plen2>127))))
if (plen1 != -1 && ((!params.ipv6 && (plen1 > 31 || plen2 > 31)) || (params.ipv6 && (plen1 > 127 || plen2 > 127))))
{
fprintf(stderr, "invalid parameter for prefix-length\n");
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_max = params.ipv6 ? plen1==-1 ? DEFAULT_V6_ZCT_MAX : 128-plen1 : plen1==-1 ? DEFAULT_V4_ZCT_MAX : 32-plen1;
params.zct_min = params.ipv6 ? plen2 == -1 ? DEFAULT_V6_ZCT_MIN : 128 - plen2 : plen2 == -1 ? DEFAULT_V4_ZCT_MIN
: 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)
{
char str[256],d;
char str[256], d;
uint32_t ipct = 0, iplist_size = 0, pos = 0, p, zct, ip_ct, pos_end;
parse_params(argc, argv);
@ -313,25 +316,27 @@ int main(int argc, char **argv)
}
if (inet_pton(AF_INET6, str, &a))
{
if (d=='/')
if (d == '/')
{
// we have subnet ip6/y
// 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;
}
}
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;
}
if (ipct >= iplist_size)
{
iplist_size += ALLOC_STEP;
iplist_new = (struct in6_addr*)(iplist ? realloc(iplist, sizeof(*iplist)*iplist_size) : malloc(sizeof(*iplist)*iplist_size));
iplist_new = (struct in6_addr *)(iplist ? realloc(iplist, sizeof(*iplist) * iplist_size) : malloc(sizeof(*iplist) * iplist_size));
if (!iplist_new)
{
free(iplist);
@ -371,7 +376,8 @@ int main(int argc, char **argv)
if (memcmp(&ip_start, &ip, sizeof(ip)))
break;
}
if (ip_ct == 1) break;
if (ip_ct == 1)
break;
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
@ -400,20 +406,19 @@ int main(int argc, char **argv)
}
else // ipv4
{
uint32_t u1,u2,u3,u4, u11,u22,u33,u44, ip;
uint32_t u1, u2, u3, u4, u11, u22, u33, u44, ip;
uint32_t *iplist = NULL, *iplist_new, i;
while (fgets(str, sizeof(str), stdin))
{
if ((i = sscanf(str, "%u.%u.%u.%u-%u.%u.%u.%u", &u1, &u2, &u3, &u4, &u11, &u22, &u33, &u44)) >= 8 &&
if ((i = sscanf(str, "%u.%u.%u.%u-%u.%u.%u.%u", &u1, &u2, &u3, &u4, &u11, &u22, &u33, &u44)) >= 8 &&
!(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00) &&
!(u11 & 0xFFFFFF00) && !(u22 & 0xFFFFFF00) && !(u33 & 0xFFFFFF00) && !(u44 & 0xFFFFFF00))
{
printf("%u.%u.%u.%u-%u.%u.%u.%u\n", u1, u2, u3, u4, u11, u22, u33, u44);
}
else
if ((i = sscanf(str, "%u.%u.%u.%u/%u", &u1, &u2, &u3, &u4, &zct)) >= 4 &&
!(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00))
else if ((i = sscanf(str, "%u.%u.%u.%u/%u", &u1, &u2, &u3, &u4, &zct)) >= 4 &&
!(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00))
{
if (i == 5 && zct != 32)
{
@ -428,7 +433,7 @@ int main(int argc, char **argv)
if (ipct >= iplist_size)
{
iplist_size += ALLOC_STEP;
iplist_new = (uint32_t*)(iplist ? realloc(iplist, sizeof(*iplist)*iplist_size) : malloc(sizeof(*iplist)*iplist_size));
iplist_new = (uint32_t *)(iplist ? realloc(iplist, sizeof(*iplist) * iplist_size) : malloc(sizeof(*iplist) * iplist_size));
if (!iplist_new)
{
free(iplist);
@ -456,12 +461,14 @@ int main(int argc, char **argv)
mask = mask_from_bitcount(zct);
ip_start = iplist[pos] & mask;
subnet_ct = ~mask + 1;
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
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
if (ip_ct == 1) break;
if (ip_ct >= (subnet_ct*params.pctmult / params.pctdiv))
for (p = pos + 1, ip_ct = 1; p < ipct && iplist[p] <= ip_end; p++)
ip_ct++; // count ips within subnet range
if (ip_ct == 1)
break;
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
if (!ip_ct_best || ip_ct == ip_ct_best)

View File

@ -20,25 +20,25 @@
Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
//#include <alloca.h>
// #include <alloca.h>
#include <limits.h>
#include <stdlib.h>
//#include <string.h>
// #include <string.h>
#include "qsort.h"
/* Byte-wise swap two items of size SIZE. */
#define SWAP(a, b, size) \
do \
{ \
size_t __size = (size); \
char *__a = (a), *__b = (b); \
do \
{ \
char __tmp = *__a; \
*__a++ = *__b; \
*__b++ = __tmp; \
} while (--__size > 0); \
} while (0)
#define SWAP(a, b, size) \
do \
{ \
size_t __size = (size); \
char *__a = (a), *__b = (b); \
do \
{ \
char __tmp = *__a; \
*__a++ = *__b; \
*__b++ = __tmp; \
} while (--__size > 0); \
} while (0)
/* Discontinue quicksort algorithm when partition gets below this size.
This particular magic number was chosen to work best on a Sun 4/260. */
@ -46,21 +46,20 @@
/* Stack node declarations used to store unfulfilled partition obligations. */
typedef struct
{
char *lo;
char *hi;
} stack_node;
{
char *lo;
char *hi;
} stack_node;
/* The next 4 #defines implement a very fast in-line stack abstraction. */
/* The stack needs log (total_elements) entries (we could even subtract
log(MAX_THRESH)). Since total_elements has type size_t, we get as
upper bound for log (total_elements):
bits per byte (CHAR_BIT) * sizeof(size_t). */
#define STACK_SIZE (CHAR_BIT * sizeof(size_t))
#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
#define STACK_NOT_EMPTY (stack < top)
#define STACK_SIZE (CHAR_BIT * sizeof(size_t))
#define PUSH(low, high) ((void)((top->lo = (low)), (top->hi = (high)), ++top))
#define POP(low, high) ((void)(--top, (low = top->lo), (high = top->hi)))
#define STACK_NOT_EMPTY (stack < top)
/* Order size using quicksort. This implementation incorporates
four optimizations discussed in Sedgewick:
@ -86,11 +85,10 @@ typedef struct
smaller partition. This *guarantees* no more than log (total_elems)
stack size is needed (actually O(1) in this case)! */
void
gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
__gnu_compar_d_fn_t cmp, void *arg)
void gnu_quicksort(void *const pbase, size_t total_elems, size_t size,
__gnu_compar_d_fn_t cmp, void *arg)
{
char *base_ptr = (char *) pbase;
char *base_ptr = (char *)pbase;
const size_t max_thresh = MAX_THRESH * size;
@ -99,101 +97,100 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
return;
if (total_elems > MAX_THRESH)
{
char *lo = base_ptr;
char *hi = &lo[size * (total_elems - 1)];
stack_node stack[STACK_SIZE];
stack_node *top = stack;
PUSH(NULL, NULL);
while (STACK_NOT_EMPTY)
{
char *lo = base_ptr;
char *hi = &lo[size * (total_elems - 1)];
stack_node stack[STACK_SIZE];
stack_node *top = stack;
char *left_ptr;
char *right_ptr;
PUSH (NULL, NULL);
/* Select median value from among LO, MID, and HI. Rearrange
LO and HI so the three values are sorted. This lowers the
probability of picking a pathological pivot value and
skips a comparison for both the LEFT_PTR and RIGHT_PTR in
the while loops. */
while (STACK_NOT_EMPTY)
char *mid = lo + size * ((hi - lo) / size >> 1);
if ((*cmp)((void *)mid, (void *)lo, arg) < 0)
SWAP(mid, lo, size);
if ((*cmp)((void *)hi, (void *)mid, arg) < 0)
SWAP(mid, hi, size);
else
goto jump_over;
if ((*cmp)((void *)mid, (void *)lo, arg) < 0)
SWAP(mid, lo, size);
jump_over:;
left_ptr = lo + size;
right_ptr = hi - size;
/* Here's the famous ``collapse the walls'' section of quicksort.
Gotta like those tight inner loops! They are the main reason
that this algorithm runs much faster than others. */
do
{
while ((*cmp)((void *)left_ptr, (void *)mid, arg) < 0)
left_ptr += size;
while ((*cmp)((void *)mid, (void *)right_ptr, arg) < 0)
right_ptr -= size;
if (left_ptr < right_ptr)
{
char *left_ptr;
char *right_ptr;
/* Select median value from among LO, MID, and HI. Rearrange
LO and HI so the three values are sorted. This lowers the
probability of picking a pathological pivot value and
skips a comparison for both the LEFT_PTR and RIGHT_PTR in
the while loops. */
char *mid = lo + size * ((hi - lo) / size >> 1);
if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
SWAP (mid, lo, size);
if ((*cmp) ((void *) hi, (void *) mid, arg) < 0)
SWAP (mid, hi, size);
else
goto jump_over;
if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
SWAP (mid, lo, size);
jump_over:;
left_ptr = lo + size;
right_ptr = hi - size;
/* Here's the famous ``collapse the walls'' section of quicksort.
Gotta like those tight inner loops! They are the main reason
that this algorithm runs much faster than others. */
do
{
while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
left_ptr += size;
while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
right_ptr -= size;
if (left_ptr < right_ptr)
{
SWAP (left_ptr, right_ptr, size);
if (mid == left_ptr)
mid = right_ptr;
else if (mid == right_ptr)
mid = left_ptr;
left_ptr += size;
right_ptr -= size;
}
else if (left_ptr == right_ptr)
{
left_ptr += size;
right_ptr -= size;
break;
}
}
while (left_ptr <= right_ptr);
/* Set up pointers for next iteration. First determine whether
left and right partitions are below the threshold size. If so,
ignore one or both. Otherwise, push the larger partition's
bounds on the stack and continue sorting the smaller one. */
if ((size_t) (right_ptr - lo) <= max_thresh)
{
if ((size_t) (hi - left_ptr) <= max_thresh)
/* Ignore both small partitions. */
POP (lo, hi);
else
/* Ignore small left partition. */
lo = left_ptr;
}
else if ((size_t) (hi - left_ptr) <= max_thresh)
/* Ignore small right partition. */
hi = right_ptr;
else if ((right_ptr - lo) > (hi - left_ptr))
{
/* Push larger left partition indices. */
PUSH (lo, right_ptr);
lo = left_ptr;
}
else
{
/* Push larger right partition indices. */
PUSH (left_ptr, hi);
hi = right_ptr;
}
SWAP(left_ptr, right_ptr, size);
if (mid == left_ptr)
mid = right_ptr;
else if (mid == right_ptr)
mid = left_ptr;
left_ptr += size;
right_ptr -= size;
}
else if (left_ptr == right_ptr)
{
left_ptr += size;
right_ptr -= size;
break;
}
} while (left_ptr <= right_ptr);
/* Set up pointers for next iteration. First determine whether
left and right partitions are below the threshold size. If so,
ignore one or both. Otherwise, push the larger partition's
bounds on the stack and continue sorting the smaller one. */
if ((size_t)(right_ptr - lo) <= max_thresh)
{
if ((size_t)(hi - left_ptr) <= max_thresh)
/* Ignore both small partitions. */
POP(lo, hi);
else
/* Ignore small left partition. */
lo = left_ptr;
}
else if ((size_t)(hi - left_ptr) <= max_thresh)
/* Ignore small right partition. */
hi = right_ptr;
else if ((right_ptr - lo) > (hi - left_ptr))
{
/* Push larger left partition indices. */
PUSH(lo, right_ptr);
lo = left_ptr;
}
else
{
/* Push larger right partition indices. */
PUSH(left_ptr, hi);
hi = right_ptr;
}
}
}
/* Once the BASE_PTR array is partially sorted by quicksort the rest
is completely sorted using insertion sort, since this is efficient
@ -214,37 +211,37 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
and the operation speeds up insertion sort's inner loop. */
for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
if ((*cmp)((void *)run_ptr, (void *)tmp_ptr, arg) < 0)
tmp_ptr = run_ptr;
if (tmp_ptr != base_ptr)
SWAP (tmp_ptr, base_ptr, size);
SWAP(tmp_ptr, base_ptr, size);
/* Insertion sort, running from left-hand-side up to right-hand-side. */
run_ptr = base_ptr + size;
while ((run_ptr += size) <= end_ptr)
{
tmp_ptr = run_ptr - size;
while ((*cmp)((void *)run_ptr, (void *)tmp_ptr, arg) < 0)
tmp_ptr -= size;
tmp_ptr += size;
if (tmp_ptr != run_ptr)
{
tmp_ptr = run_ptr - size;
while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
tmp_ptr -= size;
char *trav;
tmp_ptr += size;
if (tmp_ptr != run_ptr)
{
char *trav;
trav = run_ptr + size;
while (--trav >= run_ptr)
{
char c = *trav;
char *hi, *lo;
trav = run_ptr + size;
while (--trav >= run_ptr)
{
char c = *trav;
char *hi, *lo;
for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
*hi = *lo;
*hi = c;
}
}
for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
*hi = *lo;
*hi = c;
}
}
}
}
}

View File

@ -2,5 +2,5 @@
// GNU qsort is 2x faster than musl
typedef int (*__gnu_compar_d_fn_t) (const void *, const void *, void *);
void gnu_quicksort (void *const pbase, size_t total_elems, size_t size, __gnu_compar_d_fn_t cmp, void *arg);
typedef int (*__gnu_compar_d_fn_t)(const void *, const void *, void *);
void gnu_quicksort(void *const pbase, size_t total_elems, size_t size, __gnu_compar_d_fn_t cmp, void *arg);

View File

@ -34,10 +34,11 @@
static void trimstr(char *s)
{
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)
{
switch (r)
{
@ -76,18 +77,21 @@ static const char* eai_str(int r)
static bool dom_valid(char *dom)
{
if (!dom || *dom=='.') return false;
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 || *dom == '.')
return false;
for (; *dom; dom++)
if (*dom < 0x20 || (*dom & 0x80) || !(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z')))
return false;
return true;
}
static void invalid_domain_beautify(char *dom)
{
for (int i = 0; *dom && i < 64; i++, dom++)
if (*dom < 0x20 || *dom>0x7F) *dom = '?';
if (*dom) *dom = 0;
if (*dom < 0x20 || *dom > 0x7F)
*dom = '?';
if (*dom)
*dom = 0;
}
#define FAMILY4 1
@ -99,7 +103,7 @@ static struct
int threads;
time_t start_time;
pthread_mutex_t flock;
pthread_mutex_t slock; // stats lock
pthread_mutex_t slock; // stats lock
int stats_every, stats_ct, stats_ct_ok; // stats
FILE *F_log_resolved, *F_log_failed;
} glob;
@ -111,11 +115,12 @@ static char interlocked_get_dom(char *dom, size_t size)
pthread_mutex_lock(&glob.flock);
s = fgets(dom, size, stdin);
pthread_mutex_unlock(&glob.flock);
if (!s) return 0;
if (!s)
return 0;
trimstr(s);
return 1;
}
static void interlocked_fprintf(FILE *stream, const char * format, ...)
static void interlocked_fprintf(FILE *stream, const char *format, ...)
{
if (stream)
{
@ -128,8 +133,12 @@ static void interlocked_fprintf(FILE *stream, const char * format, ...)
}
}
#define ELOG(format, ...) interlocked_fprintf(stderr, "[%d] " format "\n", tid, ##__VA_ARGS__)
#define VLOG(format, ...) {if (glob.verbose) ELOG(format, ##__VA_ARGS__);}
#define ELOG(format, ...) interlocked_fprintf(stderr, "[%d] " format "\n", tid, ##__VA_ARGS__)
#define VLOG(format, ...) \
{ \
if (glob.verbose) \
ELOG(format, ##__VA_ARGS__); \
}
static void print_addrinfo(struct addrinfo *ai)
{
@ -139,11 +148,11 @@ static void print_addrinfo(struct addrinfo *ai)
switch (ai->ai_family)
{
case AF_INET:
if (inet_ntop(ai->ai_family, &((struct sockaddr_in*)ai->ai_addr)->sin_addr, str, sizeof(str)))
if (inet_ntop(ai->ai_family, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, str, sizeof(str)))
interlocked_fprintf(stdout, "%s\n", str);
break;
case AF_INET6:
if (inet_ntop(ai->ai_family, &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, str, sizeof(str)))
if (inet_ntop(ai->ai_family, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, str, sizeof(str)))
interlocked_fprintf(stdout, "%s\n", str);
break;
}
@ -155,8 +164,8 @@ static void stat_print(int ct, int ct_ok)
{
if (glob.stats_every > 0)
{
time_t tm = time(NULL)-glob.start_time;
interlocked_fprintf(stderr, "mdig stats : %02u:%02u:%02u : domains=%d success=%d error=%d\n", (unsigned int)(tm/3600), (unsigned int)((tm/60)%60), (unsigned int)(tm%60), ct, ct_ok, ct - ct_ok);
time_t tm = time(NULL) - glob.start_time;
interlocked_fprintf(stderr, "mdig stats : %02u:%02u:%02u : domains=%d success=%d error=%d\n", (unsigned int)(tm / 3600), (unsigned int)((tm / 60) % 60), (unsigned int)(tm % 60), ct, ct_ok, ct - ct_ok);
}
}
@ -170,7 +179,8 @@ static void stat_plus(bool is_ok)
ct_ok = glob.stats_ct_ok += is_ok;
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");
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;
while (interlocked_get_dom(dom, sizeof(dom)))
@ -211,7 +222,8 @@ static void *t_resolver(void *arg)
strncpy(s_ip, dom, sizeof(s_ip));
s_mask = strchr(s_ip, '/');
if (s_mask) *s_mask++ = 0;
if (s_mask)
*s_mask++ = 0;
family = GetAddrFamily(s_ip);
if (family)
{
@ -221,12 +233,18 @@ static void *t_resolver(void *arg)
bool mask_needed = false;
if (s_mask)
{
if (sscanf(s_mask, "%u", &mask)==1)
if (sscanf(s_mask, "%u", &mask) == 1)
{
switch (family)
{
case AF_INET: is_ok = mask <= 32; mask_needed = mask < 32; break;
case AF_INET6: is_ok = mask <= 128; mask_needed = mask < 128; break;
case AF_INET:
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)))
{
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
{
@ -262,11 +281,11 @@ static void *t_resolver(void *arg)
else if (glob.verbose)
{
char dom2[sizeof(dom)];
strcpy(dom2,dom);
strcpy(dom2, dom);
invalid_domain_beautify(dom2);
VLOG("invalid domain : %s", dom2);
}
interlocked_fprintf(is_ok ? glob.F_log_resolved : glob.F_log_failed,"%s\n",dom);
interlocked_fprintf(is_ok ? glob.F_log_resolved : glob.F_log_failed, "%s\n", dom);
}
stat_plus(is_ok);
}
@ -292,7 +311,7 @@ static int run_threads(void)
pthread_mutex_destroy(&glob.flock);
return 10;
}
t = (pthread_t*)malloc(sizeof(pthread_t)*glob.threads);
t = (pthread_t *)malloc(sizeof(pthread_t) * glob.threads);
if (!t)
{
fprintf(stderr, "out of memory\n");
@ -302,7 +321,7 @@ static int run_threads(void)
}
for (thread = 0; thread < glob.threads; thread++)
{
if (pthread_create(t + thread, NULL, t_resolver, (void*)(size_t)thread))
if (pthread_create(t + thread, NULL, t_resolver, (void *)(size_t)thread))
{
interlocked_fprintf(stderr, "failed to create thread #%d\n", thread);
break;
@ -327,25 +346,23 @@ static void exithelp(void)
" --verbose\t\t; print query progress to stderr\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-failed=<file>\t; log failed domains to a file\n"
);
" --log-failed=<file>\t; log failed domains to a file\n");
exit(1);
}
int main(int argc, char **argv)
{
int r, v, option_index = 0;
char fn1[256],fn2[256];
char fn1[256], fn2[256];
static const struct option long_options[] = {
{"help",no_argument,0,0}, // optidx=0
{"threads",required_argument,0,0}, // optidx=1
{"family",required_argument,0,0}, // optidx=2
{"verbose",no_argument,0,0}, // optidx=3
{"stats",required_argument,0,0}, // optidx=4
{"log-resolved",required_argument,0,0}, // optidx=5
{"log-failed",required_argument,0,0}, // optidx=6
{NULL,0,NULL,0}
};
{"help", no_argument, 0, 0}, // optidx=0
{"threads", required_argument, 0, 0}, // optidx=1
{"family", required_argument, 0, 0}, // optidx=2
{"verbose", no_argument, 0, 0}, // optidx=3
{"stats", required_argument, 0, 0}, // optidx=4
{"log-resolved", required_argument, 0, 0}, // optidx=5
{"log-failed", required_argument, 0, 0}, // optidx=6
{NULL, 0, NULL, 0}};
memset(&glob, 0, sizeof(glob));
*fn1 = *fn2 = 0;
@ -353,7 +370,8 @@ int main(int argc, char **argv)
glob.threads = 1;
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{
if (v) exithelp();
if (v)
exithelp();
switch (option_index)
{
case 0: /* help */
@ -387,12 +405,12 @@ int main(int argc, char **argv)
glob.stats_every = optarg ? atoi(optarg) : 0;
break;
case 5: /* log-resolved */
strncpy(fn1,optarg,sizeof(fn1));
fn1[sizeof(fn1)-1] = 0;
strncpy(fn1, optarg, sizeof(fn1));
fn1[sizeof(fn1) - 1] = 0;
break;
case 6: /* log-failed */
strncpy(fn2,optarg,sizeof(fn2));
fn2[sizeof(fn2)-1] = 0;
strncpy(fn2, optarg, sizeof(fn2));
fn2[sizeof(fn2) - 1] = 0;
break;
}
}
@ -401,35 +419,39 @@ int main(int argc, char **argv)
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
{
fprintf(stderr,"WSAStartup failed\n");
fprintf(stderr, "WSAStartup failed\n");
return 4;
}
#endif
if (*fn1)
{
glob.F_log_resolved = fopen(fn1,"wt");
glob.F_log_resolved = fopen(fn1, "wt");
if (!glob.F_log_resolved)
{
fprintf(stderr,"failed to create %s\n",fn1);
r=5; goto ex;
fprintf(stderr, "failed to create %s\n", fn1);
r = 5;
goto ex;
}
}
if (*fn2)
{
glob.F_log_failed = fopen(fn2,"wt");
glob.F_log_failed = fopen(fn2, "wt");
if (!glob.F_log_failed)
{
fprintf(stderr,"failed to create %s\n",fn2);
r=5; goto ex;
fprintf(stderr, "failed to create %s\n", fn2);
r = 5;
goto ex;
}
}
r = run_threads();
ex:
if (glob.F_log_resolved) fclose(glob.F_log_resolved);
if (glob.F_log_failed) fclose(glob.F_log_failed);
if (glob.F_log_resolved)
fclose(glob.F_log_resolved);
if (glob.F_log_failed)
fclose(glob.F_log_failed);
return r;
}

View File

@ -2,64 +2,65 @@
#include "checksum.h"
#include <netinet/in.h>
//#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
//#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
// #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
// #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
static uint16_t from64to16(uint64_t x)
{
uint32_t u = (uint32_t)(uint16_t)x + (uint16_t)(x>>16) + (uint16_t)(x>>32) + (uint16_t)(x>>48);
return (uint16_t)u + (uint16_t)(u>>16);
uint32_t u = (uint32_t)(uint16_t)x + (uint16_t)(x >> 16) + (uint16_t)(x >> 32) + (uint16_t)(x >> 48);
return (uint16_t)u + (uint16_t)(u >> 16);
}
// this function preserves data alignment requirements (otherwise it will be damn slow on mips arch)
// and uses 64-bit arithmetics to improve speed
// taken from linux source code
static uint16_t do_csum(const uint8_t * buff, size_t len)
// taken from Linux source code
static uint16_t do_csum(const uint8_t *buff, size_t len)
{
uint8_t odd;
size_t count;
uint64_t result,w,carry=0;
uint64_t result, w, carry = 0;
uint16_t u16;
if (!len) return 0;
if (!len)
return 0;
odd = (uint8_t)(1 & (size_t)buff);
if (odd)
{
// any endian compatible
u16 = 0;
*((uint8_t*)&u16+1) = *buff;
*((uint8_t *)&u16 + 1) = *buff;
result = u16;
len--;
buff++;
}
else
result = 0;
count = len >> 1; /* nr of 16-bit words.. */
count = len >> 1; /* nr of 16-bit words.. */
if (count)
{
if (2 & (size_t) buff)
if (2 & (size_t)buff)
{
result += *(uint16_t *) buff;
result += *(uint16_t *)buff;
count--;
len -= 2;
buff += 2;
}
count >>= 1; /* nr of 32-bit words.. */
count >>= 1; /* nr of 32-bit words.. */
if (count)
{
if (4 & (size_t) buff)
if (4 & (size_t)buff)
{
result += *(uint32_t *) buff;
result += *(uint32_t *)buff;
count--;
len -= 4;
buff += 4;
}
count >>= 1; /* nr of 64-bit words.. */
count >>= 1; /* nr of 64-bit words.. */
if (count)
{
do
{
w = *(uint64_t *) buff;
w = *(uint64_t *)buff;
count--;
buff += 8;
result += carry;
@ -71,13 +72,13 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
}
if (len & 4)
{
result += *(uint32_t *) buff;
result += *(uint32_t *)buff;
buff += 4;
}
}
if (len & 2)
{
result += *(uint16_t *) buff;
result += *(uint16_t *)buff;
buff += 2;
}
}
@ -85,54 +86,54 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
{
// any endian compatible
u16 = 0;
*(uint8_t*)&u16 = *buff;
*(uint8_t *)&u16 = *buff;
result += u16;
}
u16 = from64to16(result);
if (odd) u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8);
if (odd)
u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8);
return u16;
}
uint16_t csum_partial(const void *buff, size_t len)
{
return do_csum(buff,len);
return do_csum(buff, len);
}
uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum)
{
return ~from64to16((uint64_t)saddr + daddr + sum + htonl(len+proto));
return ~from64to16((uint64_t)saddr + daddr + sum + htonl(len + proto));
}
uint16_t ip4_compute_csum(const void *buff, size_t len)
{
return ~from64to16(do_csum(buff,len));
return ~from64to16(do_csum(buff, len));
}
void ip4_fix_checksum(struct ip *ip)
{
ip->ip_sum = 0;
ip->ip_sum = ip4_compute_csum(ip, ip->ip_hl<<2);
ip->ip_sum = ip4_compute_csum(ip, ip->ip_hl << 2);
}
uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum)
{
uint64_t a = (uint64_t)sum + htonl(len+proto) +
*(uint32_t*)saddr + *((uint32_t*)saddr+1) + *((uint32_t*)saddr+2) + *((uint32_t*)saddr+3) +
*(uint32_t*)daddr + *((uint32_t*)daddr+1) + *((uint32_t*)daddr+2) + *((uint32_t*)daddr+3);
uint64_t a = (uint64_t)sum + htonl(len + proto) +
*(uint32_t *)saddr + *((uint32_t *)saddr + 1) + *((uint32_t *)saddr + 2) + *((uint32_t *)saddr + 3) +
*(uint32_t *)daddr + *((uint32_t *)daddr + 1) + *((uint32_t *)daddr + 2) + *((uint32_t *)daddr + 3);
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 = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_TCP,csum_partial(tcp,len));
tcp->th_sum = csum_tcpudp_magic(src_addr->s_addr, dest_addr->s_addr, len, IPPROTO_TCP, csum_partial(tcp, len));
}
void tcp6_fix_checksum(struct tcphdr *tcp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
void tcp6_fix_checksum(struct tcphdr *tcp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
{
tcp->th_sum = 0;
tcp->th_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp,len));
tcp->th_sum = csum_ipv6_magic(src_addr, dest_addr, len, IPPROTO_TCP, csum_partial(tcp, len));
}
void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr)
void tcp_fix_checksum(struct tcphdr *tcp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr)
{
if (ip)
tcp4_fix_checksum(tcp, len, &ip->ip_src, &ip->ip_dst);
@ -140,17 +141,17 @@ void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const st
tcp6_fix_checksum(tcp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
}
void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
void udp4_fix_checksum(struct udphdr *udp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
{
udp->uh_sum = 0;
udp->uh_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_UDP,csum_partial(udp,len));
udp->uh_sum = csum_tcpudp_magic(src_addr->s_addr, dest_addr->s_addr, len, IPPROTO_UDP, csum_partial(udp, len));
}
void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
void udp6_fix_checksum(struct udphdr *udp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
{
udp->uh_sum = 0;
udp->uh_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_UDP,csum_partial(udp,len));
udp->uh_sum = csum_ipv6_magic(src_addr, dest_addr, len, IPPROTO_UDP, csum_partial(udp, len));
}
void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr)
void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr)
{
if (ip)
udp4_fix_checksum(udp, len, &ip->ip_src, &ip->ip_dst);

View File

@ -18,10 +18,10 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8
uint16_t ip4_compute_csum(const void *buff, size_t len);
void ip4_fix_checksum(struct ip *ip);
void tcp4_fix_checksum(struct tcphdr *tcp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void tcp6_fix_checksum(struct tcphdr *tcp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr);
void tcp4_fix_checksum(struct tcphdr *tcp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void tcp6_fix_checksum(struct tcphdr *tcp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void tcp_fix_checksum(struct tcphdr *tcp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr);
void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr);
void udp4_fix_checksum(struct udphdr *udp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void udp6_fix_checksum(struct udphdr *udp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr);

View File

@ -12,11 +12,11 @@ static void ut_oom_recover(void *elem)
oom = true;
}
static const char *connstate_s[]={"SYN","ESTABLISHED","FIN"};
static const char *connstate_s[] = {"SYN", "ESTABLISHED", "FIN"};
static void connswap(const t_conn *c, t_conn *c2)
{
memset(c2,0,sizeof(*c2));
memset(c2, 0, sizeof(*c2));
c2->l3proto = c->l3proto;
c2->l4proto = c->l4proto;
c2->src = c->dst;
@ -49,7 +49,11 @@ static void ConntrackFreeElem(t_conntrack_pool *elem)
static void ConntrackPoolDestroyPool(t_conntrack_pool **pp)
{
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)
{
@ -61,7 +65,7 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s
p->timeout_syn = timeout_syn;
p->timeout_established = timeout_established;
p->timeout_fin = timeout_fin;
p->timeout_udp= timeout_udp;
p->timeout_udp = timeout_udp;
p->t_purge_interval = purge_interval;
time(&p->t_last_purge);
p->pool = NULL;
@ -69,7 +73,7 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s
void ConntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{
memset(c,0,sizeof(*c));
memset(c, 0, sizeof(*c));
if (ip)
{
c->l3proto = IPPROTO_IP;
@ -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);
}
static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *c)
{
t_conntrack_pool *t;
@ -97,7 +100,7 @@ static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *
static void ConntrackInitTrack(t_ctrack *t)
{
memset(t,0,sizeof(*t));
memset(t, 0, sizeof(*t));
t->scale_orig = t->scale_reply = SCALE_NONE;
time(&t->t_start);
rawpacket_queue_init(&t->delayed);
@ -111,11 +114,16 @@ static void ConntrackReInitTrack(t_ctrack *t)
static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c)
{
t_conntrack_pool *ctnew;
if (!(ctnew = malloc(sizeof(*ctnew)))) return NULL;
if (!(ctnew = malloc(sizeof(*ctnew))))
return NULL;
ctnew->conn = *c;
oom = false;
HASH_ADD(hh, *pp, conn, sizeof(*c), ctnew);
if (oom) { free(ctnew); return NULL; }
if (oom)
{
free(ctnew);
return NULL;
}
ConntrackInitTrack(&ctnew->track);
return ctnew;
}
@ -128,38 +136,41 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (bReverse)
{
t->pcounter_reply++;
t->pdcounter_reply+=!!len_payload;
t->pdcounter_reply += !!len_payload;
}
else
{
t->pcounter_orig++;
t->pdcounter_orig+=!!len_payload;
t->pdcounter_orig += !!len_payload;
}
if (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);
}
else if (tcp_synack_segment(tcphdr))
{
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry
if (!t->seq0) t->seq0 = ntohl(tcphdr->th_ack)-1;
if (t->state != SYN)
ConntrackReInitTrack(t); // erase current entry
if (!t->seq0)
t->seq0 = ntohl(tcphdr->th_ack) - 1;
t->ack0 = ntohl(tcphdr->th_seq);
}
else if (tcphdr->th_flags & (TH_FIN|TH_RST))
else if (tcphdr->th_flags & (TH_FIN | TH_RST))
{
t->state = FIN;
}
else
{
if (t->state==SYN)
if (t->state == SYN)
{
t->state=ESTABLISHED;
if (!bReverse && !t->ack0) t->ack0 = ntohl(tcphdr->th_ack)-1;
t->state = ESTABLISHED;
if (!bReverse && !t->ack0)
t->ack0 = ntohl(tcphdr->th_ack) - 1;
}
}
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->pos_reply = t->ack_last + len_payload;
t->winsize_reply = ntohs(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_reply = scale;
if (scale != SCALE_NONE)
t->scale_reply = scale;
}
else
{
@ -178,20 +189,21 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
t->pos_orig = t->seq_last + len_payload;
t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack);
t->winsize_orig = ntohs(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_orig = scale;
if (scale != SCALE_NONE)
t->scale_orig = scale;
}
}
else
{
if (bReverse)
{
t->ack_last=t->pos_reply;
t->pos_reply+=len_payload;
t->ack_last = t->pos_reply;
t->pos_reply += len_payload;
}
else
{
t->seq_last=t->pos_orig;
t->pos_orig+=len_payload;
t->seq_last = t->pos_orig;
t->pos_orig += len_payload;
}
}
@ -200,23 +212,27 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, t_ctrack **ctrack, bool *bReverse)
{
t_conn conn,connswp;
t_conn conn, connswp;
t_conntrack_pool *ctr;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr);
if ((ctr=ConntrackPoolSearch(*pp,&conn)))
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
{
if (bReverse) *bReverse = false;
if (ctrack) *ctrack = &ctr->track;
if (bReverse)
*bReverse = false;
if (ctrack)
*ctrack = &ctr->track;
return true;
}
else
{
connswap(&conn,&connswp);
if ((ctr=ConntrackPoolSearch(*pp,&connswp)))
connswap(&conn, &connswp);
if ((ctr = ConntrackPoolSearch(*pp, &connswp)))
{
if (bReverse) *bReverse = true;
if (ctrack) *ctrack = &ctr->track;
if (bReverse)
*bReverse = true;
if (ctrack)
*ctrack = &ctr->track;
return true;
}
}
@ -233,25 +249,25 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co
t_conntrack_pool *ctr;
bool b_rev;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr);
if ((ctr=ConntrackPoolSearch(*pp,&conn)))
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
{
ConntrackFeedPacket(&ctr->track, (b_rev=false), tcphdr, len_payload);
ConntrackFeedPacket(&ctr->track, (b_rev = false), tcphdr, len_payload);
goto ok;
}
else
{
connswap(&conn,&connswp);
if ((ctr=ConntrackPoolSearch(*pp,&connswp)))
connswap(&conn, &connswp);
if ((ctr = ConntrackPoolSearch(*pp, &connswp)))
{
ConntrackFeedPacket(&ctr->track, (b_rev=true), tcphdr, len_payload);
ConntrackFeedPacket(&ctr->track, (b_rev = true), tcphdr, len_payload);
goto ok;
}
}
b_rev = tcphdr && tcp_synack_segment(tcphdr);
if ((tcphdr && tcp_syn_segment(tcphdr)) || b_rev || udphdr)
{
if ((ctr=ConntrackNew(pp, b_rev ? &connswp : &conn)))
if ((ctr = ConntrackNew(pp, b_rev ? &connswp : &conn)))
{
ConntrackFeedPacket(&ctr->track, b_rev, tcphdr, len_payload);
goto ok;
@ -259,32 +275,36 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co
}
return false;
ok:
if (ctrack) *ctrack = &ctr->track;
if (bReverse) *bReverse = b_rev;
if (ctrack)
*ctrack = &ctr->track;
if (bReverse)
*bReverse = b_rev;
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)
{
return ConntrackPoolFeedPool(&p->pool,ip,ip6,tcphdr,udphdr,len_payload,ctrack,bReverse);
return ConntrackPoolFeedPool(&p->pool, ip, ip6, tcphdr, udphdr, len_payload, ctrack, bReverse);
}
static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{
t_conn conn, connswp;
t_conntrack_pool *t;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr);
if (!(t=ConntrackPoolSearch(*pp,&conn)))
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
if (!(t = ConntrackPoolSearch(*pp, &conn)))
{
connswap(&conn,&connswp);
t=ConntrackPoolSearch(*pp,&connswp);
connswap(&conn, &connswp);
t = ConntrackPoolSearch(*pp, &connswp);
}
if (!t) return false;
HASH_DEL(*pp, t); ConntrackFreeElem(t);
if (!t)
return false;
HASH_DEL(*pp, t);
ConntrackFreeElem(t);
return true;
}
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{
return ConntrackPoolDropPool(&p->pool,ip,ip6,tcphdr,udphdr);
return ConntrackPoolDropPool(&p->pool, ip, ip6, tcphdr, udphdr);
}
void ConntrackPoolPurge(t_conntrack *p)
@ -292,19 +312,19 @@ void ConntrackPoolPurge(t_conntrack *p)
time_t tidle, tnow = time(NULL);
t_conntrack_pool *t, *tmp;
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;
if ( t->track.b_cutoff ||
(t->conn.l4proto==IPPROTO_TCP && (
(t->track.state==SYN && tidle>=p->timeout_syn) ||
(t->track.state==ESTABLISHED && tidle>=p->timeout_established) ||
(t->track.state==FIN && tidle>=p->timeout_fin))
) || (t->conn.l4proto==IPPROTO_UDP && tidle>=p->timeout_udp)
)
if (t->track.b_cutoff ||
(t->conn.l4proto == IPPROTO_TCP && ((t->track.state == SYN && tidle >= p->timeout_syn) ||
(t->track.state == ESTABLISHED && tidle >= p->timeout_established) ||
(t->track.state == FIN && tidle >= p->timeout_fin))) ||
(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;
@ -313,52 +333,59 @@ void ConntrackPoolPurge(t_conntrack *p)
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)
{
switch(proto)
switch (proto)
{
case HTTP: return "HTTP";
case TLS: return "TLS";
case QUIC: return "QUIC";
case WIREGUARD: return "WIREGUARD";
case DHT: return "DHT";
default: return "UNKNOWN";
case HTTP:
return "HTTP";
case TLS:
return "TLS";
case QUIC:
return "QUIC";
case WIREGUARD:
return "WIREGUARD";
case DHT:
return "DHT";
default:
return "UNKNOWN";
}
}
void ConntrackPoolDump(const t_conntrack *p)
{
t_conntrack_pool *t, *tmp;
char sa1[40],sa2[40];
char sa1[40], sa2[40];
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.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 ",
proto_name(t->conn.l4proto),
sa1, t->conn.sport, sa2, t->conn.dport,
t->conn.l4proto==IPPROTO_TCP ? connstate_s[t->track.state] : "-",
(unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last),
(unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig,
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply);
if (t->conn.l4proto==IPPROTO_TCP)
proto_name(t->conn.l4proto),
sa1, t->conn.sport, sa2, t->conn.dport,
t->conn.l4proto == IPPROTO_TCP ? connstate_s[t->track.state] : "-",
(unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last),
(unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig,
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply);
if (t->conn.l4proto == IPPROTO_TCP)
printf("seq0=%u rseq=%u pos_orig=%u ack0=%u rack=%u pos_reply=%u wsize_orig=%u:%d wsize_reply=%u:%d",
t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0,
t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0,
t->track.winsize_orig, t->track.scale_orig==SCALE_NONE ? -1 : t->track.scale_orig,
t->track.winsize_reply, t->track.scale_reply==SCALE_NONE ? -1 : t->track.scale_reply);
t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0,
t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0,
t->track.winsize_orig, t->track.scale_orig == SCALE_NONE ? -1 : t->track.scale_orig,
t->track.winsize_reply, t->track.scale_reply == SCALE_NONE ? -1 : t->track.scale_reply);
else
printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u",
t->track.seq_last, t->track.pos_orig,
t->track.ack_last, t->track.pos_reply);
t->track.seq_last, t->track.pos_orig,
t->track.ack_last, t->track.pos_reply);
printf(" req_retrans=%u cutoff=%u wss_cutoff=%u d_cutoff=%u hostname=%s l7proto=%s\n",
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, ConntrackProtoName(t->track.l7proto));
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, ConntrackProtoName(t->track.l7proto));
};
}
void ReasmClear(t_reassemble *reasm)
{
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)
{
reasm->packet = malloc(size_requested);
if (!reasm->packet) return false;
if (!reasm->packet)
return false;
reasm->size = size_requested;
reasm->size_present = 0;
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)
{
uint8_t *p = realloc(reasm->packet, new_size);
if (!p) return false;
if (!p)
return false;
reasm->packet = p;
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;
}
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;
szcopy = reasm->size - reasm->size_present;
if (len<szcopy) szcopy = len;
if (len < szcopy)
szcopy = len;
memcpy(reasm->packet + reasm->size_present, payload, szcopy);
reasm->size_present += szcopy;
reasm->seq += (uint32_t)szcopy;
@ -401,5 +433,5 @@ bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t le
}
bool ReasmHasSpace(t_reassemble *reasm, size_t len)
{
return (reasm->size_present+len)<=reasm->size;
return (reasm->size_present + len) <= reasm->size;
}

View File

@ -1,6 +1,5 @@
#pragma once
// this conntrack is not bullet-proof
// its designed to satisfy dpi desync needs only
@ -19,68 +18,82 @@
#include <netinet/tcp.h>
#include <netinet/udp.h>
//#define HASH_BLOOM 20
// #define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1
#undef HASH_FUNCTION
#define HASH_FUNCTION HASH_BER
#include "uthash.h"
#define RETRANS_COUNTER_STOP ((uint8_t)-1)
#define RETRANS_COUNTER_STOP ((uint8_t) - 1)
typedef union {
typedef union
{
struct in_addr ip;
struct in6_addr ip6;
} t_addr;
typedef struct
{
t_addr src, dst;
uint16_t sport,dport;
uint8_t l3proto; // IPPROTO_IP, IPPROTO_IPV6
uint16_t sport, dport;
uint8_t l3proto; // IPPROTO_IP, IPPROTO_IPV6
uint8_t l4proto; // IPPROTO_TCP, IPPROTO_UDP
} t_conn;
// this structure helps to reassemble continuous packets streams. it does not support out-of-orders
typedef struct {
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.
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
size_t size_present; // how many bytes already stored in 'packet'
typedef struct
{
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.
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
size_t size_present; // how many bytes already stored in 'packet'
} t_reassemble;
// SYN - SYN or SYN/ACK received
// ESTABLISHED - any except SYN or SYN/ACK received
// FIN - FIN or RST received
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
typedef enum
{
SYN = 0,
ESTABLISHED,
FIN
} t_connstate;
typedef enum
{
UNKNOWN = 0,
HTTP,
TLS,
QUIC,
WIREGUARD,
DHT
} t_l7proto;
typedef struct
{
// common state
time_t t_start, t_last;
uint64_t pcounter_orig, pcounter_reply; // packet counter
uint64_t pcounter_orig, pcounter_reply; // packet counter
uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload)
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
// tcp only state, not used in udp
t_connstate state;
uint32_t seq0, ack0; // starting seq and ack
uint16_t winsize_orig, winsize_reply; // last seen window size
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
uint8_t req_retrans_counter; // number of request retransmissions
bool req_seq_present,req_seq_finalized,req_seq_abandoned;
uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions)
uint32_t seq0, ack0; // starting seq and ack
uint16_t winsize_orig, winsize_reply; // last seen window size
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
uint8_t req_retrans_counter; // number of request retransmissions
bool req_seq_present, req_seq_finalized, req_seq_abandoned;
uint32_t req_seq_start, req_seq_end; // sequence interval of the request (to track retransmissions)
uint8_t autottl;
bool b_cutoff; // mark for deletion
bool b_cutoff; // mark for deletion
bool b_wssize_cutoff, b_desync_cutoff;
t_l7proto l7proto;
char *hostname;
bool hostname_ah_check; // should perform autohostlist checks
bool hostname_ah_check; // should perform autohostlist checks
t_reassemble reasm_orig;
struct rawpacket_tailhead delayed;
} t_ctrack;
@ -88,13 +101,13 @@ typedef struct
typedef struct
{
t_ctrack track;
UT_hash_handle hh; // makes this structure hashable
t_conn conn; // key
UT_hash_handle hh; // makes this structure hashable
t_conn conn; // key
} t_conntrack_pool;
typedef struct
{
// inactivity time to purge an entry in each connection state
uint32_t timeout_syn,timeout_established,timeout_fin,timeout_udp;
uint32_t timeout_syn, timeout_established, timeout_fin, timeout_udp;
time_t t_purge_interval, t_last_purge;
t_conntrack_pool *pool;
} t_conntrack;
@ -117,5 +130,5 @@ void ReasmClear(t_reassemble *reasm);
bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len);
// check if it has enough space to buffer 'len' bytes
bool ReasmHasSpace(t_reassemble *reasm, size_t len);
inline static bool ReasmIsEmpty(t_reassemble *reasm) {return !reasm->size;}
inline static bool ReasmIsFull(t_reassemble *reasm) {return !ReasmIsEmpty(reasm) && (reasm->size==reasm->size_present);}
inline static bool ReasmIsEmpty(t_reassemble *reasm) { return !reasm->size; }
inline static bool ReasmIsFull(t_reassemble *reasm) { return !ReasmIsEmpty(reasm) && (reasm->size == reasm->size_present); }

View File

@ -1,6 +1,6 @@
#pragma once
#include "gcm.h"
#include "gcm.h"
// mode : AES_ENCRYPT, AES_DECRYPT
int aes_gcm_crypt(int mode, uint8_t *output, const uint8_t *input, size_t input_length, const uint8_t *key, const size_t key_len, const uint8_t *iv, const size_t iv_len, const uint8_t *adata, size_t adata_len, uint8_t *atag, size_t atag_len);

View File

@ -1,29 +1,29 @@
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#include "aes.h"
static int aes_tables_inited = 0; // run-once flag for performing key
// expasion table generation (see below)
static int aes_tables_inited = 0; // run-once flag for performing key
// expasion table generation (see below)
/*
* The following static local tables must be filled-in before the first use of
* the GCM or AES ciphers. They are used for the AES key expansion/scheduling
@ -37,175 +37,189 @@ static int aes_tables_inited = 0; // run-once flag for performing key
* the GCM input, we ONLY NEED AES encryption. Thus, to save space AES
* decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
*/
// We always need our forward tables
static uchar FSb[256]; // Forward substitution box (FSb)
static uint32_t FT0[256]; // Forward key schedule assembly tables
// We always need our forward tables
static uchar FSb[256]; // Forward substitution box (FSb)
static uint32_t FT0[256]; // Forward key schedule assembly tables
static uint32_t FT1[256];
static uint32_t FT2[256];
static uint32_t FT3[256];
#if AES_DECRYPTION // We ONLY need reverse for decryption
static uchar RSb[256]; // Reverse substitution box (RSb)
static uint32_t RT0[256]; // Reverse key schedule assembly tables
#if AES_DECRYPTION // We ONLY need reverse for decryption
static uchar RSb[256]; // Reverse substitution box (RSb)
static uint32_t RT0[256]; // Reverse key schedule assembly tables
static uint32_t RT1[256];
static uint32_t RT2[256];
static uint32_t RT3[256];
#endif /* AES_DECRYPTION */
#endif /* AES_DECRYPTION */
static uint32_t RCON[10]; // AES round constants
static uint32_t RCON[10]; // AES round constants
/*
* Platform Endianness Neutralizing Load and Store Macro definitions
* AES wants platform-neutral Little Endian (LE) byte ordering
*/
#define GET_UINT32_LE(n,b,i) { \
(n) = ( (uint32_t) (b)[(i) ] ) \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
| ( (uint32_t) (b)[(i) + 3] << 24 ); }
#define GET_UINT32_LE(n, b, i) \
{ \
(n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \
}
#define PUT_UINT32_LE(n,b,i) { \
(b)[(i) ] = (uchar) ( (n) ); \
(b)[(i) + 1] = (uchar) ( (n) >> 8 ); \
(b)[(i) + 2] = (uchar) ( (n) >> 16 ); \
(b)[(i) + 3] = (uchar) ( (n) >> 24 ); }
#define PUT_UINT32_LE(n, b, i) \
{ \
(b)[(i)] = (uchar)((n)); \
(b)[(i) + 1] = (uchar)((n) >> 8); \
(b)[(i) + 2] = (uchar)((n) >> 16); \
(b)[(i) + 3] = (uchar)((n) >> 24); \
}
/*
* AES forward and reverse encryption round processing macros
*/
#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
{ \
X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \
FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y3 >> 24 ) & 0xFF ]; \
\
X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \
FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y0 >> 24 ) & 0xFF ]; \
\
X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \
FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y1 >> 24 ) & 0xFF ]; \
\
X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \
FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y2 >> 24 ) & 0xFF ]; \
}
/*
* AES forward and reverse encryption round processing macros
*/
#define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \
X0 = *RK++ ^ FT0[(Y0) & 0xFF] ^ \
FT1[(Y1 >> 8) & 0xFF] ^ \
FT2[(Y2 >> 16) & 0xFF] ^ \
FT3[(Y3 >> 24) & 0xFF]; \
\
X1 = *RK++ ^ FT0[(Y1) & 0xFF] ^ \
FT1[(Y2 >> 8) & 0xFF] ^ \
FT2[(Y3 >> 16) & 0xFF] ^ \
FT3[(Y0 >> 24) & 0xFF]; \
\
X2 = *RK++ ^ FT0[(Y2) & 0xFF] ^ \
FT1[(Y3 >> 8) & 0xFF] ^ \
FT2[(Y0 >> 16) & 0xFF] ^ \
FT3[(Y1 >> 24) & 0xFF]; \
\
X3 = *RK++ ^ FT0[(Y3) & 0xFF] ^ \
FT1[(Y0 >> 8) & 0xFF] ^ \
FT2[(Y1 >> 16) & 0xFF] ^ \
FT3[(Y2 >> 24) & 0xFF]; \
}
#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
{ \
X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \
RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y1 >> 24 ) & 0xFF ]; \
\
X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \
RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y2 >> 24 ) & 0xFF ]; \
\
X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \
RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y3 >> 24 ) & 0xFF ]; \
\
X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \
RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y0 >> 24 ) & 0xFF ]; \
}
#define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \
X0 = *RK++ ^ RT0[(Y0) & 0xFF] ^ \
RT1[(Y3 >> 8) & 0xFF] ^ \
RT2[(Y2 >> 16) & 0xFF] ^ \
RT3[(Y1 >> 24) & 0xFF]; \
\
X1 = *RK++ ^ RT0[(Y1) & 0xFF] ^ \
RT1[(Y0 >> 8) & 0xFF] ^ \
RT2[(Y3 >> 16) & 0xFF] ^ \
RT3[(Y2 >> 24) & 0xFF]; \
\
X2 = *RK++ ^ RT0[(Y2) & 0xFF] ^ \
RT1[(Y1 >> 8) & 0xFF] ^ \
RT2[(Y0 >> 16) & 0xFF] ^ \
RT3[(Y3 >> 24) & 0xFF]; \
\
X3 = *RK++ ^ RT0[(Y3) & 0xFF] ^ \
RT1[(Y2 >> 8) & 0xFF] ^ \
RT2[(Y1 >> 16) & 0xFF] ^ \
RT3[(Y0 >> 24) & 0xFF]; \
}
/*
* These macros improve the readability of the key
* generation initialization code by collapsing
* repetitive common operations into logical pieces.
*/
#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 )
#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) )
#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 CPY128 { *RK++ = *SK++; *RK++ = *SK++; \
*RK++ = *SK++; *RK++ = *SK++; }
/*
* These macros improve the readability of the key
* generation initialization code by collapsing
* repetitive common operations into logical pieces.
*/
#define ROTL8(x) ((x << 8) & 0xFFFFFFFF) | (x >> 24)
#define XTIME(x) ((x << 1) ^ ((x & 0x80) ? 0x1B : 0x00))
#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 CPY128 \
{ \
*RK++ = *SK++; \
*RK++ = *SK++; \
*RK++ = *SK++; \
*RK++ = *SK++; \
}
/******************************************************************************
*
* AES_INIT_KEYGEN_TABLES
*
* Fills the AES key expansion tables allocated above with their static
* data. This is not "per key" data, but static system-wide read-only
* table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once
* at system initialization to setup the tables for all subsequent use.
*
******************************************************************************/
/******************************************************************************
*
* AES_INIT_KEYGEN_TABLES
*
* Fills the AES key expansion tables allocated above with their static
* data. This is not "per key" data, but static system-wide read-only
* table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once
* at system initialization to setup the tables for all subsequent use.
*
******************************************************************************/
void aes_init_keygen_tables(void)
{
int i, x, y, z; // general purpose iteration and computation locals
int i, x, y, z; // general purpose iteration and computation locals
int pow[256];
int log[256];
if (aes_tables_inited) return;
if (aes_tables_inited)
return;
// 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;
log[x] = i;
x = (x ^ XTIME(x)) & 0xFF;
}
// 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;
x = XTIME(x) & 0xFF;
}
// fill the forward and reverse substitution boxes
FSb[0x00] = 0x63;
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
RSb[0x63] = 0x00;
#endif /* AES_DECRYPTION */
for (i = 1; i < 256; i++) {
for (i = 1; i < 256; i++)
{
x = y = pow[255 - log[i]];
MIX(x, y);
MIX(x, y);
MIX(x, y);
MIX(x, y);
FSb[i] = (uchar)(x ^= 0x63);
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
RSb[x] = (uchar)i;
#endif /* AES_DECRYPTION */
}
// generate the forward and reverse key expansion tables
for (i = 0; i < 256; i++) {
for (i = 0; i < 256; i++)
{
x = FSb[i];
y = XTIME(x) & 0xFF;
z = (y ^ x) & 0xFF;
FT0[i] = ((uint32_t)y) ^ ((uint32_t)x << 8) ^
((uint32_t)x << 16) ^ ((uint32_t)z << 24);
((uint32_t)x << 16) ^ ((uint32_t)z << 24);
FT1[i] = ROTL8(FT0[i]);
FT2[i] = ROTL8(FT1[i]);
FT3[i] = ROTL8(FT2[i]);
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
x = RSb[i];
RT0[i] = ((uint32_t)MUL(0x0E, x)) ^
((uint32_t)MUL(0x09, x) << 8) ^
((uint32_t)MUL(0x0D, x) << 16) ^
((uint32_t)MUL(0x0B, x) << 24);
((uint32_t)MUL(0x09, x) << 8) ^
((uint32_t)MUL(0x0D, x) << 16) ^
((uint32_t)MUL(0x0B, x) << 24);
RT1[i] = ROTL8(RT0[i]);
RT2[i] = ROTL8(RT1[i]);
RT3[i] = ROTL8(RT2[i]);
#endif /* AES_DECRYPTION */
}
aes_tables_inited = 1; // flag that the tables have been generated
} // to permit subsequent use of the AES cipher
aes_tables_inited = 1; // flag that the tables have been generated
} // to permit subsequent use of the AES cipher
/******************************************************************************
*
@ -218,25 +232,27 @@ void aes_init_keygen_tables(void)
*
******************************************************************************/
int aes_set_encryption_key(aes_context *ctx,
const uchar *key,
uint keysize)
const uchar *key,
uint keysize)
{
uint i; // general purpose iteration local
uint i; // general purpose iteration local
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);
}
switch (ctx->rounds)
{
case 10:
for (i = 0; i < 10; i++, RK += 4) {
for (i = 0; i < 10; i++, RK += 4)
{
RK[4] = RK[0] ^ RCON[i] ^
((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[3]) & 0xFF] << 24);
((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[3]) & 0xFF] << 24);
RK[5] = RK[1] ^ RK[4];
RK[6] = RK[2] ^ RK[5];
@ -245,12 +261,13 @@ int aes_set_encryption_key(aes_context *ctx,
break;
case 12:
for (i = 0; i < 8; i++, RK += 6) {
for (i = 0; i < 8; i++, RK += 6)
{
RK[6] = RK[0] ^ RCON[i] ^
((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[5]) & 0xFF] << 24);
((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[5]) & 0xFF] << 24);
RK[7] = RK[1] ^ RK[6];
RK[8] = RK[2] ^ RK[7];
@ -261,22 +278,23 @@ int aes_set_encryption_key(aes_context *ctx,
break;
case 14:
for (i = 0; i < 7; i++, RK += 8) {
for (i = 0; i < 7; i++, RK += 8)
{
RK[8] = RK[0] ^ RCON[i] ^
((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[7]) & 0xFF] << 24);
((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[7]) & 0xFF] << 24);
RK[9] = RK[1] ^ RK[8];
RK[10] = RK[2] ^ RK[9];
RK[11] = RK[3] ^ RK[10];
RK[12] = RK[4] ^
((uint32_t)FSb[(RK[11]) & 0xFF]) ^
((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24);
((uint32_t)FSb[(RK[11]) & 0xFF]) ^
((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24);
RK[13] = RK[5] ^ RK[12];
RK[14] = RK[6] ^ RK[13];
@ -287,10 +305,10 @@ int aes_set_encryption_key(aes_context *ctx,
default:
return -1;
}
return(0);
return (0);
}
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
/******************************************************************************
*
@ -303,36 +321,38 @@ int aes_set_encryption_key(aes_context *ctx,
*
******************************************************************************/
int aes_set_decryption_key(aes_context *ctx,
const uchar *key,
uint keysize)
const uchar *key,
uint keysize)
{
int i, j;
aes_context cty; // a calling aes context for set_encryption_key
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
aes_context cty; // a calling aes context for set_encryption_key
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
uint32_t *SK;
int ret;
cty.rounds = ctx->rounds; // initialize our local aes context
cty.rk = cty.buf; // round count and key buf pointer
cty.rounds = ctx->rounds; // initialize our local aes context
cty.rk = cty.buf; // round count and key buf pointer
if ((ret = aes_set_encryption_key(&cty, key, keysize)) != 0)
return(ret);
return (ret);
SK = cty.rk + cty.rounds * 4;
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 (j = 0; j < 4; j++, SK++) {
*RK++ = RT0[FSb[(*SK) & 0xFF]] ^
for (i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8)
{
for (j = 0; j < 4; j++, SK++)
{
*RK++ = RT0[FSb[(*SK) & 0xFF]] ^
RT1[FSb[(*SK >> 8) & 0xFF]] ^
RT2[FSb[(*SK >> 16) & 0xFF]] ^
RT3[FSb[(*SK >> 24) & 0xFF]];
}
}
CPY128 // copy a 128-bit block from *SK to *RK
memset(&cty, 0, sizeof(aes_context)); // clear local aes context
return(0);
}
CPY128 // copy a 128-bit block from *SK to *RK
memset(&cty, 0, sizeof(aes_context)); // clear local aes context
return (0);
}
#endif /* AES_DECRYPTION */
@ -344,34 +364,42 @@ int aes_set_decryption_key(aes_context *ctx,
* Invoked to establish the key schedule for subsequent encryption/decryption
*
******************************************************************************/
int aes_setkey(aes_context *ctx, // AES context provided by our caller
int mode, // ENCRYPT or DECRYPT flag
const uchar *key, // pointer to the key
uint keysize) // key length in bytes
int aes_setkey(aes_context *ctx, // AES context provided by our caller
int mode, // ENCRYPT or DECRYPT flag
const uchar *key, // pointer to the key
uint keysize) // key length in bytes
{
// since table initialization is not thread safe, we could either add
// system-specific mutexes and init the AES key generation tables on
// demand, or ask the developer to simply call "gcm_initialize" once during
// 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->rk = ctx->buf; // initialize our round key pointer
ctx->mode = mode; // capture the key type we're creating
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 24: ctx->rounds = 12; break; // 24-byte, 192-bit key
case 32: ctx->rounds = 14; break; // 32-byte, 256-bit key
default: return(-1);
case 16:
ctx->rounds = 10;
break; // 16-byte, 128-bit key
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 (mode == DECRYPT) // expand our key for encryption or decryption
return(aes_set_decryption_key(ctx, key, keysize));
else /* ENCRYPT */
#endif /* AES_DECRYPTION */
return(aes_set_encryption_key(ctx, key, keysize));
if (mode == DECRYPT) // expand our key for encryption or decryption
return (aes_set_decryption_key(ctx, key, keysize));
else /* ENCRYPT */
#endif /* AES_DECRYPTION */
return (aes_set_encryption_key(ctx, key, keysize));
}
/******************************************************************************
@ -384,20 +412,24 @@ int aes_setkey(aes_context *ctx, // AES context provided by our caller
*
******************************************************************************/
int aes_cipher(aes_context *ctx,
const uchar input[16],
uchar output[16])
const uchar input[16],
uchar output[16])
{
int i;
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals
RK = ctx->rk;
GET_UINT32_LE(X0, input, 0); X0 ^= *RK++; // load our 128-bit
GET_UINT32_LE(X1, input, 4); 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++;
GET_UINT32_LE(X0, input, 0);
X0 ^= *RK++; // load our 128-bit
GET_UINT32_LE(X1, input, 4);
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
if (ctx->mode == DECRYPT)
{
@ -409,29 +441,29 @@ int aes_cipher(aes_context *ctx,
AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ \
((uint32_t)RSb[(Y0) & 0xFF]) ^
((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24);
X0 = *RK++ ^
((uint32_t)RSb[(Y0) & 0xFF]) ^
((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24);
X1 = *RK++ ^ \
((uint32_t)RSb[(Y1) & 0xFF]) ^
((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24);
X1 = *RK++ ^
((uint32_t)RSb[(Y1) & 0xFF]) ^
((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24);
X2 = *RK++ ^ \
((uint32_t)RSb[(Y2) & 0xFF]) ^
((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24);
X2 = *RK++ ^
((uint32_t)RSb[(Y2) & 0xFF]) ^
((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24);
X3 = *RK++ ^ \
((uint32_t)RSb[(Y3) & 0xFF]) ^
((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24);
X3 = *RK++ ^
((uint32_t)RSb[(Y3) & 0xFF]) ^
((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24);
}
else /* ENCRYPT */
{
@ -445,31 +477,31 @@ int aes_cipher(aes_context *ctx,
AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ \
((uint32_t)FSb[(Y0) & 0xFF]) ^
((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24);
X0 = *RK++ ^
((uint32_t)FSb[(Y0) & 0xFF]) ^
((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24);
X1 = *RK++ ^ \
((uint32_t)FSb[(Y1) & 0xFF]) ^
((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24);
X1 = *RK++ ^
((uint32_t)FSb[(Y1) & 0xFF]) ^
((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24);
X2 = *RK++ ^ \
((uint32_t)FSb[(Y2) & 0xFF]) ^
((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24);
X2 = *RK++ ^
((uint32_t)FSb[(Y2) & 0xFF]) ^
((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24);
X3 = *RK++ ^ \
((uint32_t)FSb[(Y3) & 0xFF]) ^
((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24);
X3 = *RK++ ^
((uint32_t)FSb[(Y3) & 0xFF]) ^
((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24);
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
}
#endif /* AES_DECRYPTION */
@ -478,6 +510,6 @@ int aes_cipher(aes_context *ctx,
PUT_UINT32_LE(X2, output, 8);
PUT_UINT32_LE(X3, output, 12);
return(0);
return (0);
}
/* end of aes.c */

View File

@ -1,35 +1,35 @@
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#pragma once
/******************************************************************************/
#define AES_DECRYPTION 0 // whether AES decryption is supported
#define AES_DECRYPTION 0 // whether AES decryption is supported
/******************************************************************************/
#include <string.h>
#define AES_ENCRYPT 1 // specify whether we're encrypting
#define AES_DECRYPT 0 // or decrypting
#define AES_ENCRYPT 1 // specify whether we're encrypting
#define AES_DECRYPT 0 // or decrypting
#if defined(_MSC_VER)
#include <basetsd.h>
@ -38,41 +38,39 @@ typedef UINT32 uint32_t;
#include <inttypes.h>
#endif
typedef unsigned char uchar; // add some convienent shorter types
typedef unsigned char uchar; // add some convienent shorter types
typedef unsigned int uint;
/******************************************************************************
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
******************************************************************************/
void aes_init_keygen_tables(void);
/******************************************************************************
* AES_CONTEXT : cipher context / holds inter-call data
******************************************************************************/
typedef struct {
int mode; // 1 for Encryption, 0 for Decryption
int rounds; // keysize-based rounds count
uint32_t *rk; // pointer to current round key
uint32_t buf[68]; // key expansion buffer
typedef struct
{
int mode; // 1 for Encryption, 0 for Decryption
int rounds; // keysize-based rounds count
uint32_t *rk; // pointer to current round key
uint32_t buf[68]; // key expansion buffer
} aes_context;
/******************************************************************************
* AES_SETKEY : called to expand the key for encryption or decryption
******************************************************************************/
int aes_setkey(aes_context *ctx, // pointer to context
int mode, // 1 or 0 for Encrypt/Decrypt
const uchar *key, // AES input key
uint keysize); // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
// returns 0 for success
int aes_setkey(aes_context *ctx, // pointer to context
int mode, // 1 or 0 for Encrypt/Decrypt
const uchar *key, // AES input key
uint keysize); // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
// returns 0 for success
/******************************************************************************
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
******************************************************************************/
int aes_cipher(aes_context *ctx, // pointer to context
const uchar input[16], // 128-bit block to en/decipher
uchar output[16]); // 128-bit output result block
// returns 0 for success
int aes_cipher(aes_context *ctx, // pointer to context
const uchar input[16], // 128-bit block to en/decipher
uchar output[16]); // 128-bit output result block
// returns 0 for success

View File

@ -1,26 +1,26 @@
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It
* should be endian (memory byte order) neutral since the few places that care
* are handled explicitly.
*
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/
* gcm/gcm-revised-spec.pdf
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It
* should be endian (memory byte order) neutral since the few places that care
* are handled explicitly.
*
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/
* gcm/gcm-revised-spec.pdf
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#include "gcm.h"
#include "aes.h"
@ -41,80 +41,79 @@
*
******************************************************************************/
/* Calculating the "GHASH"
*
* There are many ways of calculating the so-called GHASH in software, each with
* a traditional size vs performance tradeoff. The GHASH (Galois field hash) is
* an intriguing construction which takes two 128-bit strings (also the cipher's
* block size and the fundamental operation size for the system) and hashes them
* into a third 128-bit result.
*
* Many implementation solutions have been worked out that use large precomputed
* table lookups in place of more time consuming bit fiddling, and this approach
* can be scaled easily upward or downward as needed to change the time/space
* tradeoff. It's been studied extensively and there's a solid body of theory and
* practice. For example, without using any lookup tables an implementation
* might obtain 119 cycles per byte throughput, whereas using a simple, though
* large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13
* cycles per byte.
*
* And Intel's processors have, since 2010, included an instruction which does
* the entire 128x128->128 bit job in just several 64x64->128 bit pieces.
*
* Since SQRL is interactive, and only processing a few 128-bit blocks, I've
* settled upon a relatively slower but appealing small-table compromise which
* folds a bunch of not only time consuming but also bit twiddling into a simple
* 16-entry table which is attributed to Victor Shoup's 1996 work while at
* Bellcore: "On Fast and Provably Secure MessageAuthentication Based on
* Universal Hashing." See: http://www.shoup.net/papers/macs.pdf
* See, also section 4.1 of the "gcm-revised-spec" cited above.
*/
/* Calculating the "GHASH"
*
* There are many ways of calculating the so-called GHASH in software, each with
* a traditional size vs performance tradeoff. The GHASH (Galois field hash) is
* an intriguing construction which takes two 128-bit strings (also the cipher's
* block size and the fundamental operation size for the system) and hashes them
* into a third 128-bit result.
*
* Many implementation solutions have been worked out that use large precomputed
* table lookups in place of more time consuming bit fiddling, and this approach
* can be scaled easily upward or downward as needed to change the time/space
* tradeoff. It's been studied extensively and there's a solid body of theory and
* practice. For example, without using any lookup tables an implementation
* might obtain 119 cycles per byte throughput, whereas using a simple, though
* large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13
* cycles per byte.
*
* And Intel's processors have, since 2010, included an instruction which does
* the entire 128x128->128 bit job in just several 64x64->128 bit pieces.
*
* Since SQRL is interactive, and only processing a few 128-bit blocks, I've
* settled upon a relatively slower but appealing small-table compromise which
* folds a bunch of not only time consuming but also bit twiddling into a simple
* 16-entry table which is attributed to Victor Shoup's 1996 work while at
* Bellcore: "On Fast and Provably Secure MessageAuthentication Based on
* Universal Hashing." See: http://www.shoup.net/papers/macs.pdf
* See, also section 4.1 of the "gcm-revised-spec" cited above.
*/
/*
* This 16-entry table of pre-computed constants is used by the
* GHASH multiplier to improve over a strictly table-free but
* significantly slower 128x128 bit multiple within GF(2^128).
*/
/*
* This 16-entry table of pre-computed constants is used by the
* GHASH multiplier to improve over a strictly table-free but
* significantly slower 128x128 bit multiple within GF(2^128).
*/
static const uint64_t last4[16] = {
0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0 };
0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0};
/*
* Platform Endianness Neutralizing Load and Store Macro definitions
* GCM wants platform-neutral Big Endian (BE) byte ordering
*/
#define GET_UINT32_BE(n,b,i) { \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); }
#define GET_UINT32_BE(n, b, i) \
{ \
(n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); \
}
#define PUT_UINT32_BE(n,b,i) { \
(b)[(i) ] = (uchar) ( (n) >> 24 ); \
(b)[(i) + 1] = (uchar) ( (n) >> 16 ); \
(b)[(i) + 2] = (uchar) ( (n) >> 8 ); \
(b)[(i) + 3] = (uchar) ( (n) ); }
#define PUT_UINT32_BE(n, b, i) \
{ \
(b)[(i)] = (uchar)((n) >> 24); \
(b)[(i) + 1] = (uchar)((n) >> 16); \
(b)[(i) + 2] = (uchar)((n) >> 8); \
(b)[(i) + 3] = (uchar)((n)); \
}
/******************************************************************************
*
* GCM_INITIALIZE
*
* Must be called once to initialize the GCM library.
*
* At present, this only calls the AES keygen table generator, which expands
* the AES keying tables for use. This is NOT A THREAD-SAFE function, so it
* MUST be called during system initialization before a multi-threading
* environment is running.
*
******************************************************************************/
/******************************************************************************
*
* GCM_INITIALIZE
*
* Must be called once to initialize the GCM library.
*
* At present, this only calls the AES keygen table generator, which expands
* the AES keying tables for use. This is NOT A THREAD-SAFE function, so it
* MUST be called during system initialization before a multi-threading
* environment is running.
*
******************************************************************************/
int gcm_initialize(void)
{
aes_init_keygen_tables();
return(0);
return (0);
}
/******************************************************************************
*
* GCM_MULT
@ -124,9 +123,9 @@ int gcm_initialize(void)
* 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
*
******************************************************************************/
static void gcm_mult(gcm_context *ctx, // pointer to established context
const uchar x[16], // pointer to 128-bit input vector
uchar output[16]) // pointer to 128-bit output vector
static void gcm_mult(gcm_context *ctx, // pointer to established context
const uchar x[16], // pointer to 128-bit input vector
uchar output[16]) // pointer to 128-bit output vector
{
int i;
uchar lo, hi, rem;
@ -137,11 +136,13 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
zh = ctx->HH[lo];
zl = ctx->HL[lo];
for (i = 15; i >= 0; i--) {
for (i = 15; i >= 0; i--)
{
lo = (uchar)(x[i] & 0x0f);
hi = (uchar)(x[i] >> 4);
if (i != 15) {
if (i != 15)
{
rem = (uchar)(zl & 0x0f);
zl = (zh << 60) | (zl >> 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);
}
/******************************************************************************
*
* GCM_SETKEY
@ -172,26 +172,26 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
*
******************************************************************************/
int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
const uchar *key, // pointer to the AES encryption key
const uint keysize) // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
const uchar *key, // pointer to the AES encryption key
const uint keysize) // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
{
int ret, i, j;
uint64_t hi, lo;
uint64_t vl, vh;
unsigned char h[16];
memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context
memset(h, 0, 16); // initialize the block to encrypt
memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context
memset(h, 0, 16); // initialize the block to encrypt
// encrypt the null 128-bit block to generate a key-based value
// which is then used to initialize our GHASH lookup tables
if ((ret = aes_setkey(&ctx->aes_ctx, AES_ENCRYPT, key, keysize)) != 0)
return(ret);
return (ret);
if ((ret = aes_cipher(&ctx->aes_ctx, h, h)) != 0)
return(ret);
return (ret);
GET_UINT32_BE(hi, h, 0); // pack h as two 64-bit ints, big-endian
GET_UINT32_BE(hi, h, 0); // pack h as two 64-bit ints, big-endian
GET_UINT32_BE(lo, h, 4);
vh = (uint64_t)hi << 32 | lo;
@ -199,31 +199,33 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
GET_UINT32_BE(lo, h, 12);
vl = (uint64_t)hi << 32 | lo;
ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128)
ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128)
ctx->HH[8] = vh;
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;
for (i = 4; i > 0; i >>= 1) {
for (i = 4; i > 0; i >>= 1)
{
uint32_t T = (uint32_t)(vl & 1) * 0xe1000000U;
vl = (vh << 63) | (vl >> 1);
vh = (vh >> 1) ^ ((uint64_t)T << 32);
ctx->HL[i] = vl;
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;
vh = *HiH;
vl = *HiL;
for (j = 1; j < i; j++) {
for (j = 1; j < i; j++)
{
HiH[j] = vh ^ ctx->HH[j];
HiL[j] = vl ^ ctx->HL[j];
}
}
return(0);
return (0);
}
/******************************************************************************
*
* GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH.
@ -245,18 +247,18 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
* mode, and preprocesses the initialization vector and additional AEAD data.
*
******************************************************************************/
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // ptr to additional AEAD data (NULL if none)
size_t add_len) // length of additional AEAD data (bytes)
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // ptr to additional AEAD data (NULL if none)
size_t add_len) // length of additional AEAD data (bytes)
{
int ret; // our error return if the AES encrypt fails
int ret; // our error return if the AES encrypt fails
uchar work_buf[16]; // XOR source built from provided IV if len != 16
const uchar *p; // general purpose array pointer
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
const uchar *p; // general purpose array pointer
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
// since the context might be reused under the same key
// we zero the working buffers for this next new process
@ -265,42 +267,48 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
ctx->len = 0;
ctx->add_len = 0;
ctx->mode = mode; // set the GCM encryption/decryption mode
ctx->aes_ctx.mode = AES_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode
ctx->mode = mode; // set the GCM encryption/decryption 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
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)
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
ctx->y[15] = 1; // start "counting" from 1 (not 0)
}
else // if we don't have a 12-byte IV, we GHASH whatever we've been given
else // if we don't have a 12-byte IV, we GHASH whatever we've been given
{
memset(work_buf, 0x00, 16); // clear the working buffer
PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer
memset(work_buf, 0x00, 16); // clear the working buffer
PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer
p = iv;
while (iv_len > 0) {
while (iv_len > 0)
{
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);
iv_len -= 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);
}
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0)
return(ret);
return (ret);
ctx->add_len = add_len;
p = add;
while (add_len > 0) {
while (add_len > 0)
{
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);
add_len -= use_len;
p += use_len;
}
return(0);
return (0);
}
/******************************************************************************
@ -314,48 +322,53 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
* have a partial block length of < 128 bits.)
*
******************************************************************************/
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output) // pointer to destination data
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output) // pointer to destination data
{
int ret; // our error return if the AES encrypt fails
uchar ectr[16]; // counter-mode cipher output for XORing
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
int ret; // our error return if the AES encrypt fails
uchar ectr[16]; // counter-mode cipher output for XORing
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
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
use_len = (length < 16) ? length : 16;
// 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
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ectr)) != 0)
return(ret);
return (ret);
// encrypt or decrypt the input to the output
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
output[i] = (uchar)(ectr[i] ^ input[i]);
// now we mix in our data into the authentication hash.
// if we're ENcrypting we XOR in the post-XOR (output)
// results, but if we're DEcrypting we XOR in the input
// if we're ENcrypting we XOR in the post-XOR (output)
// results, but if we're DEcrypting we XOR in the input
// data
ctx->buf[i] ^= output[i];
}
}
else
{
for (i = 0; i < use_len; i++) {
// but if we're DEcrypting we XOR in the input data first,
// i.e. before saving to ouput data, otherwise if the input
// and output buffer are the same (inplace decryption) we
for (i = 0; i < use_len; i++)
{
// but if we're DEcrypting we XOR in the input data first,
// i.e. before saving to ouput data, otherwise if the input
// and output buffer are the same (inplace decryption) we
// would not get the correct auth tag
ctx->buf[i] ^= input[i];
@ -364,13 +377,13 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
output[i] = (uchar)(ectr[i] ^ input[i]);
}
}
gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation
gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation
length -= use_len; // drop the remaining byte count to process
length -= use_len; // drop the remaining byte count to process
input += use_len; // bump our input pointer forward
output += use_len; // bump our output pointer forward
output += use_len; // bump our output pointer forward
}
return(0);
return (0);
}
/******************************************************************************
@ -381,18 +394,20 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
* It performs the final GHASH to produce the resulting authentication TAG.
*
******************************************************************************/
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // pointer to buffer which receives the tag
size_t tag_len) // length, in bytes, of the tag-receiving buf
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // pointer to buffer which receives the tag
size_t tag_len) // length, in bytes, of the tag-receiving buf
{
uchar work_buf[16];
uint64_t orig_len = ctx->len * 8;
uint64_t orig_add_len = ctx->add_len * 8;
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);
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), 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);
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
@ -426,29 +442,28 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
*
******************************************************************************/
int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len) // byte length of the tag to be generated
{ /*
assuming that the caller has already invoked gcm_setkey to
prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn...
*/
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len) // byte length of the tag to be generated
{ /*
assuming that the caller has already invoked gcm_setkey to
prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn...
*/
gcm_start(ctx, mode, iv, iv_len, add, add_len);
gcm_update(ctx, length, input, output);
gcm_finish(ctx, tag, tag_len);
return(0);
return (0);
}
/******************************************************************************
*
* GCM_AUTH_DECRYPT
@ -462,37 +477,38 @@ int gcm_crypt_and_tag(
*
******************************************************************************/
int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len) // byte length of the tag <= 16
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len) // byte length of the tag <= 16
{
uchar check_tag[16]; // the tag generated and returned by decryption
int diff; // an ORed flag to detect authentication errors
size_t i; // our local iterator
uchar check_tag[16]; // the tag generated and returned by decryption
int diff; // an ORed flag to detect authentication errors
size_t i; // our local iterator
/*
we use GCM_DECRYPT_AND_TAG (above) to perform our decryption
(which is an identical XORing to reverse the previous one)
and also to re-generate the matching authentication tag
*/
gcm_crypt_and_tag(ctx, AES_DECRYPT, iv, iv_len, add, add_len,
input, output, length, check_tag, tag_len);
input, output, length, check_tag, tag_len);
// now we verify the authentication tag in 'constant time'
for (diff = 0, i = 0; i < tag_len; i++)
diff |= tag[i] ^ check_tag[i];
if (diff != 0) { // see whether any bits differed?
memset(output, 0, length); // if so... wipe the output data
return(GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
if (diff != 0)
{ // see whether any bits differed?
memset(output, 0, length); // if so... wipe the output data
return (GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
}
return(0);
return (0);
}
/******************************************************************************

View File

@ -1,73 +1,70 @@
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It
* should be endian (memory byte order) neutral since the few places that care
* are handled explicitly.
*
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \
* gcm/gcm-revised-spec.pdf
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It
* should be endian (memory byte order) neutral since the few places that care
* are handled explicitly.
*
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \
* gcm/gcm-revised-spec.pdf
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#pragma once
#define GCM_AUTH_FAILURE 0x55555555 // authentication failure
#define GCM_AUTH_FAILURE 0x55555555 // authentication failure
#include "aes.h" // gcm_context includes aes_context
#include "aes.h" // gcm_context includes aes_context
#if defined(_MSC_VER)
#include <basetsd.h>
typedef unsigned int size_t;// use the right type for length declarations
typedef unsigned int size_t; // use the right type for length declarations
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;
#else
#include <stdint.h>
#endif
/******************************************************************************
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
******************************************************************************/
typedef struct {
int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable
uchar base_ectr[16]; // first counter-mode cipher output for tag
uchar y[16]; // the current cipher-input IV|Counter value
uchar buf[16]; // buf working value
aes_context aes_ctx; // cipher context used
typedef struct
{
int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable
uchar base_ectr[16]; // first counter-mode cipher output for tag
uchar y[16]; // the current cipher-input IV|Counter value
uchar buf[16]; // buf working value
aes_context aes_ctx; // cipher context used
} gcm_context;
/******************************************************************************
* GCM_CONTEXT : MUST be called once before ANY use of this library
******************************************************************************/
int gcm_initialize(void);
/******************************************************************************
* GCM_SETKEY : sets the GCM (and AES) keying material for use
******************************************************************************/
int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
const uchar *key, // pointer to cipher key
const uint keysize // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
); // returns 0 for success
int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
const uchar *key, // pointer to cipher key
const uint keysize // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
); // returns 0 for success
/******************************************************************************
*
@ -87,18 +84,17 @@ int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
*
******************************************************************************/
int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len); // byte length of the tag to be generated
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len); // byte length of the tag to be generated
/******************************************************************************
*
@ -113,17 +109,16 @@ int gcm_crypt_and_tag(
*
******************************************************************************/
int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len); // byte length of the tag <= 16
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len); // byte length of the tag <= 16
/******************************************************************************
*
@ -133,13 +128,12 @@ int gcm_auth_decrypt(
* mode, and preprocesses the initialization vector and additional AEAD data.
*
******************************************************************************/
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // pointer to additional AEAD data (NULL if none)
size_t add_len); // length of additional AEAD data (bytes)
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // pointer to additional AEAD data (NULL if none)
size_t add_len); // length of additional AEAD data (bytes)
/******************************************************************************
*
@ -152,11 +146,10 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
* have a partial block length of < 128 bits.)
*
******************************************************************************/
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output); // pointer to destination data
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output); // pointer to destination data
/******************************************************************************
*
@ -166,10 +159,9 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
* It performs the final GHASH to produce the resulting authentication TAG.
*
******************************************************************************/
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf
/******************************************************************************
*

View File

@ -15,54 +15,54 @@
#include <string.h>
#include <stdlib.h>
/*
* hkdf
*
* Description:
* This function will generate keying material using HKDF.
*
* Parameters:
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* salt[ ]: [in]
* The optional salt value (a non-secret random value);
* if not provided (salt == NULL), it is set internally
* to a string of HashLen(whichSha) zeros.
* salt_len: [in]
* The length of the salt value. (Ignored if salt == NULL.)
* ikm[ ]: [in]
* Input keying material.
* ikm_len: [in]
* The length of the input keying material.
* info[ ]: [in]
* The optional context and application specific information.
* If info == NULL or a zero-length string, it is ignored.
* info_len: [in]
* The length of the optional context and application specific
* information. (Ignored if info == NULL.)
* okm[ ]: [out]
* Where the HKDF is to be stored.
* okm_len: [in]
* The length of the buffer to hold okm.
* okm_len must be <= 255 * USHABlockSize(whichSha)
*
* Notes:
* Calls hkdfExtract() and hkdfExpand().
*
* Returns:
* sha Error Code.
*
*/
/*
* hkdf
*
* Description:
* This function will generate keying material using HKDF.
*
* Parameters:
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* salt[ ]: [in]
* The optional salt value (a non-secret random value);
* if not provided (salt == NULL), it is set internally
* to a string of HashLen(whichSha) zeros.
* salt_len: [in]
* The length of the salt value. (Ignored if salt == NULL.)
* ikm[ ]: [in]
* Input keying material.
* ikm_len: [in]
* The length of the input keying material.
* info[ ]: [in]
* The optional context and application specific information.
* If info == NULL or a zero-length string, it is ignored.
* info_len: [in]
* The length of the optional context and application specific
* information. (Ignored if info == NULL.)
* okm[ ]: [out]
* Where the HKDF is to be stored.
* okm_len: [in]
* The length of the buffer to hold okm.
* okm_len must be <= 255 * USHABlockSize(whichSha)
*
* Notes:
* Calls hkdfExtract() and hkdfExpand().
*
* Returns:
* sha Error Code.
*
*/
int hkdf(SHAversion whichSha,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
{
uint8_t prk[USHAMaxHashSize];
return hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) ||
hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
info_len, okm, okm_len);
hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
info_len, okm, okm_len);
}
/*
@ -93,17 +93,19 @@ int hkdf(SHAversion whichSha,
*
*/
int hkdfExtract(SHAversion whichSha,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
uint8_t prk[USHAMaxHashSize])
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
uint8_t prk[USHAMaxHashSize])
{
unsigned char nullSalt[USHAMaxHashSize];
if (salt == 0) {
if (salt == 0)
{
salt = nullSalt;
salt_len = USHAHashSize(whichSha);
memset(nullSalt, '\0', salt_len);
}
else if (salt_len < 0) {
else if (salt_len < 0)
{
return shaBadParam;
}
return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
@ -143,42 +145,51 @@ int hkdfExtract(SHAversion whichSha,
*
*/
int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
{
size_t hash_len, N;
unsigned char T[USHAMaxHashSize];
size_t Tlen, where, i;
if (info == 0) {
if (info == 0)
{
info = (const unsigned char *)"";
info_len = 0;
}
else if (info_len < 0) {
else if (info_len < 0)
{
return shaBadParam;
}
if (okm_len <= 0) return shaBadParam;
if (!okm) return shaBadParam;
if (okm_len <= 0)
return shaBadParam;
if (!okm)
return shaBadParam;
hash_len = USHAHashSize(whichSha);
if (prk_len < hash_len) return shaBadParam;
if (prk_len < hash_len)
return shaBadParam;
N = okm_len / hash_len;
if ((okm_len % hash_len) != 0) N++;
if (N > 255) return shaBadParam;
if ((okm_len % hash_len) != 0)
N++;
if (N > 255)
return shaBadParam;
Tlen = 0;
where = 0;
for (i = 1; i <= N; i++) {
for (i = 1; i <= N; i++)
{
HMACContext context;
unsigned char c = i;
int ret = hmacReset(&context, whichSha, prk, prk_len) ||
hmacInput(&context, T, Tlen) ||
hmacInput(&context, info, info_len) ||
hmacInput(&context, &c, 1) ||
hmacResult(&context, T);
if (ret != shaSuccess) return ret;
hmacInput(&context, T, Tlen) ||
hmacInput(&context, info, info_len) ||
hmacInput(&context, &c, 1) ||
hmacResult(&context, T);
if (ret != shaSuccess)
return ret;
memcpy(okm + where, T,
(i != N) ? hash_len : (okm_len - where));
(i != N) ? hash_len : (okm_len - where));
where += hash_len;
Tlen = hash_len;
}
@ -210,14 +221,16 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
*
*/
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];
if (!context) return shaNull;
if (!context)
return shaNull;
context->whichSha = whichSha;
context->hashSize = USHAHashSize(whichSha);
if (salt == 0) {
if (salt == 0)
{
salt = nullSalt;
salt_len = context->hashSize;
memset(nullSalt, '\0', salt_len);
@ -247,11 +260,14 @@ int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
*
*/
int hkdfInput(HKDFContext *context, const unsigned char *ikm,
size_t ikm_len)
size_t ikm_len)
{
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
return hmacInput(&context->hmacContext, ikm, ikm_len);
}
@ -276,11 +292,14 @@ int hkdfInput(HKDFContext *context, const unsigned char *ikm,
* sha Error Code.
*/
int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
unsigned int ikm_bit_count)
unsigned int ikm_bit_count)
{
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count);
}
@ -315,23 +334,27 @@ int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
*
*/
int hkdfResult(HKDFContext *context,
uint8_t prk[USHAMaxHashSize],
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
uint8_t prk[USHAMaxHashSize],
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
{
uint8_t prkbuf[USHAMaxHashSize];
int ret;
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!okm) return context->Corrupted = shaBadParam;
if (!prk) prk = prkbuf;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
if (!okm)
return context->Corrupted = shaBadParam;
if (!prk)
prk = prkbuf;
ret = hmacResult(&context->hmacContext, prk) ||
hkdfExpand(context->whichSha, prk, context->hashSize, info,
info_len, okm, okm_len);
hkdfExpand(context->whichSha, prk, context->hashSize, info,
info_len, okm, okm_len);
context->Computed = 1;
return context->Corrupted = ret;
}

View File

@ -14,44 +14,44 @@
#include "sha.h"
#include <stddef.h>
/*
* hmac
*
* Description:
* This function will compute an HMAC message digest.
*
* Parameters:
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* message_array[ ]: [in]
* An array of octets representing the message.
* Note: in RFC 2104, this parameter is known
* as 'text'.
* length: [in]
* The length of the message in message_array.
* key[ ]: [in]
* The secret shared key.
* key_len: [in]
* The length of the secret shared key.
* digest[ ]: [out]
* Where the digest is to be returned.
* NOTE: The length of the digest is determined by
* the value of whichSha.
*
* Returns:
* sha Error Code.
*
*/
/*
* hmac
*
* Description:
* This function will compute an HMAC message digest.
*
* Parameters:
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* message_array[ ]: [in]
* An array of octets representing the message.
* Note: in RFC 2104, this parameter is known
* as 'text'.
* length: [in]
* The length of the message in message_array.
* key[ ]: [in]
* The secret shared key.
* key_len: [in]
* The length of the secret shared key.
* digest[ ]: [out]
* Where the digest is to be returned.
* NOTE: The length of the digest is determined by
* the value of whichSha.
*
* Returns:
* sha Error Code.
*
*/
int hmac(SHAversion whichSha,
const unsigned char *message_array, size_t length,
const unsigned char *key, size_t key_len,
uint8_t digest[USHAMaxHashSize])
const unsigned char *message_array, size_t length,
const unsigned char *key, size_t key_len,
uint8_t digest[USHAMaxHashSize])
{
HMACContext context;
return hmacReset(&context, whichSha, key, key_len) ||
hmacInput(&context, message_array, length) ||
hmacResult(&context, digest);
hmacInput(&context, message_array, length) ||
hmacResult(&context, digest);
}
/*
@ -76,7 +76,7 @@ int hmac(SHAversion whichSha,
*
*/
int hmacReset(HMACContext *context, enum SHAversion whichSha,
const unsigned char *key, size_t key_len)
const unsigned char *key, size_t key_len)
{
size_t i, blocksize, hashsize;
int ret;
@ -87,7 +87,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
/* temporary buffer when keylen > blocksize */
unsigned char tempkey[USHAMaxHashSize];
if (!context) return shaNull;
if (!context)
return shaNull;
context->Computed = 0;
context->Corrupted = shaSuccess;
@ -99,12 +100,14 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
* If key is longer than the hash blocksize,
* reset it to key = HASH(key).
*/
if (key_len > blocksize) {
if (key_len > blocksize)
{
USHAContext tcontext;
int err = USHAReset(&tcontext, whichSha) ||
USHAInput(&tcontext, key, key_len) ||
USHAResult(&tcontext, tempkey);
if (err != shaSuccess) return err;
USHAInput(&tcontext, key, key_len) ||
USHAResult(&tcontext, tempkey);
if (err != shaSuccess)
return err;
key = tempkey;
key_len = hashsize;
@ -121,13 +124,15 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
* and text is the data being protected.
*/
/* store key into the pads, XOR'd with ipad and opad values */
for (i = 0; i < key_len; i++) {
/* store key into the pads, XOR'd with ipad and opad values */
for (i = 0; i < key_len; i++)
{
k_ipad[i] = key[i] ^ 0x36;
context->k_opad[i] = key[i] ^ 0x5c;
}
/* remaining pad bytes are '\0' XOR'd with ipad and opad values */
for (; i < blocksize; i++) {
for (; i < blocksize; i++)
{
k_ipad[i] = 0x36;
context->k_opad[i] = 0x5c;
}
@ -135,8 +140,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
/* perform inner hash */
/* init context for 1st pass */
ret = USHAReset(&context->shaContext, whichSha) ||
/* and start with inner pad */
USHAInput(&context->shaContext, k_ipad, blocksize);
/* and start with inner pad */
USHAInput(&context->shaContext, k_ipad, blocksize);
return context->Corrupted = ret;
}
@ -161,14 +166,17 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
*
*/
int hmacInput(HMACContext *context, const unsigned char *text,
size_t text_len)
size_t text_len)
{
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
/* then text of datagram */
return context->Corrupted =
USHAInput(&context->shaContext, text, text_len);
USHAInput(&context->shaContext, text, text_len);
}
/*
@ -191,14 +199,17 @@ int hmacInput(HMACContext *context, const unsigned char *text,
* sha Error Code.
*/
int hmacFinalBits(HMACContext *context,
uint8_t bits, unsigned int bit_count)
uint8_t bits, unsigned int bit_count)
{
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
/* then final bits of datagram */
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 ret;
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
/* finish up 1st pass */
/* (Use digest here as a temporary buffer.) */
@ -238,7 +252,7 @@ int hmacResult(HMACContext *context, uint8_t *digest)
/* start with outer pad */
USHAInput(&context->shaContext, context->k_opad,
context->blockSize) ||
context->blockSize) ||
/* then results of 1st hash */
USHAInput(&context->shaContext, digest, context->hashSize) ||

View File

@ -10,16 +10,16 @@
*/
#ifndef USE_MODIFIED_MACROS
#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define SHA_Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
#define SHA_Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#else /* USE_MODIFIED_MACROS */
/*
* The following definitions are equivalent and potentially faster.
*/
#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
#endif /* USE_MODIFIED_MACROS */
#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z))
#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z))

View File

@ -85,12 +85,13 @@
/*
* All SHA functions return one of these values.
*/
enum {
enum
{
shaSuccess = 0,
shaNull, /* Null pointer parameter */
shaInputTooLong, /* input data too long */
shaStateError, /* called Input after FinalBits or Result */
shaBadParam /* passed a bad parameter */
shaNull, /* Null pointer parameter */
shaInputTooLong, /* input data too long */
shaStateError, /* called Input after FinalBits or Result */
shaBadParam /* passed a bad parameter */
};
#endif /* _SHA_enum_ */
@ -98,41 +99,50 @@ enum {
* These constants hold size information for each of the SHA
* hashing operations
*/
enum {
SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64,
enum
{
SHA1_Message_Block_Size = 64,
SHA224_Message_Block_Size = 64,
SHA256_Message_Block_Size = 64,
USHA_Max_Message_Block_Size = SHA256_Message_Block_Size,
SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32,
SHA1HashSize = 20,
SHA224HashSize = 28,
SHA256HashSize = 32,
USHAMaxHashSize = SHA256HashSize,
SHA1HashSizeBits = 160, SHA224HashSizeBits = 224,
SHA256HashSizeBits = 256, USHAMaxHashSizeBits = SHA256HashSizeBits
SHA1HashSizeBits = 160,
SHA224HashSizeBits = 224,
SHA256HashSizeBits = 256,
USHAMaxHashSizeBits = SHA256HashSizeBits
};
/*
* These constants are used in the USHA (Unified SHA) functions.
*/
typedef enum SHAversion {
SHA224, SHA256
typedef enum SHAversion
{
SHA224,
SHA256
} SHAversion;
/*
* This structure will hold context information for the SHA-256
* hashing operation.
*/
typedef struct SHA256Context {
uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */
typedef struct SHA256Context
{
uint32_t Intermediate_Hash[SHA256HashSize / 4]; /* Message Digest */
uint32_t Length_High; /* Message length in bits */
uint32_t Length_Low; /* Message length in bits */
uint32_t Length_High; /* Message length in bits */
uint32_t Length_Low; /* Message length in bits */
int_least16_t Message_Block_Index; /* Message_Block array index */
/* 512-bit message blocks */
int_least16_t Message_Block_Index; /* Message_Block array index */
/* 512-bit message blocks */
uint8_t Message_Block[SHA256_Message_Block_Size];
int Computed; /* Is the hash computed? */
int Corrupted; /* Cumulative corruption code */
int Computed; /* Is the hash computed? */
int Corrupted; /* Cumulative corruption code */
} SHA256Context;
/*
@ -145,10 +155,13 @@ typedef struct SHA256Context SHA224Context;
* This structure holds context information for all SHA
* hashing operations.
*/
typedef struct USHAContext {
int whichSha; /* which SHA is being used */
union {
SHA224Context sha224Context; SHA256Context sha256Context;
typedef struct USHAContext
{
int whichSha; /* which SHA is being used */
union
{
SHA224Context sha224Context;
SHA256Context sha256Context;
} ctx;
} USHAContext;
@ -157,15 +170,16 @@ typedef struct USHAContext {
* This structure will hold context information for the HMAC
* keyed-hashing operation.
*/
typedef struct HMACContext {
int whichSha; /* which SHA is being used */
int hashSize; /* hash size of SHA being used */
int blockSize; /* block size of SHA being used */
USHAContext shaContext; /* SHA context */
typedef struct HMACContext
{
int whichSha; /* which SHA is being used */
int hashSize; /* hash size of SHA being used */
int blockSize; /* block size of SHA being used */
USHAContext shaContext; /* SHA context */
unsigned char k_opad[USHA_Max_Message_Block_Size];
/* outer padding - key XORd with opad */
int Computed; /* Is the MAC computed? */
int Corrupted; /* Cumulative corruption code */
/* outer padding - key XORd with opad */
int Computed; /* Is the MAC computed? */
int Corrupted; /* Cumulative corruption code */
} HMACContext;
@ -173,47 +187,47 @@ typedef struct HMACContext {
* This structure will hold context information for the HKDF
* extract-and-expand Key Derivation Functions.
*/
typedef struct HKDFContext {
int whichSha; /* which SHA is being used */
typedef struct HKDFContext
{
int whichSha; /* which SHA is being used */
HMACContext hmacContext;
int hashSize; /* hash size of SHA being used */
int hashSize; /* hash size of SHA being used */
unsigned char prk[USHAMaxHashSize];
/* pseudo-random key - output of hkdfInput */
int Computed; /* Is the key material computed? */
int Corrupted; /* Cumulative corruption code */
/* pseudo-random key - output of hkdfInput */
int Computed; /* Is the key material computed? */
int Corrupted; /* Cumulative corruption code */
} HKDFContext;
/*
* Function Prototypes
*/
/* SHA-224 */
int SHA224Reset(SHA224Context *);
int SHA224Input(SHA224Context *, const uint8_t *bytes,
unsigned int bytecount);
unsigned int bytecount);
int SHA224FinalBits(SHA224Context *, uint8_t bits,
unsigned int bit_count);
unsigned int bit_count);
int SHA224Result(SHA224Context *,
uint8_t Message_Digest[SHA224HashSize]);
uint8_t Message_Digest[SHA224HashSize]);
/* SHA-256 */
int SHA256Reset(SHA256Context *);
int SHA256Input(SHA256Context *, const uint8_t *bytes,
unsigned int bytecount);
unsigned int bytecount);
int SHA256FinalBits(SHA256Context *, uint8_t bits,
unsigned int bit_count);
unsigned int bit_count);
int SHA256Result(SHA256Context *,
uint8_t Message_Digest[SHA256HashSize]);
uint8_t Message_Digest[SHA256HashSize]);
/* Unified SHA functions, chosen by whichSha */
int USHAReset(USHAContext *context, SHAversion whichSha);
int USHAInput(USHAContext *context,
const uint8_t *bytes, unsigned int bytecount);
const uint8_t *bytes, unsigned int bytecount);
int USHAFinalBits(USHAContext *context,
uint8_t bits, unsigned int bit_count);
uint8_t bits, unsigned int bit_count);
int USHAResult(USHAContext *context,
uint8_t Message_Digest[USHAMaxHashSize]);
uint8_t Message_Digest[USHAMaxHashSize]);
int USHABlockSize(enum SHAversion whichSha);
int USHAHashSize(enum SHAversion whichSha);
@ -222,12 +236,12 @@ int USHAHashSize(enum SHAversion whichSha);
* for all SHAs.
* This interface allows a fixed-length text input to be used.
*/
int hmac(SHAversion whichSha, /* which SHA algorithm to use */
const unsigned char *text, /* pointer to data stream */
size_t text_len, /* length of data stream */
const unsigned char *key, /* pointer to authentication key */
size_t key_len, /* length of authentication key */
uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */
int hmac(SHAversion whichSha, /* which SHA algorithm to use */
const unsigned char *text, /* pointer to data stream */
size_t text_len, /* length of data stream */
const unsigned char *key, /* pointer to authentication key */
size_t key_len, /* length of authentication key */
uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */
/*
* HMAC Keyed-Hashing for Message Authentication, RFC 2104,
@ -235,31 +249,30 @@ int hmac(SHAversion whichSha, /* which SHA algorithm to use */
* This interface allows any length of text input to be used.
*/
int hmacReset(HMACContext *context, enum SHAversion whichSha,
const unsigned char *key, size_t key_len);
const unsigned char *key, size_t key_len);
int hmacInput(HMACContext *context, const unsigned char *text,
size_t text_len);
size_t text_len);
int hmacFinalBits(HMACContext *context, uint8_t bits,
unsigned int bit_count);
unsigned int bit_count);
int hmacResult(HMACContext *context,
uint8_t digest[USHAMaxHashSize]);
uint8_t digest[USHAMaxHashSize]);
/*
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
* RFC 5869, for all SHAs.
*/
int hkdf(SHAversion whichSha,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
uint8_t okm[ ], size_t okm_len);
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len);
int hkdfExtract(SHAversion whichSha, const unsigned char *salt,
size_t salt_len, const unsigned char *ikm,
size_t ikm_len, uint8_t prk[USHAMaxHashSize]);
int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ],
size_t prk_len, const unsigned char *info,
size_t info_len, uint8_t okm[ ], size_t okm_len);
size_t salt_len, const unsigned char *ikm,
size_t ikm_len, uint8_t prk[USHAMaxHashSize]);
int hkdfExpand(SHAversion whichSha, const uint8_t prk[],
size_t prk_len, const unsigned char *info,
size_t info_len, uint8_t okm[], size_t okm_len);
/*
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
@ -267,12 +280,12 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ],
* This interface allows any length of text input to be used.
*/
int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
const unsigned char *salt, size_t salt_len);
const unsigned char *salt, size_t salt_len);
int hkdfInput(HKDFContext *context, const unsigned char *ikm,
size_t ikm_len);
size_t ikm_len);
int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
unsigned int ikm_bit_count);
unsigned int ikm_bit_count);
int hkdfResult(HKDFContext *context,
uint8_t prk[USHAMaxHashSize],
const unsigned char *info, size_t info_len,
uint8_t okm[USHAMaxHashSize], size_t okm_len);
uint8_t prk[USHAMaxHashSize],
const unsigned char *info, size_t info_len,
uint8_t okm[USHAMaxHashSize], size_t okm_len);

View File

@ -44,54 +44,53 @@
#include "sha-private.h"
/* Define the SHA shift, rotate left, and rotate right macros */
#define SHA256_SHR(bits,word) ((word) >> (bits))
#define SHA256_ROTL(bits,word) \
(((word) << (bits)) | ((word) >> (32-(bits))))
#define SHA256_ROTR(bits,word) \
(((word) >> (bits)) | ((word) << (32-(bits))))
#define SHA256_SHR(bits, word) ((word) >> (bits))
#define SHA256_ROTL(bits, word) \
(((word) << (bits)) | ((word) >> (32 - (bits))))
#define SHA256_ROTR(bits, word) \
(((word) >> (bits)) | ((word) << (32 - (bits))))
/* Define the SHA SIGMA and sigma macros */
#define SHA256_SIGMA0(word) \
(SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word))
#define SHA256_SIGMA1(word) \
(SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word))
#define SHA256_sigma0(word) \
(SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word))
#define SHA256_sigma1(word) \
(SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word))
#define SHA256_SIGMA0(word) \
(SHA256_ROTR(2, word) ^ SHA256_ROTR(13, word) ^ SHA256_ROTR(22, word))
#define SHA256_SIGMA1(word) \
(SHA256_ROTR(6, word) ^ SHA256_ROTR(11, word) ^ SHA256_ROTR(25, word))
#define SHA256_sigma0(word) \
(SHA256_ROTR(7, word) ^ SHA256_ROTR(18, word) ^ SHA256_SHR(3, word))
#define SHA256_sigma1(word) \
(SHA256_ROTR(17, word) ^ SHA256_ROTR(19, word) ^ SHA256_SHR(10, word))
/*
* Add "length" to the length.
* Set Corrupted when overflow has occurred.
*/
static uint32_t addTemp;
#define SHA224_256AddLength(context, length) \
(addTemp = (context)->Length_Low, (context)->Corrupted = \
(((context)->Length_Low += (length)) < addTemp) && \
(++(context)->Length_High == 0) ? shaInputTooLong : \
(context)->Corrupted )
#define SHA224_256AddLength(context, length) \
(addTemp = (context)->Length_Low, (context)->Corrupted = \
(((context)->Length_Low += (length)) < addTemp) && \
(++(context)->Length_High == 0) \
? shaInputTooLong \
: (context)->Corrupted)
/* Local Function Prototypes */
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0);
static void SHA224_256ProcessMessageBlock(SHA256Context *context);
static void SHA224_256Finalize(SHA256Context *context,
uint8_t Pad_Byte);
uint8_t Pad_Byte);
static void SHA224_256PadMessage(SHA256Context *context,
uint8_t Pad_Byte);
uint8_t Pad_Byte);
static int SHA224_256ResultN(SHA256Context *context,
uint8_t Message_Digest[ ], int HashSize);
uint8_t Message_Digest[], int HashSize);
/* 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,
0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4
};
0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4};
/* Initial Hash Values: FIPS 180-3 section 5.3.3 */
static uint32_t SHA256_H0[SHA256HashSize/4] = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
};
static uint32_t SHA256_H0[SHA256HashSize / 4] = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19};
/*
* SHA224Reset
@ -133,7 +132,7 @@ int SHA224Reset(SHA224Context *context)
*
*/
int SHA224Input(SHA224Context *context, const uint8_t *message_array,
unsigned int length)
unsigned int length)
{
return SHA256Input(context, message_array, length);
}
@ -183,7 +182,7 @@ int SHA224FinalBits(SHA224Context *context,
* sha Error Code.
*/
int SHA224Result(SHA224Context *context,
uint8_t Message_Digest[SHA224HashSize])
uint8_t Message_Digest[SHA224HashSize])
{
return SHA224_256ResultN(context, Message_Digest, SHA224HashSize);
}
@ -227,27 +226,32 @@ int SHA256Reset(SHA256Context *context)
* sha Error Code.
*/
int SHA256Input(SHA256Context *context, const uint8_t *message_array,
unsigned int length)
unsigned int length)
{
if (!context) return shaNull;
if (!length) return shaSuccess;
if (!message_array) return shaNull;
if (context->Computed) return context->Corrupted = shaStateError;
if (context->Corrupted) return context->Corrupted;
if (!context)
return shaNull;
if (!length)
return shaSuccess;
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++] =
*message_array;
*message_array;
if ((SHA224_256AddLength(context, 8) == shaSuccess) &&
(context->Message_Block_Index == SHA256_Message_Block_Size))
(context->Message_Block_Index == SHA256_Message_Block_Size))
SHA224_256ProcessMessageBlock(context);
message_array++;
}
return context->Corrupted;
}
/*
@ -276,24 +280,26 @@ int SHA256FinalBits(SHA256Context *context,
/* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80,
/* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0,
/* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8,
/* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE
};
/* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE};
static uint8_t markbit[8] = {
/* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40,
/* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10,
/* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04,
/* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01
};
/* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01};
if (!context) return shaNull;
if (!length) return shaSuccess;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (length >= 8) return context->Corrupted = shaBadParam;
if (!context)
return shaNull;
if (!length)
return shaSuccess;
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_256Finalize(context, (uint8_t)
((message_bits & masks[length]) | markbit[length]));
SHA224_256Finalize(context, (uint8_t)((message_bits & masks[length]) | markbit[length]));
return context->Corrupted;
}
@ -341,10 +347,11 @@ int SHA256Result(SHA256Context *context,
*/
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->Message_Block_Index = 0;
context->Message_Block_Index = 0;
context->Intermediate_Hash[0] = H0[0];
context->Intermediate_Hash[1] = H0[1];
@ -355,7 +362,7 @@ static int SHA224_256Reset(SHA256Context *context, uint32_t *H0)
context->Intermediate_Hash[6] = H0[6];
context->Intermediate_Hash[7] = H0[7];
context->Computed = 0;
context->Computed = 0;
context->Corrupted = shaSuccess;
return shaSuccess;
@ -396,12 +403,11 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
int t, t4; /* Loop counter */
uint32_t temp1, temp2; /* Temporary word value */
uint32_t W[64]; /* Word sequence */
uint32_t A, B, C, D, E, F, G, H; /* Word buffers */
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
int t, t4; /* Loop counter */
uint32_t temp1, temp2; /* Temporary word value */
uint32_t W[64]; /* Word sequence */
uint32_t A, B, C, D, E, F, G, H; /* Word buffers */
/*
* Initialize the first 16 words in the array W
@ -412,8 +418,8 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
(((uint32_t)context->Message_Block[t4 + 2]) << 8) |
(((uint32_t)context->Message_Block[t4 + 3]));
for (t = 16; t < 64; t++)
W[t] = SHA256_sigma1(W[t-2]) + W[t-7] +
SHA256_sigma0(W[t-15]) + W[t-16];
W[t] = SHA256_sigma1(W[t - 2]) + W[t - 7] +
SHA256_sigma0(W[t - 15]) + W[t - 16];
A = context->Intermediate_Hash[0];
B = context->Intermediate_Hash[1];
@ -424,9 +430,10 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
G = context->Intermediate_Hash[6];
H = context->Intermediate_Hash[7];
for (t = 0; t < 64; t++) {
temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t];
temp2 = SHA256_SIGMA0(A) + SHA_Maj(A,B,C);
for (t = 0; t < 64; t++)
{
temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E, F, G) + K[t] + W[t];
temp2 = SHA256_SIGMA0(A) + SHA_Maj(A, B, C);
H = G;
G = F;
F = E;
@ -468,14 +475,14 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
* sha Error Code.
*/
static void SHA224_256Finalize(SHA256Context *context,
uint8_t Pad_Byte)
uint8_t Pad_Byte)
{
int i;
SHA224_256PadMessage(context, Pad_Byte);
/* message may be sensitive, so clear it out */
for (i = 0; i < SHA256_Message_Block_Size; ++i)
context->Message_Block[i] = 0;
context->Length_High = 0; /* and clear length */
context->Length_High = 0; /* and clear length */
context->Length_Low = 0;
context->Computed = 1;
}
@ -505,7 +512,7 @@ static void SHA224_256Finalize(SHA256Context *context,
* Nothing.
*/
static void SHA224_256PadMessage(SHA256Context *context,
uint8_t Pad_Byte)
uint8_t Pad_Byte)
{
/*
* Check to see if the current message block is too small to hold
@ -513,15 +520,17 @@ static void SHA224_256PadMessage(SHA256Context *context,
* block, process it, and then continue padding into a second
* 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;
while (context->Message_Block_Index < SHA256_Message_Block_Size)
context->Message_Block[context->Message_Block_Index++] = 0;
SHA224_256ProcessMessageBlock(context);
} else
}
else
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))
context->Message_Block[context->Message_Block_Index++] = 0;
/*
@ -561,21 +570,22 @@ static void SHA224_256PadMessage(SHA256Context *context,
* sha Error Code.
*/
static int SHA224_256ResultN(SHA256Context *context,
uint8_t Message_Digest[ ], int HashSize)
uint8_t Message_Digest[], int HashSize)
{
int i;
if (!context) return shaNull;
if (!Message_Digest) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (!context)
return shaNull;
if (!Message_Digest)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (!context->Computed)
SHA224_256Finalize(context, 0x80);
for (i = 0; i < HashSize; ++i)
Message_Digest[i] = (uint8_t)
(context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ));
Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03)));
return shaSuccess;
}

View File

@ -30,12 +30,17 @@
*/
int USHAReset(USHAContext *context, enum SHAversion whichSha)
{
if (!context) return shaNull;
if (!context)
return shaNull;
context->whichSha = whichSha;
switch (whichSha) {
case SHA224: return SHA224Reset((SHA224Context*)&context->ctx);
case SHA256: return SHA256Reset((SHA256Context*)&context->ctx);
default: return shaBadParam;
switch (whichSha)
{
case SHA224:
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,
const uint8_t *bytes, unsigned int bytecount)
{
if (!context) return shaNull;
switch (context->whichSha) {
case SHA224:
return SHA224Input((SHA224Context*)&context->ctx, bytes,
bytecount);
case SHA256:
return SHA256Input((SHA256Context*)&context->ctx, bytes,
bytecount);
default: return shaBadParam;
if (!context)
return shaNull;
switch (context->whichSha)
{
case SHA224:
return SHA224Input((SHA224Context *)&context->ctx, bytes,
bytecount);
case SHA256:
return SHA256Input((SHA256Context *)&context->ctx, bytes,
bytecount);
default:
return shaBadParam;
}
}
@ -96,15 +104,18 @@ int USHAInput(USHAContext *context,
int USHAFinalBits(USHAContext *context,
uint8_t bits, unsigned int bit_count)
{
if (!context) return shaNull;
switch (context->whichSha) {
case SHA224:
return SHA224FinalBits((SHA224Context*)&context->ctx, bits,
bit_count);
case SHA256:
return SHA256FinalBits((SHA256Context*)&context->ctx, bits,
bit_count);
default: return shaBadParam;
if (!context)
return shaNull;
switch (context->whichSha)
{
case SHA224:
return SHA224FinalBits((SHA224Context *)&context->ctx, bits,
bit_count);
case SHA256:
return SHA256FinalBits((SHA256Context *)&context->ctx, bits,
bit_count);
default:
return shaBadParam;
}
}
@ -130,15 +141,18 @@ int USHAFinalBits(USHAContext *context,
int USHAResult(USHAContext *context,
uint8_t Message_Digest[USHAMaxHashSize])
{
if (!context) return shaNull;
switch (context->whichSha) {
case SHA224:
return SHA224Result((SHA224Context*)&context->ctx,
Message_Digest);
case SHA256:
return SHA256Result((SHA256Context*)&context->ctx,
Message_Digest);
default: return shaBadParam;
if (!context)
return shaNull;
switch (context->whichSha)
{
case SHA224:
return SHA224Result((SHA224Context *)&context->ctx,
Message_Digest);
case SHA256:
return SHA256Result((SHA256Context *)&context->ctx,
Message_Digest);
default:
return shaBadParam;
}
}
@ -159,10 +173,13 @@ int USHAResult(USHAContext *context,
*/
int USHABlockSize(enum SHAversion whichSha)
{
switch (whichSha) {
case SHA224: return SHA224_Message_Block_Size;
default:
case SHA256: return SHA256_Message_Block_Size;
switch (whichSha)
{
case SHA224:
return SHA224_Message_Block_Size;
default:
case SHA256:
return SHA256_Message_Block_Size;
}
}
@ -183,9 +200,12 @@ int USHABlockSize(enum SHAversion whichSha)
*/
int USHAHashSize(enum SHAversion whichSha)
{
switch (whichSha) {
case SHA224: return SHA224HashSize;
default:
case SHA256: return SHA256HashSize;
switch (whichSha)
{
case SHA224:
return SHA224HashSize;
default:
case SHA256:
return SHA256HashSize;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@
#include <netinet/udp.h>
#ifndef IPV6_FREEBIND
#define IPV6_FREEBIND 78
#define IPV6_FREEBIND 78
#endif
#ifdef __CYGWIN__
@ -30,7 +30,7 @@
#endif
#ifndef AF_DIVERT
#define AF_DIVERT 44 /* divert(4) */
#define AF_DIVERT 44 /* divert(4) */
#endif
#ifndef PF_DIVERT
#define PF_DIVERT AF_DIVERT
@ -40,24 +40,24 @@
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);
uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
#define FOOL_NONE 0x00
#define FOOL_MD5SIG 0x01
#define FOOL_BADSUM 0x02
#define FOOL_TS 0x04
#define FOOL_BADSEQ 0x08
#define FOOL_HOPBYHOP 0x10
#define FOOL_HOPBYHOP2 0x20
#define FOOL_DESTOPT 0x40
#define FOOL_IPFRAG1 0x80
#define FOOL_DATANOACK 0x100
#define FOOL_NONE 0x00
#define FOOL_MD5SIG 0x01
#define FOOL_BADSUM 0x02
#define FOOL_TS 0x04
#define FOOL_BADSEQ 0x08
#define FOOL_HOPBYHOP 0x10
#define FOOL_HOPBYHOP2 0x20
#define FOOL_DESTOPT 0x40
#define FOOL_IPFRAG1 0x80
#define FOOL_DATANOACK 0x100
#define SCALE_NONE ((uint8_t)-1)
#define SCALE_NONE ((uint8_t) - 1)
#define VERDICT_PASS 0
#define VERDICT_MODIFY 1
#define VERDICT_DROP 2
#define VERDICT_MASK 3
#define VERDICT_NOCSUM 4
#define VERDICT_PASS 0
#define VERDICT_MODIFY 1
#define VERDICT_DROP 2
#define VERDICT_MASK 3
#define VERDICT_NOCSUM 4
// seq and wsize have network byte order
bool prepare_tcp_segment4(
@ -100,7 +100,6 @@ bool prepare_tcp_segment(
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
bool prepare_udp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t ttl,
@ -144,11 +143,11 @@ bool ip_frag(
size_t frag_pos, uint32_t ident,
uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_size);
void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl);
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport);
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);
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind);
uint32_t *tcp_find_timestamps(struct tcphdr *tcp);
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp);
@ -170,7 +169,7 @@ bool rawsend_preinit(bool bind_fix4, bool bind_fix6);
#endif
// auto creates internal socket and uses it for subsequent calls
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);
bool rawsend_rp(const struct rawpacket *rp);
// return trues if all packets were send successfully
bool rawsend_queue(struct rawpacket_tailhead *q);
@ -189,7 +188,7 @@ void print_tcphdr(const struct tcphdr *tcphdr);
void print_udphdr(const struct udphdr *udphdr);
void str_ip(char *s, size_t s_len, const struct ip *ip);
void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto);
void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr);
void str_srcdst_ip6(char *s, size_t s_len, const void *saddr, const void *daddr);
void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr);
void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr);
@ -225,7 +224,12 @@ typedef struct
#define AUTOTTL_DEFAULT_MIN 3
#define AUTOTTL_DEFAULT_MAX 20
#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);
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);

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,9 @@
#define DPI_DESYNC_MAX_FAKE_LEN 9216
enum dpi_desync_mode {
DESYNC_NONE=0,
enum dpi_desync_mode
{
DESYNC_NONE = 0,
DESYNC_INVALID,
DESYNC_FAKE,
DESYNC_FAKE_KNOWN,

View File

@ -5,7 +5,7 @@
#define ZCHUNK 16384
#define BUFMIN 128
#define BUFCHUNK (1024*128)
#define BUFCHUNK (1024 * 128)
int z_readfile(FILE *F, char **buf, size_t *size)
{
@ -21,7 +21,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
bufsize = *size = 0;
r = inflateInit2(&zs, 47);
if (r != Z_OK) return r;
if (r != Z_OK)
return r;
do
{
@ -31,7 +32,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
r = Z_ERRNO;
goto zerr;
}
if (!zs.avail_in) break;
if (!zs.avail_in)
break;
zs.next_in = in;
do
{
@ -47,9 +49,10 @@ int z_readfile(FILE *F, char **buf, size_t *size)
*buf = newbuf;
}
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);
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;
} while (r == Z_OK && zs.avail_in);
} while (r == Z_OK);
@ -57,7 +60,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
if (*size < bufsize)
{
// free extra space
if ((newbuf = realloc(*buf, *size))) *buf = newbuf;
if ((newbuf = realloc(*buf, *size)))
*buf = newbuf;
}
inflateEnd(&zs);
@ -73,7 +77,7 @@ zerr:
return r;
}
bool is_gzip(FILE* F)
bool is_gzip(FILE *F)
{
unsigned char magic[2];
bool b = !fseek(F, 0, SEEK_SET) && fread(magic, 1, 2, F) == 2 && magic[0] == 0x1F && magic[1] == 0x8B;

View File

@ -4,5 +4,5 @@
#include <zlib.h>
#include <stdbool.h>
int z_readfile(FILE *F,char **buf,size_t *size);
bool is_gzip(FILE* F);
int z_readfile(FILE *F, char **buf, size_t *size);
bool is_gzip(FILE *F);

View File

@ -7,7 +7,6 @@
#include <ctype.h>
#include <sys/stat.h>
#include "params.h"
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;
bcut = true;
}
if (!size) return;
for (k = 0; k < size; k++) DLOG("%02X ", data[k]);
if (!size)
return;
for (k = 0; k < size; k++)
DLOG("%02X ", data[k]);
DLOG(bcut ? "... : " : ": ");
for (k = 0; k < size; k++) DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.');
if (bcut) DLOG(" ...");
for (k = 0; k < size; k++)
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)
@ -38,9 +41,11 @@ char *strncasestr(const char *s, const char *find, size_t slen)
{
do
{
if (slen-- < 1 || (sc = *s++) == '\0') return NULL;
if (slen-- < 1 || (sc = *s++) == '\0')
return NULL;
} while (toupper(c) != toupper(sc));
if (len > slen) return NULL;
if (len > slen)
return NULL;
} while (strncasecmp(s, find, len) != 0);
s--;
}
@ -52,7 +57,8 @@ bool load_file(const char *filename, void *buffer, size_t *buffer_size)
FILE *F;
F = fopen(filename, "rb");
if (!F) return false;
if (!F)
return false;
*buffer_size = fread(buffer, 1, *buffer_size, F);
if (ferror(F))
@ -74,7 +80,8 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size)
FILE *F;
F = fopen(filename, "wb");
if (!F) return false;
if (!F)
return false;
fwrite(buffer, 1, buffer_size, F);
if (ferror(F))
@ -88,25 +95,26 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size)
}
bool append_to_list_file(const char *filename, const char *s)
{
FILE *F = fopen(filename,"at");
if (!F) return false;
bool bOK = fprintf(F,"%s\n",s)>0;
FILE *F = fopen(filename, "at");
if (!F)
return false;
bool bOK = fprintf(F, "%s\n", s) > 0;
fclose(F);
return bOK;
}
void ntop46(const struct sockaddr *sa, char *str, size_t len)
{
if (!len) return;
if (!len)
return;
*str = 0;
switch (sa->sa_family)
{
case AF_INET:
inet_ntop(sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr, str, len);
inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, str, len);
break;
case AF_INET6:
inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, str, len);
inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, str, len);
break;
default:
snprintf(str, len, "UNKNOWN_FAMILY_%d", sa->sa_family);
@ -119,10 +127,10 @@ void ntop46_port(const struct sockaddr *sa, char *str, size_t len)
switch (sa->sa_family)
{
case AF_INET:
snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in*)sa)->sin_port));
snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in *)sa)->sin_port));
break;
case AF_INET6:
snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6 *)sa)->sin6_port));
break;
default:
snprintf(str, len, "%s", ip);
@ -138,49 +146,55 @@ void print_sockaddr(const struct sockaddr *sa)
bool pton4_port(const char *s, struct sockaddr_in *sa)
{
char ip[16],*p;
char ip[16], *p;
size_t l;
unsigned int u;
p = strchr(s,':');
if (!p) return false;
l = p-s;
if (l<7 || l>15) return false;
memcpy(ip,s,l);
ip[l]=0;
p = strchr(s, ':');
if (!p)
return false;
l = p - s;
if (l < 7 || l > 15)
return false;
memcpy(ip, s, l);
ip[l] = 0;
p++;
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);
return true;
}
bool pton6_port(const char *s, struct sockaddr_in6 *sa)
{
char ip[40],*p;
char ip[40], *p;
size_t l;
unsigned int u;
if (*s++!='[') return false;
p = strchr(s,']');
if (!p || p[1]!=':') return false;
l = p-s;
if (l<2 || l>39) return false;
p+=2;
memcpy(ip,s,l);
ip[l]=0;
if (*s++ != '[')
return false;
p = strchr(s, ']');
if (!p || p[1] != ':')
return false;
l = p - s;
if (l < 2 || l > 39)
return false;
p += 2;
memcpy(ip, s, l);
ip[l] = 0;
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_flowinfo = 0;
sa->sin6_scope_id = 0;
return true;
}
void dbgprint_socket_buffers(int fd)
{
if (params.debug)
@ -190,7 +204,7 @@ void dbgprint_socket_buffers(int fd)
sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &v, &sz))
DLOG("fd=%d SO_RCVBUF=%d\n", fd, v);
sz = sizeof(int);
sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &v, &sz))
DLOG("fd=%d SO_SNDBUF=%d\n", fd, v);
}
@ -216,14 +230,14 @@ bool set_socket_buffers(int fd, int rcvbuf, int sndbuf)
uint64_t pntoh64(const void *p)
{
return (uint64_t)*((const uint8_t *)(p)+0) << 56 |
(uint64_t)*((const uint8_t *)(p)+1) << 48 |
(uint64_t)*((const uint8_t *)(p)+2) << 40 |
(uint64_t)*((const uint8_t *)(p)+3) << 32 |
(uint64_t)*((const uint8_t *)(p)+4) << 24 |
(uint64_t)*((const uint8_t *)(p)+5) << 16 |
(uint64_t)*((const uint8_t *)(p)+6) << 8 |
(uint64_t)*((const uint8_t *)(p)+7) << 0;
return (uint64_t) * ((const uint8_t *)(p) + 0) << 56 |
(uint64_t) * ((const uint8_t *)(p) + 1) << 48 |
(uint64_t) * ((const uint8_t *)(p) + 2) << 40 |
(uint64_t) * ((const uint8_t *)(p) + 3) << 32 |
(uint64_t) * ((const uint8_t *)(p) + 4) << 24 |
(uint64_t) * ((const uint8_t *)(p) + 5) << 16 |
(uint64_t) * ((const uint8_t *)(p) + 6) << 8 |
(uint64_t) * ((const uint8_t *)(p) + 7) << 0;
}
void phton64(uint8_t *p, uint64_t v)
{
@ -239,57 +253,60 @@ void phton64(uint8_t *p, uint64_t v)
bool seq_within(uint32_t s, uint32_t s1, uint32_t s2)
{
return (s2>=s1 && s>=s1 && s<=s2) || (s2<s1 && (s<=s2 || s>=s1));
return (s2 >= s1 && s >= s1 && s <= s2) || (s2 < s1 && (s <= s2 || s >= s1));
}
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)
{
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)
{
uint8_t u,l;
uint8_t u, l;
u = parse_hex_digit(s[0]);
l = parse_hex_digit(s[1]);
if (u==INVALID_HEX_DIGIT || l==INVALID_HEX_DIGIT)
if (u == INVALID_HEX_DIGIT || l == INVALID_HEX_DIGIT)
{
*pbyte=0;
*pbyte = 0;
return false;
}
else
{
*pbyte=(u<<4) | l;
*pbyte = (u << 4) | l;
return true;
}
}
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size)
{
uint8_t *pe = pbuf+*size;
*size=0;
while(pbuf<pe && *s)
uint8_t *pe = pbuf + *size;
*size = 0;
while (pbuf < pe && *s)
{
if (!parse_hex_byte(s,pbuf))
if (!parse_hex_byte(s, pbuf))
return false;
pbuf++; s+=2; (*size)++;
pbuf++;
s += 2;
(*size)++;
}
return true;
}
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize)
void fill_pattern(uint8_t *buf, size_t bufsize, const void *pattern, size_t patsize)
{
size_t size;
while (bufsize)
{
size = bufsize>patsize ? patsize : bufsize;
memcpy(buf,pattern,size);
size = bufsize > patsize ? patsize : bufsize;
memcpy(buf, pattern, size);
buf += size;
bufsize -= size;
}
@ -301,66 +318,72 @@ int fprint_localtime(FILE *F)
time_t now;
time(&now);
localtime_r(&now,&t);
localtime_r(&now, &t);
return fprintf(F, "%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
}
time_t file_mod_time(const char *filename)
{
struct stat st;
return stat(filename,&st)==-1 ? 0 : st.st_mtime;
return stat(filename, &st) == -1 ? 0 : st.st_mtime;
}
bool pf_in_range(uint16_t port, const port_filter *pf)
{
return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg);
return port && (((!pf->from && !pf->to) || (port >= pf->from && port <= pf->to)) ^ pf->neg);
}
bool pf_parse(const char *s, port_filter *pf)
{
unsigned int v1,v2;
unsigned int v1, v2;
if (!s) return false;
if (*s=='~')
if (!s)
return false;
if (*s == '~')
{
pf->neg=true;
pf->neg = true;
s++;
}
else
pf->neg=false;
if (sscanf(s,"%u-%u",&v1,&v2)==2)
pf->neg = false;
if (sscanf(s, "%u-%u", &v1, &v2) == 2)
{
if (!v1 || v1>65535 || v2>65535 || v1>v2) return false;
pf->from=(uint16_t)v1;
pf->to=(uint16_t)v2;
if (!v1 || v1 > 65535 || v2 > 65535 || v1 > v2)
return false;
pf->from = (uint16_t)v1;
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;
pf->to=pf->from=(uint16_t)v1;
if (!v1 || v1 > 65535)
return false;
pf->to = pf->from = (uint16_t)v1;
}
else
return false;
return true;
}
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;
for(k=0;k<sz16;k++) ((uint16_t*)p)[k]=(uint16_t)random();
if (sz & 1) p[sz-1]=(uint8_t)random();
size_t k, sz16 = sz >> 1;
for (k = 0; k < sz16; k++)
((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;
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)
{
size_t k;
uint8_t rnd;
for(k=0;k<sz;k++)
for (k = 0; k < sz; k++)
{
rnd = random() % (10 + 'z'-'a'+1);
p[k] = rnd<10 ? rnd+'0' : 'a'+rnd-10;
rnd = random() % (10 + 'z' - 'a' + 1);
p[k] = rnd < 10 ? rnd + '0' : 'a' + rnd - 10;
}
}

View File

@ -10,9 +10,9 @@
#include <time.h>
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit);
char *strncasestr(const char *s,const char *find, size_t slen);
bool load_file(const char *filename,void *buffer,size_t *buffer_size);
bool load_file_nonempty(const char *filename,void *buffer,size_t *buffer_size);
char *strncasestr(const char *s, const char *find, size_t slen);
bool load_file(const char *filename, void *buffer, size_t *buffer_size);
bool load_file_nonempty(const char *filename, void *buffer, size_t *buffer_size);
bool save_file(const char *filename, const void *buffer, size_t buffer_size);
bool append_to_list_file(const char *filename, const char *s);
@ -32,19 +32,22 @@ void phton64(uint8_t *p, uint64_t v);
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];
}
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[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];
}
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size);
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize);
void fill_pattern(uint8_t *buf, size_t bufsize, const void *pattern, size_t patsize);
int fprint_localtime(FILE *F);
@ -52,12 +55,12 @@ time_t file_mod_time(const char *filename);
typedef struct
{
uint16_t from,to;
uint16_t from, to;
bool neg;
} port_filter;
bool pf_in_range(uint16_t port, const port_filter *pf);
bool pf_parse(const char *s, port_filter *pf);
void fill_random_bytes(uint8_t *p,size_t sz);
void fill_random_az(uint8_t *p,size_t sz);
void fill_random_az09(uint8_t *p,size_t sz);
void fill_random_bytes(uint8_t *p, size_t sz);
void fill_random_az(uint8_t *p, size_t sz);
void fill_random_az09(uint8_t *p, size_t sz);

View File

@ -8,17 +8,19 @@
static bool addpool(strpool **hostlist, char **s, const char *end)
{
char *p;
// advance until eol lowering all chars
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
for (p = *s; p < end && *p && *p != '\r' && *p != '\n'; p++)
*p = tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p - *s))
{
StrPoolDestroy(hostlist);
*hostlist = NULL;
return false;
}
// 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;
return true;
}
@ -31,7 +33,7 @@ bool AppendHostList(strpool **hostlist, char *filename)
FILE *F;
int r;
DLOG_CONDUP("Loading hostlist %s\n",filename);
DLOG_CONDUP("Loading hostlist %s\n", filename);
if (!(F = fopen(filename, "rb")))
{
@ -41,18 +43,19 @@ bool AppendHostList(strpool **hostlist, char *filename)
if (is_gzip(F))
{
r = z_readfile(F,&zbuf,&zsize);
r = z_readfile(F, &zbuf, &zsize);
fclose(F);
if (r==Z_OK)
if (r == Z_OK)
{
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
p = zbuf;
e = zbuf + zsize;
while(p<e)
while (p < e)
{
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,e))
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
continue;
if (!addpool(hostlist, &p, e))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
free(zbuf);
@ -64,19 +67,20 @@ bool AppendHostList(strpool **hostlist, char *filename)
}
else
{
DLOG_ERR("zlib decompression failed : result %d\n",r);
DLOG_ERR("zlib decompression failed : result %d\n", r);
return false;
}
}
else
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, 256, F))
{
p = s;
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,p+strlen(p)))
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
continue;
if (!addpool(hostlist, &p, p + strlen(p)))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
fclose(F);
@ -103,7 +107,8 @@ bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list)
LIST_FOREACH(file, file_list, next)
{
if (!AppendHostList(hostlist, file->str)) return false;
if (!AppendHostList(hostlist, file->str))
return false;
}
return true;
}
@ -114,7 +119,6 @@ bool NonEmptyHostlist(strpool **hostlist)
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
}
bool SearchHostList(strpool *hostlist, const char *host)
{
if (hostlist)
@ -125,9 +129,11 @@ bool SearchHostList(strpool *hostlist, const char *host)
{
bInHostList = StrPoolCheckStr(hostlist, p);
DLOG("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
if (bInHostList) return true;
if (bInHostList)
return true;
p = strchr(p, '.');
if (p) p++;
if (p)
p++;
}
}
return false;
@ -136,13 +142,15 @@ bool SearchHostList(strpool *hostlist, const char *host)
// return : true = apply fooling, false = do not apply
static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded)
{
if (excluded) *excluded = false;
if (excluded)
*excluded = false;
if (hostlist_exclude)
{
DLOG("Checking exclude hostlist\n");
if (SearchHostList(hostlist_exclude, host))
{
if (excluded) *excluded = true;
if (excluded)
*excluded = true;
return false;
}
}
@ -160,7 +168,7 @@ bool HostlistCheck(const char *host, bool *excluded)
if (*params.hostlist_auto_filename)
{
time_t t = file_mod_time(params.hostlist_auto_filename);
if (t!=params.hostlist_auto_mod_time)
if (t != params.hostlist_auto_mod_time)
{
DLOG_CONDUP("Autohostlist was modified by another process. Reloading include hostslist.\n");
if (!LoadIncludeHostLists())

File diff suppressed because it is too large Load Diff

View File

@ -9,26 +9,30 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q)
}
void rawpacket_free(struct rawpacket *rp)
{
if (rp) free(rp->packet);
if (rp)
free(rp->packet);
free(rp);
}
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q)
{
struct rawpacket *rp;
rp = TAILQ_FIRST(q);
if (rp) TAILQ_REMOVE(q, rp, next);
if (rp)
TAILQ_REMOVE(q, rp, next);
return rp;
}
void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
{
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));
if (!rp) return NULL;
if (!rp)
return NULL;
rp->packet = malloc(len);
if (!rp->packet)
@ -36,30 +40,31 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
free(rp);
return NULL;
}
rp->dst = *dst;
rp->fwmark = fwmark;
if (ifout)
{
strncpy(rp->ifout,ifout,sizeof(rp->ifout));
rp->ifout[sizeof(rp->ifout)-1]=0;
strncpy(rp->ifout, ifout, sizeof(rp->ifout));
rp->ifout[sizeof(rp->ifout) - 1] = 0;
}
else
rp->ifout[0]=0;
memcpy(rp->packet,data,len);
rp->len=len;
rp->len_payload=len_payload;
rp->ifout[0] = 0;
memcpy(rp->packet, data, len);
rp->len = len;
rp->len_payload = len_payload;
TAILQ_INSERT_TAIL(q, rp, next);
return rp;
}
unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q)
{
const struct rawpacket *rp;
unsigned int ct=0;
TAILQ_FOREACH(rp, q, next) ct++;
unsigned int ct = 0;
TAILQ_FOREACH(rp, q, next)
ct++;
return ct;
}
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q)

View File

@ -9,11 +9,12 @@
struct rawpacket
{
struct sockaddr_storage dst;
char ifout[IFNAMSIZ+1];
char ifout[IFNAMSIZ + 1];
uint32_t fwmark;
size_t len, len_payload;
uint8_t *packet;
TAILQ_ENTRY(rawpacket) next;
TAILQ_ENTRY(rawpacket)
next;
};
TAILQ_HEAD(rawpacket_tailhead, rawpacket);
@ -21,6 +22,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q);
void rawpacket_queue_destroy(struct rawpacket_tailhead *q);
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q);
unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q);
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 *rawpacket_dequeue(struct rawpacket_tailhead *q);
void rawpacket_free(struct rawpacket *rp);

View File

@ -13,40 +13,39 @@ const char *progname = "nfqws";
#error UNKNOWN_SYSTEM_TIME
#endif
int DLOG_FILE(FILE *F, const char *format, va_list args)
{
return vfprintf(F, format, args);
}
int DLOG_CON(const char *format, int syslog_priority, va_list args)
{
return DLOG_FILE(syslog_priority==LOG_ERR ? stderr : stdout, format, args);
return DLOG_FILE(syslog_priority == LOG_ERR ? stderr : stdout, format, args);
}
int DLOG_FILENAME(const char *filename, const char *format, va_list args)
{
int r;
FILE *F = fopen(filename,"at");
FILE *F = fopen(filename, "at");
if (F)
{
r = DLOG_FILE(F, format, args);
fclose(F);
}
else
r=-1;
r = -1;
return r;
}
static char syslog_buf[1024];
static size_t syslog_buf_sz=0;
static size_t syslog_buf_sz = 0;
static void syslog_buffered(int priority, const char *format, va_list args)
{
if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0)
if (vsnprintf(syslog_buf + syslog_buf_sz, sizeof(syslog_buf) - syslog_buf_sz, format, args) > 0)
{
syslog_buf_sz=strlen(syslog_buf);
syslog_buf_sz = strlen(syslog_buf);
// log when buffer is full or buffer ends with \n
if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n'))
if (syslog_buf_sz >= (sizeof(syslog_buf) - 1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz - 1] == '\n'))
{
syslog(priority,"%s",syslog_buf);
syslog(priority, "%s", syslog_buf);
syslog_buf_sz = 0;
}
}
@ -54,31 +53,31 @@ static void syslog_buffered(int priority, const char *format, va_list args)
static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list args)
{
int r=0;
int r = 0;
va_list args2;
if (condup && !(params.debug && params.debug_target==LOG_TARGET_CONSOLE))
if (condup && !(params.debug && params.debug_target == LOG_TARGET_CONSOLE))
{
va_copy(args2,args);
DLOG_CON(format,syslog_priority,args2);
va_copy(args2, args);
DLOG_CON(format, syslog_priority, args2);
}
if (params.debug)
{
switch(params.debug_target)
switch (params.debug_target)
{
case LOG_TARGET_CONSOLE:
r = DLOG_CON(format,syslog_priority,args);
break;
case LOG_TARGET_FILE:
r = DLOG_FILENAME(params.debug_logfile,format,args);
break;
case LOG_TARGET_SYSLOG:
// skip newlines
syslog_buffered(syslog_priority,format,args);
r = 1;
break;
default:
break;
case LOG_TARGET_CONSOLE:
r = DLOG_CON(format, syslog_priority, args);
break;
case LOG_TARGET_FILE:
r = DLOG_FILENAME(params.debug_logfile, format, args);
break;
case LOG_TARGET_SYSLOG:
// skip newlines
syslog_buffered(syslog_priority, format, args);
r = 1;
break;
default:
break;
}
}
return r;
@ -116,11 +115,10 @@ int DLOG_PERROR(const char *s)
return DLOG_ERR("%s: %s\n", s, strerror(errno));
}
int LOG_APPEND(const char *filename, const char *format, va_list args)
{
int r;
FILE *F = fopen(filename,"at");
FILE *F = fopen(filename, "at");
if (F)
{
fprint_localtime(F);
@ -130,7 +128,7 @@ int LOG_APPEND(const char *filename, const char *format, va_list args)
fclose(F);
}
else
r=-1;
r = -1;
return r;
}

View File

@ -13,27 +13,32 @@
#include <stdio.h>
#include <time.h>
#define TLS_PARTIALS_ENABLE true
#define TLS_PARTIALS_ENABLE true
#define Q_RCVBUF (128*1024) // in bytes
#define Q_SNDBUF (64*1024) // in bytes
#define RAW_SNDBUF (64*1024) // in bytes
#define Q_RCVBUF (128 * 1024) // in bytes
#define Q_SNDBUF (64 * 1024) // in bytes
#define RAW_SNDBUF (64 * 1024) // in bytes
#define Q_MAXLEN 1024 // in packets
#define Q_MAXLEN 1024 // in packets
#define BADSEQ_INCREMENT_DEFAULT -10000
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000
#define BADSEQ_INCREMENT_DEFAULT -10000
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000
#define IPFRAG_UDP_DEFAULT 8
#define IPFRAG_TCP_DEFAULT 32
#define UDPLEN_INCREMENT_DEFAULT 2
#define UDPLEN_INCREMENT_DEFAULT 2
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
#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
{
@ -41,8 +46,8 @@ struct params_s
char debug_logfile[PATH_MAX];
bool debug;
uint16_t wsize,wssize;
uint8_t wscale,wsscale;
uint16_t wsize, wssize;
uint8_t wscale, wsscale;
char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int wssize_cutoff;
#ifdef __linux__
@ -50,12 +55,12 @@ struct params_s
#elif defined(BSD)
uint16_t port; // divert port
#endif
char bind_fix4,bind_fix6;
char bind_fix4, bind_fix6;
bool hostcase, hostnospace, domcase;
char hostspell[4];
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
bool desync_retrans,desync_skip_nosni,desync_any_proto;
unsigned int desync_repeats,desync_split_pos,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp;
enum dpi_desync_mode desync_mode0, desync_mode, desync_mode2;
bool desync_retrans, desync_skip_nosni, desync_any_proto;
unsigned int desync_repeats, desync_split_pos, desync_seqovl, desync_ipfrag_pos_tcp, desync_ipfrag_pos_udp;
enum httpreqpos desync_split_http_req;
enum tlspos desync_split_tls;
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
@ -65,13 +70,13 @@ struct params_s
uint32_t desync_fooling_mode;
uint32_t desync_fwmark; // unused in BSD
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
uint8_t fake_http[1460],fake_tls[1460],fake_unknown[1460],fake_syndata[1460],seqovl_pattern[1460];
uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472];
size_t fake_http_size,fake_tls_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size;
uint8_t fake_http[1460], fake_tls[1460], fake_unknown[1460], fake_syndata[1460], seqovl_pattern[1460];
uint8_t fake_unknown_udp[1472], udplen_pattern[1472], fake_quic[1472], fake_wg[1472], fake_dht[1472];
size_t fake_http_size, fake_tls_size, fake_quic_size, fake_wg_size, fake_dht_size, fake_unknown_size, fake_syndata_size, fake_unknown_udp_size;
int udplen_increment;
#ifdef __CYGWIN__
struct str_list_head ssid_filter,nlm_filter;
struct str_list_head ssid_filter, nlm_filter;
#else
bool droproot;
uid_t uid;

View File

@ -5,33 +5,33 @@
#include <stdio.h>
#define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) { \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) \
{ \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype *)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
}
#undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
@ -65,13 +65,8 @@ void StrPoolDestroy(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);
ADD_STR_POOL(hostfail_pool, pp, s, slen)
@ -79,7 +74,7 @@ hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
elem->counter = 0;
return elem;
}
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s)
hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s)
{
hostfail_pool *elem;
HASH_FIND_STR(p, s, elem);
@ -104,7 +99,7 @@ void HostFailPoolPurge(hostfail_pool **pp)
}
}
}
static time_t host_fail_purge_prev=0;
static time_t host_fail_purge_prev = 0;
void HostFailPoolPurgeRateLimited(hostfail_pool **pp)
{
time_t now = time(NULL);
@ -120,14 +115,14 @@ void HostFailPoolDump(hostfail_pool *p)
hostfail_pool *elem, *tmp;
time_t now = time(NULL);
HASH_ITER(hh, p, elem, tmp)
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)
{
struct str_list *entry = malloc(sizeof(struct str_list));
if (!entry) return false;
if (!entry)
return false;
entry->str = strdup(filename);
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)
{
if (entry->str) free(entry->str);
if (entry->str)
free(entry->str);
free(entry);
}
void strlist_destroy(struct str_list_head *head)

View File

@ -5,38 +5,41 @@
#include <sys/queue.h>
#include <time.h>
//#define HASH_BLOOM 20
// #define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1
#define HASH_FUNCTION HASH_BER
#include "uthash.h"
typedef struct strpool {
char *str; /* key */
UT_hash_handle hh; /* makes this structure hashable */
typedef struct strpool
{
char *str; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} strpool;
void StrPoolDestroy(strpool **pp);
bool StrPoolAddStr(strpool **pp,const char *s);
bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
bool StrPoolCheckStr(strpool *p,const char *s);
bool StrPoolAddStr(strpool **pp, const char *s);
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen);
bool StrPoolCheckStr(strpool *p, const char *s);
struct str_list {
char *str;
LIST_ENTRY(str_list) next;
struct str_list
{
char *str;
LIST_ENTRY(str_list)
next;
};
LIST_HEAD(str_list_head, str_list);
typedef struct hostfail_pool {
char *str; /* key */
int counter; /* value */
time_t expire; /* when to expire record (unixtime) */
UT_hash_handle hh; /* makes this structure hashable */
typedef struct hostfail_pool
{
char *str; /* key */
int counter; /* value */
time_t expire; /* when to expire record (unixtime) */
UT_hash_handle hh; /* makes this structure hashable */
} hostfail_pool;
void HostFailPoolDestroy(hostfail_pool **pp);
hostfail_pool *HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time);
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s);
hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time);
hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s);
void HostFailPoolDel(hostfail_pool **pp, hostfail_pool *elem);
void HostFailPoolPurge(hostfail_pool **pp);
void HostFailPoolPurgeRateLimited(hostfail_pool **pp);

View File

@ -7,7 +7,7 @@
#include <arpa/inet.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 **method;
@ -22,24 +22,26 @@ const char *HttpMethod(const uint8_t *data, size_t len)
}
bool IsHttp(const uint8_t *data, size_t len)
{
return !!HttpMethod(data,len);
return !!HttpMethod(data, len);
}
// pHost points to "Host: ..."
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs)
bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs)
{
if (!*pHost)
{
*pHost = memmem(buf, bs, "\nHost:", 6);
if (*pHost) (*pHost)++;
if (*pHost)
(*pHost)++;
}
return !!*pHost;
}
bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs)
bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs)
{
if (!*pHost)
{
*pHost = memmem(buf, bs, "\nHost:", 6);
if (*pHost) (*pHost)++;
if (*pHost)
(*pHost)++;
}
return !!*pHost;
}
@ -47,32 +49,37 @@ bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs)
bool IsHttpReply(const uint8_t *data, size_t len)
{
// HTTP/1.x 200\r\n
return len>14 && !memcmp(data,"HTTP/1.",7) && (data[7]=='0' || data[7]=='1') && data[8]==' ' &&
data[9]>='0' && data[9]<='9' &&
data[10]>='0' && data[10]<='9' &&
data[11]>='0' && data[11]<='9';
return len > 14 && !memcmp(data, "HTTP/1.", 7) && (data[7] == '0' || data[7] == '1') && data[8] == ' ' &&
data[9] >= '0' && data[9] <= '9' &&
data[10] >= '0' && data[10] <= '9' &&
data[11] >= '0' && data[11] <= '9';
}
int HttpReplyCode(const uint8_t *data, size_t len)
{
return (data[9]-'0')*100 + (data[10]-'0')*10 + (data[11]-'0');
return (data[9] - '0') * 100 + (data[10] - '0') * 10 + (data[11] - '0');
}
bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf)
{
const uint8_t *p, *s, *e = data + len;
p = (uint8_t*)strncasestr((char*)data, header, len);
if (!p) return false;
p = (uint8_t *)strncasestr((char *)data, header, len);
if (!p)
return false;
p += strlen(header);
while (p < e && (*p == ' ' || *p == '\t')) p++;
while (p < e && (*p == ' ' || *p == '\t'))
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)
{
size_t slen = s - p;
if (buf && len_buf)
{
if (slen >= len_buf) slen = len_buf - 1;
for (size_t i = 0; i < slen; i++) buf[i] = tolower(p[i]);
if (slen >= len_buf)
slen = len_buf - 1;
for (size_t i = 0; i < slen; i++)
buf[i] = tolower(p[i]);
buf[slen] = 0;
}
return true;
@ -85,83 +92,97 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
}
const char *HttpFind2ndLevelDomain(const char *host)
{
const char *p=NULL;
const char *p = NULL;
if (*host)
{
for (p = host + strlen(host)-1; p>host && *p!='.'; p--);
if (*p=='.') for (p--; p>host && *p!='.'; p--);
if (*p=='.') p++;
for (p = host + strlen(host) - 1; p > host && *p != '.'; p--)
;
if (*p == '.')
for (p--; p > host && *p != '.'; p--)
;
if (*p == '.')
p++;
}
return p;
}
// DPI redirects are global redirects to another domain
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host)
{
char loc[256],*redirect_host, *p;
char loc[256], *redirect_host, *p;
int code;
if (!host || !*host) return false;
code = HttpReplyCode(data,len);
if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false;
if (!host || !*host)
return false;
code = HttpReplyCode(data, len);
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
if (!strncmp(loc,"http://",7))
redirect_host=loc+7;
else if (!strncmp(loc,"https://",8))
redirect_host=loc+8;
if (!strncmp(loc, "http://", 7))
redirect_host = loc + 7;
else if (!strncmp(loc, "https://", 8))
redirect_host = loc + 8;
else
return false;
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
for(p=redirect_host; *p && *p!='/' ; p++);
*p=0;
if (!*redirect_host) return false;
for (p = redirect_host; *p && *p != '/'; p++)
;
*p = 0;
if (!*redirect_host)
return false;
// somethinkg like : censor.net
// extract 2nd level domains
const char *dhost = HttpFind2ndLevelDomain(host);
const char *drhost = HttpFind2ndLevelDomain(redirect_host);
return strcasecmp(dhost, drhost)!=0;
return strcasecmp(dhost, drhost) != 0;
}
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
{
const uint8_t *method, *host;
int i;
switch(tpos_type)
{
case httpreqpos_method:
// recognize some tpws pre-applied hacks
method=http;
if (sz<10) break;
if (*method=='\n' || *method=='\r') method++;
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;
case httpreqpos_host:
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
{
host+=5;
if (*host==' ') host++;
return host-http;
}
break;
case httpreqpos_pos:
break;
default:
return 0;
}
return hpos_pos<sz ? hpos_pos : 0;
}
switch (tpos_type)
{
case httpreqpos_method:
// recognize some tpws pre-applied hacks
method = http;
if (sz < 10)
break;
if (*method == '\n' || *method == '\r')
method++;
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;
case httpreqpos_host:
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
{
host += 5;
if (*host == ' ')
host++;
return host - http;
}
break;
case httpreqpos_pos:
break;
default:
return 0;
}
return hpos_pos < sz ? hpos_pos : 0;
}
uint16_t TLSRecordDataLen(const uint8_t *data)
{
@ -173,7 +194,7 @@ size_t TLSRecordLen(const uint8_t *data)
}
bool IsTLSRecordFull(const uint8_t *data, size_t len)
{
return TLSRecordLen(data)<=len;
return TLSRecordLen(data) <= len;
}
bool IsTLSClientHello(const uint8_t *data, size_t len, bool bPartialIsOK)
{
@ -186,14 +207,13 @@ size_t TLSHandshakeLen(const uint8_t *data)
}
bool IsTLSHandshakeClientHello(const uint8_t *data, size_t len)
{
return len>=4 && data[0]==0x01 && TLSHandshakeLen(data)>0;
return len >= 4 && data[0] == 0x01 && TLSHandshakeLen(data) > 0;
}
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
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;
if (!bPartialIsOK && !IsTLSHandshakeFull(data,len)) return false;
if (!bPartialIsOK && !IsTLSHandshakeFull(data, len))
return false;
l = 1 + 3 + 2 + 32;
// SessionIDLength
if (len < (l + 1)) return false;
if (len < (l + 1))
return false;
l += data[l] + 1;
// CipherSuitesLength
if (len < (l + 2)) return false;
if (len < (l + 2))
return false;
l += pntoh16(data + l) + 2;
// CompressionMethodsLength
if (len < (l + 1)) return false;
if (len < (l + 1))
return false;
l += data[l] + 1;
// ExtensionsLength
if (len < (l + 2)) return false;
if (len < (l + 2))
return false;
data += l; len -= l;
data += l;
len -= l;
l = pntoh16(data);
data += 2; len -= 2;
data += 2;
len -= 2;
if (bPartialIsOK)
{
if (len < l) l = len;
if (len < l)
l = len;
}
else
{
if (len < l) return false;
if (len < l)
return false;
}
while (l >= 4)
{
uint16_t etype = pntoh16(data);
size_t elen = pntoh16(data + 2);
data += 4; l -= 4;
if (l < elen) break;
data += 4;
l -= 4;
if (l < elen)
break;
if (etype == type)
{
if (ext && len_ext)
@ -255,7 +286,8 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
}
return true;
}
data += elen; l -= elen;
data += elen;
l -= elen;
}
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 Length
size_t reclen;
if (!IsTLSClientHello(data, len, bPartialIsOK)) return false;
reclen=TLSRecordLen(data);
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
if (!IsTLSClientHello(data, len, bPartialIsOK))
return false;
reclen = TLSRecordLen(data);
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);
}
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
// u8 data+2 - server name type. 0=host_name
// 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);
ext += 5; elen -= 5;
if (slen < elen) return false;
ext += 5;
elen -= 5;
if (slen < elen)
return false;
if (host && len_host)
{
if (slen >= len_host) slen = len_host - 1;
for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]);
if (slen >= len_host)
slen = len_host - 1;
for (size_t i = 0; i < slen; i++)
host[i] = tolower(ext[i]);
host[slen] = 0;
}
return true;
@ -294,7 +333,8 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len
const uint8_t *ext;
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);
}
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK)
@ -302,48 +342,52 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
const uint8_t *ext;
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);
}
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
{
size_t elen;
const uint8_t *ext;
switch(tpos_type)
switch (tpos_type)
{
case tlspos_sni:
case tlspos_sniext:
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
// fall through
case tlspos_pos:
return tpos_pos<sz ? tpos_pos : 0;
default:
return 0;
case tlspos_sni:
case tlspos_sniext:
if (TLSFindExt(tls, sz, 0, &ext, &elen, false))
return (tpos_type == tlspos_sni) ? ext - tls + 6 : ext - tls + 1;
// fall through
case tlspos_pos:
return tpos_pos < sz ? tpos_pos : 0;
default:
return 0;
}
}
static uint8_t tvb_get_varint(const uint8_t *tvb, uint64_t *value)
{
switch (*tvb >> 6)
{
case 0: /* 0b00 => 1 byte length (6 bits Usable) */
if (value) *value = *tvb & 0x3F;
if (value)
*value = *tvb & 0x3F;
return 1;
case 1: /* 0b01 => 2 bytes length (14 bits Usable) */
if (value) *value = pntoh16(tvb) & 0x3FFF;
if (value)
*value = pntoh16(tvb) & 0x3FFF;
return 2;
case 2: /* 0b10 => 4 bytes length (30 bits Usable) */
if (value) *value = pntoh32(tvb) & 0x3FFFFFFF;
if (value)
*value = pntoh32(tvb) & 0x3FFFFFFF;
return 4;
case 3: /* 0b11 => 8 bytes length (62 bits Usable) */
if (value) *value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF;
if (value)
*value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF;
return 8;
}
// impossible case
if (*value) *value = 0;
if (*value)
*value = 0;
return 0;
}
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;
uint64_t coff, clen;
if (len < 3 || *data != 6) return false;
if ((offset+tvb_get_size(data[offset])) >= len) return false;
if (len < 3 || *data != 6)
return false;
if ((offset + tvb_get_size(data[offset])) >= len)
return false;
offset += tvb_get_varint(data + offset, &coff);
// 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);
if ((offset + clen) > len || !IsTLSHandshakeClientHello(data+offset,clen)) return false;
if (hello_offset) *hello_offset = offset;
if (hello_len) *hello_len = (size_t)clen;
if ((offset + clen) > len || !IsTLSHandshakeClientHello(data + offset, clen))
return false;
if (hello_offset)
*hello_offset = offset;
if (hello_len)
*hello_len = (size_t)clen;
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)
{
/* IETF Draft versions */
if ((version >> 8) == 0xff0000) {
if ((version >> 8) == 0xff0000)
{
return (uint8_t)version;
}
/* Facebook mvfst, based on draft -22. */
if (version == 0xfaceb001) {
if (version == 0xfaceb001)
{
return 22;
}
/* Facebook mvfst, based on draft -27. */
if (version == 0xfaceb002 || version == 0xfaceb00e) {
if (version == 0xfaceb002 || version == 0xfaceb00e)
{
return 27;
}
/* GQUIC Q050, T050 and T051: they are not really based on any drafts,
* but we must return a sensible value */
if (version == 0x51303530 ||
version == 0x54303530 ||
version == 0x54303531) {
version == 0x54303531)
{
return 27;
}
/* 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
we don't have a real version here! Let's hope that we need to handle
only latest drafts... */
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) {
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a)
{
return 29;
}
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
final draft version */
if (version == 0x00000001) {
if (version == 0x00000001)
{
return 34;
}
/* QUIC Version 2 */
/* 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 0;
@ -418,7 +475,7 @@ static bool is_quic_draft_max(uint32_t draft_version, uint8_t max_version)
}
static bool is_quic_v2(uint32_t version)
{
return version == 0x6b3343cf;
return version == 0x6b3343cf;
}
static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len)
@ -426,9 +483,11 @@ static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, co
uint8_t hkdflabel[64];
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;
if (hkdflabel_size > sizeof(hkdflabel)) return false;
if (hkdflabel_size > sizeof(hkdflabel))
return false;
phton16(hkdflabel, out_len);
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] = {
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] = {
0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7,
0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02,
0xc3,
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] = {
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] = {
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] = {
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] = {
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] = {
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] = {
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;
const uint8_t *salt;
uint8_t secret[USHAMaxHashSize];
uint8_t draft_version = QUICDraftVersion(version);
if (version == 0x51303530) {
if (version == 0x51303530)
{
salt = hanshake_salt_draft_q50;
}
else if (version == 0x54303530) {
else if (version == 0x54303530)
{
salt = hanshake_salt_draft_t50;
}
else if (version == 0x54303531) {
else if (version == 0x54303531)
{
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;
}
else if (is_quic_draft_max(draft_version, 28)) {
else if (is_quic_draft_max(draft_version, 28))
{
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;
}
else if (is_quic_draft_max(draft_version, 34)) {
else if (is_quic_draft_max(draft_version, 34))
{
salt = handshake_salt_v1;
}
else {
else
{
salt = handshake_salt_v2;
}
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))
return false;
@ -525,16 +604,17 @@ static bool quic_derive_initial_secret(const quic_cid_t *cid, uint8_t *client_in
}
bool QUICIsLongHeader(const uint8_t *data, size_t len)
{
return len>=9 && !!(*data & 0x80);
return len >= 9 && !!(*data & 0x80);
}
uint32_t QUICExtractVersion(const uint8_t *data, size_t len)
{
// long header, fixed bit, type=initial
return QUICIsLongHeader(data, len) ? ntohl(*(uint32_t*)(data + 1)) : 0;
return QUICIsLongHeader(data, len) ? ntohl(*(uint32_t *)(data + 1)) : 0;
}
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];
memcpy(&cid->cid, data + 6, data[5]);
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)
{
uint32_t ver = QUICExtractVersion(data, data_len);
if (!ver) return false;
if (!ver)
return false;
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];
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];
bool v1_label = !is_quic_v2(ver);
@ -559,23 +642,28 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
return false;
}
uint64_t payload_len,token_len;
uint64_t payload_len, token_len;
size_t pn_offset;
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];
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 += 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);
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();
uint8_t sample_enc[16];
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];
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];
memcpy(pkn_bytes, data + pn_offset, pkn_len);
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;
if (cryptlen > *clean_len) return false;
if (cryptlen > *clean_len)
return false;
*clean_len = cryptlen;
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;
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);
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)))
return false;
@ -609,48 +701,56 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16);
}
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len)
bool QUICDefragCrypto(const uint8_t *clean, size_t clean_len, uint8_t *defrag, size_t *defrag_len)
{
// Crypto frame can be split into multiple chunks
// chromium randomly splits it and pads with zero/one bytes to force support the standard
// mozilla does not split
if (*defrag_len<10) return false;
uint8_t *defrag_data = defrag+10;
size_t defrag_data_len = *defrag_len-10;
if (*defrag_len < 10)
return false;
uint8_t *defrag_data = defrag + 10;
size_t defrag_data_len = *defrag_len - 10;
uint8_t ft;
uint64_t offset,sz,szmax=0,zeropos=0,pos=0;
bool found=false;
uint64_t offset, sz, szmax = 0, zeropos = 0, pos = 0;
bool found = false;
while(pos<clean_len)
while (pos < clean_len)
{
ft = clean[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;
pos += tvb_get_varint(clean+pos, &offset);
if ((pos + tvb_get_size(clean[pos]) >= clean_len))
return false;
pos += tvb_get_varint(clean + pos, &offset);
if ((pos+tvb_get_size(clean[pos])>clean_len)) return false;
pos += tvb_get_varint(clean+pos, &sz);
if ((pos+sz)>clean_len) return false;
if ((pos + tvb_get_size(clean[pos]) > clean_len))
return false;
pos += tvb_get_varint(clean + pos, &sz);
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)
// make sure no uninitialized gaps exist in case of not full fragment coverage
memset(defrag_data+zeropos,0,offset-zeropos);
if ((offset+sz) > zeropos)
zeropos=offset+sz;
memcpy(defrag_data+offset,clean+pos,sz);
if ((offset+sz) > szmax) szmax = offset+sz;
memset(defrag_data + zeropos, 0, offset - zeropos);
if ((offset + sz) > zeropos)
zeropos = offset + sz;
memcpy(defrag_data + offset, clean + pos, sz);
if ((offset + sz) > szmax)
szmax = offset + sz;
found=true;
pos+=sz;
found = true;
pos += sz;
}
}
if (found)
@ -659,31 +759,38 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
defrag[1] = 0; // offset
// 2..9 - length 64 bit
// +10 - data start
phton64(defrag+2,szmax);
phton64(defrag + 2, szmax);
defrag[2] |= 0xC0; // 64 bit value
*defrag_len = (size_t)(szmax+10);
*defrag_len = (size_t)(szmax + 10);
}
return found;
}
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 (bDecryptOK) *bDecryptOK=false;
if (bIsCryptoHello)
*bIsCryptoHello = false;
if (bDecryptOK)
*bDecryptOK = false;
uint8_t clean[1500];
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];
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;
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len)) return false;
if (bIsCryptoHello) *bIsCryptoHello=true;
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len))
return false;
if (bIsCryptoHello)
*bIsCryptoHello = true;
return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, true);
}
@ -692,47 +799,53 @@ bool IsQUICInitial(const uint8_t *data, size_t len)
{
// too small packets are not likely to be initials with client hello
// 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);
if (QUICDraftVersion(ver) < 11) return false;
uint32_t ver = QUICExtractVersion(data, len);
if (QUICDraftVersion(ver) < 11)
return false;
// quic v1 : initial packets are 00b
// quic v2 : initial packets are 01b
if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00)) return false;
// QUIC v1 : initial packets are 00b
// QUIC v2 : initial packets are 01b
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
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];
// SCID
if (data[offset] > QUIC_MAX_CID_LENGTH) return false;
if (data[offset] > QUIC_MAX_CID_LENGTH)
return false;
offset += 1 + data[offset];
// token length
offset += tvb_get_varint(data + offset, &sz);
offset += sz;
if (offset >= len) return false;
if (offset >= len)
return false;
// 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);
offset += sz;
if (offset > len) return false;
if (offset > len)
return false;
// client hello cannot be too small. likely ACK
return sz>=96;
// ClientHello cannot be too small. likely ACK
return sz >= 96;
}
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;
}
bool IsDhtD1(const uint8_t *data, size_t len)
{
return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e';
return len >= 7 && data[0] == 'd' && data[1] == '1' && data[len - 1] == 'e';
}

View File

@ -10,8 +10,8 @@
extern const char *http_methods[9];
const char *HttpMethod(const uint8_t *data, size_t len);
bool IsHttp(const uint8_t *data, size_t len);
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs);
bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs);
bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs);
bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs);
// header must be passed like this : "\nHost:"
bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf);
bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host);
@ -21,7 +21,13 @@ const char *HttpFind2ndLevelDomain(const char *host);
int HttpReplyCode(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply
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);
uint16_t TLSRecordDataLen(const uint8_t *data);
@ -35,16 +41,23 @@ 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 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);
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);
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
bool IsDhtD1(const uint8_t *data, size_t len);
#define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid {
uint8_t len;
uint8_t cid[QUIC_MAX_CID_LENGTH];
#define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid
{
uint8_t len;
uint8_t cid[QUIC_MAX_CID_LENGTH];
} quic_cid_t;
bool IsQUICInitial(const uint8_t *data, size_t len);
@ -55,5 +68,5 @@ uint8_t QUICDraftVersion(uint32_t version);
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 QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len);
bool QUICDefragCrypto(const uint8_t *clean, size_t clean_len, uint8_t *defrag, size_t *defrag_len);
bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);

186
nfq/sec.c
View File

@ -25,128 +25,127 @@
// block most of the undesired syscalls to harden against code execution
static long blocked_syscalls[] = {
#ifdef SYS_execv
SYS_execv,
SYS_execv,
#endif
SYS_execve,
SYS_execve,
#ifdef SYS_execveat
SYS_execveat,
SYS_execveat,
#endif
#ifdef SYS_exec_with_loader
SYS_exec_with_loader,
SYS_exec_with_loader,
#endif
#ifdef SYS_clone
SYS_clone,
SYS_clone,
#endif
#ifdef SYS_clone2
SYS_clone2,
SYS_clone2,
#endif
#ifdef SYS_clone3
SYS_clone3,
SYS_clone3,
#endif
#ifdef SYS_osf_execve
SYS_osf_execve,
SYS_osf_execve,
#endif
#ifdef SYS_fork
SYS_fork,
SYS_fork,
#endif
#ifdef SYS_vfork
SYS_vfork,
SYS_vfork,
#endif
#ifdef SYS_uselib
SYS_uselib,
SYS_uselib,
#endif
#ifdef SYS_unlink
SYS_unlink,
SYS_unlink,
#endif
SYS_unlinkat,
SYS_unlinkat,
#ifdef SYS_chmod
SYS_chmod,
SYS_chmod,
#endif
SYS_fchmod,SYS_fchmodat,
SYS_fchmod, SYS_fchmodat,
#ifdef SYS_chown
SYS_chown,
SYS_chown,
#endif
#ifdef SYS_chown32
SYS_chown32,
SYS_chown32,
#endif
SYS_fchown,
SYS_fchown,
#ifdef SYS_fchown32
SYS_fchown32,
SYS_fchown32,
#endif
#ifdef SYS_lchown
SYS_lchown,
SYS_lchown,
#endif
#ifdef SYS_lchown32
SYS_lchown32,
SYS_lchown32,
#endif
SYS_fchownat,
SYS_fchownat,
#ifdef SYS_symlink
SYS_symlink,
SYS_symlink,
#endif
SYS_symlinkat,
SYS_symlinkat,
#ifdef SYS_link
SYS_link,
SYS_link,
#endif
SYS_linkat,
SYS_linkat,
#ifdef SYS_pkey_mprotect
SYS_pkey_mprotect,
SYS_pkey_mprotect,
#endif
SYS_mprotect,
SYS_truncate,
SYS_mprotect,
SYS_truncate,
#ifdef SYS_truncate64
SYS_truncate64,
SYS_truncate64,
#endif
SYS_ftruncate,
SYS_ftruncate,
#ifdef SYS_ftruncate64
SYS_ftruncate64,
SYS_ftruncate64,
#endif
#ifdef SYS_mknod
SYS_mknod,
SYS_mknod,
#endif
SYS_mknodat,
SYS_mknodat,
#ifdef SYS_mkdir
SYS_mkdir,
SYS_mkdir,
#endif
SYS_mkdirat,
SYS_mkdirat,
#ifdef SYS_rmdir
SYS_rmdir,
SYS_rmdir,
#endif
#ifdef SYS_rename
SYS_rename,
SYS_rename,
#endif
#ifdef SYS_renameat2
SYS_renameat2,
SYS_renameat2,
#endif
#ifdef SYS_renameat
SYS_renameat,
SYS_renameat,
#endif
#ifdef SYS_readdir
SYS_readdir,
SYS_readdir,
#endif
#ifdef SYS_getdents
SYS_getdents,
SYS_getdents,
#endif
#ifdef SYS_getdents64
SYS_getdents64,
SYS_getdents64,
#endif
#ifdef SYS_process_vm_readv
SYS_process_vm_readv,
SYS_process_vm_readv,
#endif
#ifdef SYS_process_vm_writev
SYS_process_vm_writev,
SYS_process_vm_writev,
#endif
#ifdef SYS_process_madvise
SYS_process_madvise,
SYS_process_madvise,
#endif
#ifdef SYS_tkill
SYS_tkill,
SYS_tkill,
#endif
#ifdef SYS_tgkill
SYS_tgkill,
SYS_tgkill,
#endif
SYS_kill, SYS_ptrace
};
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls))
SYS_kill, SYS_ptrace};
#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)
{
@ -159,13 +158,13 @@ static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf,
static bool set_seccomp(void)
{
#ifdef __X32_SYSCALL_BIT
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
#else
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
#endif
struct sock_filter sockf[SECCOMP_PROG_SIZE];
struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE, .filter = sockf };
int i,idx=0;
struct sock_fprog prog = {.len = SECCOMP_PROG_SIZE, .filter = sockf};
int i, idx = 0;
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr);
#ifdef __X32_SYSCALL_BIT
@ -178,19 +177,19 @@ static bool set_seccomp(void)
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr);
#endif
/*
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr
*/
for(i=0 ; i<BLOCKED_SYSCALL_COUNT ; i++)
/*
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr
*/
for (i = 0; i < BLOCKED_SYSCALL_COUNT; i++)
{
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, BLOCKED_SYSCALL_COUNT-i, 0, blocked_syscalls[i]);
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, BLOCKED_SYSCALL_COUNT - i, 0, blocked_syscalls[i]);
}
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_ALLOW); // success case
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); // fail case
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); // fail case
return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) >= 0;
}
@ -201,42 +200,41 @@ bool sec_harden(void)
DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)");
return false;
}
#if ARCH_NR!=0
#if ARCH_NR != 0
if (!set_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;
}
#endif
return true;
}
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_data_struct cd[2];
uint32_t c0 = (uint32_t)caps;
uint32_t c1 = (uint32_t)(caps>>32);
uint32_t c1 = (uint32_t)(caps >> 32);
return !capget(&ch,cd) && (cd[0].effective & c0)==c0 && (cd[1].effective & c1)==c1;
return !capget(&ch, cd) && (cd[0].effective & c0) == c0 && (cd[1].effective & c1) == c1;
}
bool setpcap(uint64_t caps)
{
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
struct __user_cap_data_struct cd[2];
cd[0].effective = cd[0].permitted = (uint32_t)caps;
cd[0].inheritable = 0;
cd[1].effective = cd[1].permitted = (uint32_t)(caps>>32);
cd[1].effective = cd[1].permitted = (uint32_t)(caps >> 32);
cd[1].inheritable = 0;
return !capset(&ch,cd);
return !capset(&ch, cd);
}
int getmaxcap(void)
{
@ -248,18 +246,17 @@ int getmaxcap(void)
fclose(F);
}
return maxcap;
}
bool dropcaps(void)
{
uint64_t caps = (1<<CAP_NET_ADMIN)|(1<<CAP_NET_RAW);
uint64_t caps = (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
int maxcap = getmaxcap();
if (setpcap(caps|(1<<CAP_SETPCAP)))
if (setpcap(caps | (1 << CAP_SETPCAP)))
{
for (int cap = 0; cap <= maxcap; cap++)
{
if (prctl(PR_CAPBSET_DROP, cap)<0)
if (prctl(PR_CAPBSET_DROP, cap) < 0)
{
DLOG_ERR("could not drop bound cap %d\n", cap);
DLOG_PERROR("cap_drop_bound");
@ -291,7 +288,7 @@ bool can_drop_root(void)
{
#ifdef __linux__
// has some caps
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID)|(1<<CAP_SETPCAP));
return checkpcap((1 << CAP_SETUID) | (1 << CAP_SETGID) | (1 << CAP_SETPCAP));
#else
// effective root
return !geteuid();
@ -308,7 +305,7 @@ bool droproot(uid_t uid, gid_t gid)
}
#endif
// drop all SGIDs
if (setgroups(0,NULL))
if (setgroups(0, NULL))
{
DLOG_PERROR("setgroups");
return false;
@ -332,24 +329,23 @@ bool droproot(uid_t uid, gid_t gid)
void print_id(void)
{
int i,N;
gid_t g[128];
int i, N;
gid_t g[128];
DLOG_CONDUP("Running as UID=%u GID=",getuid());
N=getgroups(sizeof(g)/sizeof(*g),g);
if (N>0)
{
for(i=0;i<N;i++)
DLOG_CONDUP(i==(N-1) ? "%u" : "%u,", g[i]);
DLOG_CONDUP("\n");
}
else
DLOG_CONDUP("%u\n",getgid());
DLOG_CONDUP("Running as UID=%u GID=", getuid());
N = getgroups(sizeof(g) / sizeof(*g), g);
if (N > 0)
{
for (i = 0; i < N; i++)
DLOG_CONDUP(i == (N - 1) ? "%u" : "%u,", g[i]);
DLOG_CONDUP("\n");
}
else
DLOG_CONDUP("%u\n", getgid());
}
#endif
void daemonize(void)
{
int pid;

View File

@ -20,67 +20,66 @@ bool dropcaps(void);
#if defined(__aarch64__)
# define ARCH_NR AUDIT_ARCH_AARCH64
#define ARCH_NR AUDIT_ARCH_AARCH64
#elif defined(__amd64__)
# define ARCH_NR AUDIT_ARCH_X86_64
#define ARCH_NR AUDIT_ARCH_X86_64
#elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__))
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_ARM
# else
# define ARCH_NR AUDIT_ARCH_ARMEB
# endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_ARM
#else
#define ARCH_NR AUDIT_ARCH_ARMEB
#endif
#elif defined(__i386__)
# define ARCH_NR AUDIT_ARCH_I386
#define ARCH_NR AUDIT_ARCH_I386
#elif defined(__mips__)
#if _MIPS_SIM == _MIPS_SIM_ABI32
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_MIPSEL
# else
# define ARCH_NR AUDIT_ARCH_MIPS
# endif
#elif _MIPS_SIM == _MIPS_SIM_ABI64
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_MIPSEL64
# else
# define ARCH_NR AUDIT_ARCH_MIPS64
# endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_MIPSEL
#else
# error "Unsupported mips abi"
#define ARCH_NR AUDIT_ARCH_MIPS
#endif
#elif _MIPS_SIM == _MIPS_SIM_ABI64
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_MIPSEL64
#else
#define ARCH_NR AUDIT_ARCH_MIPS64
#endif
#else
#error "Unsupported MIPS ABI"
#endif
#elif defined(__PPC64__)
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_PPC64LE
# else
# define ARCH_NR AUDIT_ARCH_PPC64
# endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_PPC64LE
#else
#define ARCH_NR AUDIT_ARCH_PPC64
#endif
#elif defined(__PPC__)
# define ARCH_NR AUDIT_ARCH_PPC
#define ARCH_NR AUDIT_ARCH_PPC
#elif __riscv && __riscv_xlen == 64
# define ARCH_NR AUDIT_ARCH_RISCV64
#define ARCH_NR AUDIT_ARCH_RISCV64
#else
# error "Platform does not support seccomp filter yet"
#error "Platform does not support seccomp filter yet"
#endif
#endif
#ifndef __CYGWIN__
bool sec_harden(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_NAME, (LPSERVICE_MAIN_FUNCTION)service_main},
{NULL, NULL}
};
{NULL, NULL}};
service_argc = argc;
service_argv = argv;
@ -76,5 +75,4 @@ void service_main(int argc __attribute__((unused)), char *argv[] __attribute__((
return;
}
#endif

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
#ifndef SHIM_SYS_EPOLL_H
#define SHIM_SYS_EPOLL_H
#ifndef SHIM_SYS_EPOLL_H
#define SHIM_SYS_EPOLL_H
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
#include <stdint.h>
@ -18,7 +19,10 @@ extern "C" {
#define EPOLL_CLOEXEC O_CLOEXEC
#define EPOLL_NONBLOCK O_NONBLOCK
enum EPOLL_EVENTS { __EPOLL_DUMMY };
enum EPOLL_EVENTS
{
__EPOLL_DUMMY
};
#define EPOLLIN 0x001
#define EPOLLPRI 0x002
#define EPOLLOUT 0x004
@ -31,48 +35,47 @@ enum EPOLL_EVENTS { __EPOLL_DUMMY };
#define EPOLLERR 0x008
#define EPOLLHUP 0x010
#define EPOLLRDHUP 0x2000
#define EPOLLEXCLUSIVE (1U<<28)
#define EPOLLWAKEUP (1U<<29)
#define EPOLLONESHOT (1U<<30)
#define EPOLLET (1U<<31)
#define EPOLLEXCLUSIVE (1U << 28)
#define EPOLLWAKEUP (1U << 29)
#define EPOLLONESHOT (1U << 30)
#define EPOLLET (1U << 31)
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
#define EPOLL_CTL_MOD 3
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
typedef union epoll_data
{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events;
epoll_data_t data;
}
struct epoll_event
{
uint32_t events;
epoll_data_t data;
}
#ifdef __x86_64__
__attribute__ ((__packed__))
__attribute__((__packed__))
#endif
;
int epoll_create(int);
int epoll_create1(int);
int epoll_ctl(int, int, int, struct epoll_event *);
int epoll_wait(int, struct epoll_event *, int, int);
int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *);
;
int epoll_create(int);
int epoll_create1(int);
int epoll_ctl(int, int, int, struct epoll_event *);
int epoll_wait(int, struct epoll_event *, int, int);
int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *);
#ifndef SHIM_SYS_SHIM_HELPERS
#define SHIM_SYS_SHIM_HELPERS
#include <unistd.h> /* IWYU pragma: keep */
extern int epoll_shim_close(int);
extern int epoll_shim_close(int);
#define close epoll_shim_close
#endif
#ifdef __cplusplus
}
#endif

View File

@ -21,14 +21,16 @@
// TODO(jan): Remove this once the definition is exposed in <sys/time.h> in
// all supported FreeBSD versions.
#ifndef timespecsub
#define timespecsub(tsp, usp, vsp) \
do { \
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
if ((vsp)->tv_nsec < 0) { \
(vsp)->tv_sec--; \
(vsp)->tv_nsec += 1000000000L; \
} \
#define timespecsub(tsp, usp, vsp) \
do \
{ \
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
if ((vsp)->tv_nsec < 0) \
{ \
(vsp)->tv_sec--; \
(vsp)->tv_nsec += 1000000000L; \
} \
} while (0)
#endif
@ -39,9 +41,9 @@ epollfd_close(FDContextMapNode *node)
}
static FDContextVTable const epollfd_vtable = {
.read_fun = fd_context_default_read,
.write_fun = fd_context_default_write,
.close_fun = epollfd_close,
.read_fun = fd_context_default_read,
.write_fun = fd_context_default_write,
.close_fun = epollfd_close,
};
static FDContextMapNode *
@ -50,14 +52,16 @@ epoll_create_impl(errno_t *ec)
FDContextMapNode *node;
node = epoll_shim_ctx_create_node(&epoll_shim_ctx, ec);
if (!node) {
if (!node)
{
return NULL;
}
node->flags = 0;
if ((*ec = epollfd_ctx_init(&node->ctx.epollfd, /**/
node->fd)) != 0) {
node->fd)) != 0)
{
goto fail;
}
@ -77,7 +81,8 @@ epoll_create_common(void)
errno_t ec;
node = epoll_create_impl(&ec);
if (!node) {
if (!node)
{
errno = ec;
return -1;
}
@ -85,10 +90,10 @@ epoll_create_common(void)
return node->fd;
}
int
epoll_create(int size)
int epoll_create(int size)
{
if (size <= 0) {
if (size <= 0)
{
errno = EINVAL;
return -1;
}
@ -96,10 +101,10 @@ epoll_create(int size)
return epoll_create_common();
}
int
epoll_create1(int flags)
int epoll_create1(int flags)
{
if (flags & ~EPOLL_CLOEXEC) {
if (flags & ~EPOLL_CLOEXEC)
{
errno = EINVAL;
return -1;
}
@ -110,12 +115,14 @@ epoll_create1(int flags)
static errno_t
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;
}
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;
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);
}
int
epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
{
errno_t ec = epoll_ctl_impl(fd, op, fd2, ev);
if (ec != 0) {
if (ec != 0)
{
errno = ec;
return -1;
}
@ -143,33 +150,39 @@ is_no_wait_deadline(struct timespec const *deadline)
static errno_t
epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
int *actual_cnt, struct timespec const *deadline, sigset_t const *sigs)
int *actual_cnt, struct timespec const *deadline, sigset_t const *sigs)
{
errno_t ec;
for (;;) {
for (;;)
{
if ((ec = epollfd_ctx_wait(epollfd, /**/
ev, cnt, actual_cnt)) != 0) {
ev, cnt, actual_cnt)) != 0)
{
return ec;
}
if (*actual_cnt || is_no_wait_deadline(deadline)) {
if (*actual_cnt || is_no_wait_deadline(deadline))
{
return 0;
}
struct timespec timeout;
if (deadline) {
if (deadline)
{
struct timespec current_time;
if (clock_gettime(CLOCK_MONOTONIC, /**/
&current_time) < 0) {
&current_time) < 0)
{
return errno;
}
timespecsub(deadline, &current_time, &timeout);
if (timeout.tv_sec < 0 ||
is_no_wait_deadline(&timeout)) {
is_no_wait_deadline(&timeout))
{
return 0;
}
}
@ -180,14 +193,16 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
size_t size;
if (__builtin_mul_overflow(nfds, sizeof(struct pollfd),
&size)) {
&size))
{
ec = ENOMEM;
(void)pthread_mutex_unlock(&epollfd->mutex);
return ec;
}
struct pollfd *pfds = malloc(size);
if (!pfds) {
if (!pfds)
{
ec = errno;
(void)pthread_mutex_unlock(&epollfd->mutex);
return ec;
@ -211,7 +226,8 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
#endif
int n = ppoll(pfds, nfds, deadline ? &timeout : NULL, sigs);
if (n < 0) {
if (n < 0)
{
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);
--epollfd->nr_polling_threads;
if (epollfd->nr_polling_threads == 0) {
if (epollfd->nr_polling_threads == 0)
{
(void)pthread_cond_signal(
&epollfd->nr_polling_threads_cond);
&epollfd->nr_polling_threads_cond);
}
(void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex);
if (n < 0) {
if (n < 0)
{
return ec;
}
}
@ -236,21 +254,27 @@ timeout_to_deadline(struct timespec *deadline, int to)
{
assert(to >= 0);
if (to == 0) {
if (to == 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;
}
if (__builtin_add_overflow(deadline->tv_sec, to / 1000 + 1,
&deadline->tv_sec)) {
&deadline->tv_sec))
{
return EINVAL;
}
deadline->tv_sec -= 1;
deadline->tv_nsec += (to % 1000) * 1000000L;
if (deadline->tv_nsec >= 1000000000) {
if (deadline->tv_nsec >= 1000000000)
{
deadline->tv_nsec -= 1000000000;
deadline->tv_sec += 1;
}
@ -261,36 +285,39 @@ timeout_to_deadline(struct timespec *deadline, int to)
static errno_t
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;
}
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;
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
}
struct timespec deadline;
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 epollfd_ctx_wait_or_block(&node->ctx.epollfd, ev, cnt,
actual_cnt, (to >= 0) ? &deadline : NULL, sigs);
actual_cnt, (to >= 0) ? &deadline : NULL, sigs);
}
int
epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
sigset_t const *sigs)
int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
sigset_t const *sigs)
{
int actual_cnt;
errno_t ec = epoll_pwait_impl(fd, ev, cnt, to, sigs, &actual_cnt);
if (ec != 0) {
if (ec != 0)
{
errno = ec;
return -1;
}
@ -298,8 +325,7 @@ epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
return actual_cnt;
}
int
epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
{
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;
node = malloc(sizeof(FDContextMapNode));
if (!node) {
if (!node)
{
*ec = errno;
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;
if (close_fd && close(node->fd) < 0) {
if (close_fd && close(node->fd) < 0)
{
ec = ec ? ec : errno;
}
@ -53,7 +55,7 @@ fd_context_map_node_destroy(FDContextMapNode *node)
errno_t
fd_context_default_read(FDContextMapNode *node, /**/
void *buf, size_t nbytes, size_t *bytes_transferred)
void *buf, size_t nbytes, size_t *bytes_transferred)
{
(void)node;
(void)buf;
@ -65,7 +67,7 @@ fd_context_default_read(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)
{
(void)node;
(void)buf;
@ -84,18 +86,18 @@ fd_context_map_node_cmp(FDContextMapNode *e1, FDContextMapNode *e2)
}
RB_PROTOTYPE_STATIC(fd_context_map_, fd_context_map_node_, entry,
fd_context_map_node_cmp);
fd_context_map_node_cmp);
RB_GENERATE_STATIC(fd_context_map_, fd_context_map_node_, entry,
fd_context_map_node_cmp);
fd_context_map_node_cmp);
EpollShimCtx epoll_shim_ctx = {
.fd_context_map = RB_INITIALIZER(&fd_context_map),
.mutex = PTHREAD_MUTEX_INITIALIZER,
.fd_context_map = RB_INITIALIZER(&fd_context_map),
.mutex = PTHREAD_MUTEX_INITIALIZER,
};
static FDContextMapNode *
epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
errno_t *ec)
errno_t *ec)
{
FDContextMapNode *node;
@ -104,10 +106,11 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
find.fd = kq;
node = RB_FIND(fd_context_map_, /**/
&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
* with a normal 'close()' call, i.e. not with our
@ -118,14 +121,17 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
*/
(void)fd_context_map_node_terminate(node, false);
fd_context_map_node_init(node, kq);
} else {
}
else
{
node = fd_context_map_node_create(kq, ec);
if (!node) {
if (!node)
{
return NULL;
}
void *colliding_node = RB_INSERT(fd_context_map_,
&epoll_shim_ctx->fd_context_map, node);
&epoll_shim_ctx->fd_context_map, node);
(void)colliding_node;
assert(colliding_node == NULL);
}
@ -139,7 +145,8 @@ epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec)
FDContextMapNode *node;
int kq = kqueue();
if (kq < 0) {
if (kq < 0)
{
*ec = errno;
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);
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
if (!node) {
if (!node)
{
close(kq);
}
@ -164,7 +172,7 @@ epoll_shim_ctx_find_node_impl(EpollShimCtx *epoll_shim_ctx, int fd)
find.fd = fd;
node = RB_FIND(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, &find);
&epoll_shim_ctx->fd_context_map, &find);
return node;
}
@ -188,39 +196,40 @@ epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, int fd)
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
node = epoll_shim_ctx_find_node_impl(epoll_shim_ctx, fd);
if (node) {
if (node)
{
RB_REMOVE(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, node);
&epoll_shim_ctx->fd_context_map, node);
}
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
return node;
}
void
epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
FDContextMapNode *node)
void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
FDContextMapNode *node)
{
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
RB_REMOVE(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, node);
&epoll_shim_ctx->fd_context_map, node);
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
}
/**/
int
epoll_shim_close(int fd)
int epoll_shim_close(int fd)
{
FDContextMapNode *node;
node = epoll_shim_ctx_remove_node(&epoll_shim_ctx, fd);
if (!node) {
if (!node)
{
return close(fd);
}
errno_t ec = fd_context_map_node_destroy(node);
if (ec != 0) {
if (ec != 0)
{
errno = ec;
return -1;
}
@ -234,19 +243,22 @@ epoll_shim_read(int fd, void *buf, size_t nbytes)
FDContextMapNode *node;
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node) {
if (!node)
{
return read(fd, buf, nbytes);
}
if (nbytes > SSIZE_MAX) {
if (nbytes > SSIZE_MAX)
{
errno = EINVAL;
return -1;
}
size_t bytes_transferred;
errno_t ec = node->vtable->read_fun(node, /**/
buf, nbytes, &bytes_transferred);
if (ec != 0) {
buf, nbytes, &bytes_transferred);
if (ec != 0)
{
errno = ec;
return -1;
}
@ -260,19 +272,22 @@ epoll_shim_write(int fd, void const *buf, size_t nbytes)
FDContextMapNode *node;
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node) {
if (!node)
{
return write(fd, buf, nbytes);
}
if (nbytes > SSIZE_MAX) {
if (nbytes > SSIZE_MAX)
{
errno = EINVAL;
return -1;
}
size_t bytes_transferred;
errno_t ec = node->vtable->write_fun(node, /**/
buf, nbytes, &bytes_transferred);
if (ec != 0) {
buf, nbytes, &bytes_transferred);
if (ec != 0)
{
errno = ec;
return -1;
}

View File

@ -16,27 +16,31 @@ struct fd_context_map_node_;
typedef struct fd_context_map_node_ FDContextMapNode;
typedef errno_t (*fd_context_read_fun)(FDContextMapNode *node, /**/
void *buf, size_t nbytes, size_t *bytes_transferred);
void *buf, size_t nbytes, size_t *bytes_transferred);
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 struct {
typedef struct
{
fd_context_read_fun read_fun;
fd_context_write_fun write_fun;
fd_context_close_fun close_fun;
} FDContextVTable;
errno_t fd_context_default_read(FDContextMapNode *node, /**/
void *buf, size_t nbytes, size_t *bytes_transferred);
void *buf, size_t nbytes, size_t *bytes_transferred);
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_ {
RB_ENTRY(fd_context_map_node_) entry;
struct fd_context_map_node_
{
RB_ENTRY(fd_context_map_node_)
entry;
int fd;
int flags;
union {
union
{
EpollFDCtx epollfd;
EventFDCtx eventfd;
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 struct {
typedef struct
{
FDContextMap fd_context_map;
pthread_mutex_t mutex;
} EpollShimCtx;
@ -59,13 +64,13 @@ typedef struct {
extern EpollShimCtx epoll_shim_ctx;
FDContextMapNode *epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx,
errno_t *ec);
errno_t *ec);
FDContextMapNode *epoll_shim_ctx_find_node(EpollShimCtx *epoll_shim_ctx,
int fd);
int fd);
FDContextMapNode *epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx,
int fd);
int fd);
void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
FDContextMapNode *node);
FDContextMapNode *node);
/**/

File diff suppressed because it is too large Load Diff

View File

@ -19,12 +19,14 @@
struct registered_fds_node_;
typedef struct registered_fds_node_ RegisteredFDsNode;
typedef enum {
typedef enum
{
EOF_STATE_READ_EOF = 0x01,
EOF_STATE_WRITE_EOF = 0x02,
} EOFState;
typedef enum {
typedef enum
{
NODE_TYPE_FIFO = 1,
NODE_TYPE_SOCKET = 2,
NODE_TYPE_KQUEUE = 3,
@ -32,9 +34,12 @@ typedef enum {
NODE_TYPE_POLL = 5,
} NodeType;
struct registered_fds_node_ {
RB_ENTRY(registered_fds_node_) entry;
TAILQ_ENTRY(registered_fds_node_) pollfd_list_entry;
struct registered_fds_node_
{
RB_ENTRY(registered_fds_node_)
entry;
TAILQ_ENTRY(registered_fds_node_)
pollfd_list_entry;
int fd;
epoll_data_t data;
@ -50,8 +55,10 @@ struct registered_fds_node_ {
bool got_evfilt_except;
NodeType node_type;
union {
struct {
union
{
struct
{
bool readable;
bool writable;
} fifo;
@ -72,7 +79,8 @@ struct registered_fds_node_ {
typedef TAILQ_HEAD(pollfds_list_, registered_fds_node_) PollFDList;
typedef RB_HEAD(registered_fds_set_, registered_fds_node_) RegisteredFDsSet;
typedef struct {
typedef struct
{
int kq; // non owning
pthread_mutex_t mutex;
@ -101,8 +109,8 @@ errno_t epollfd_ctx_terminate(EpollFDCtx *epollfd);
void epollfd_ctx_fill_pollfds(EpollFDCtx *epollfd, struct pollfd *pfds);
errno_t epollfd_ctx_ctl(EpollFDCtx *epollfd, int op, int fd2,
struct epoll_event *ev);
struct epoll_event *ev);
errno_t epollfd_ctx_wait(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
int *actual_cnt);
int *actual_cnt);
#endif

View File

@ -11,7 +11,8 @@
#define EVENTFD_CTX_FLAG_SEMAPHORE (1 << 0)
typedef struct {
typedef struct
{
int kq_; // non owning
int flags_;
pthread_mutex_t mutex_;
@ -22,7 +23,7 @@ typedef struct {
} EventFDCtx;
errno_t eventfd_ctx_init(EventFDCtx *eventfd, int kq, unsigned int counter,
int flags);
int flags);
errno_t eventfd_ctx_terminate(EventFDCtx *eventfd);
errno_t eventfd_ctx_write(EventFDCtx *eventfd, uint64_t value);

View File

@ -4,7 +4,7 @@
#include <errno.h>
int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const sigset_t *sigmask)
int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask)
{
// macos does not implement ppoll
// this is a hacky ppoll shim. only for tpws which does not require sigmask
@ -13,7 +13,7 @@ int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const si
errno = EINVAL;
return -1;
}
return poll(fds,nfds,tmo_p ? tmo_p->tv_sec*1000 + tmo_p->tv_nsec/1000000 : -1);
return poll(fds, nfds, tmo_p ? tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000 : -1);
}
#endif

View File

@ -11,10 +11,11 @@ typedef int errno_t;
#include <signal.h>
#include <poll.h>
struct itimerspec {
struct timespec it_interval;
struct timespec it_value;
struct itimerspec
{
struct timespec it_interval;
struct timespec it_value;
};
int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const sigset_t *sigmask);
int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask);
#endif

View File

@ -7,7 +7,8 @@
#include <stdint.h>
#include <stdlib.h>
typedef struct {
typedef struct
{
int kq; // non owning
} SignalFDCtx;

View File

@ -11,7 +11,8 @@
#include <pthread.h>
#include <time.h>
typedef struct {
typedef struct
{
int kq; // non owning
int flags;
pthread_mutex_t mutex;
@ -30,7 +31,7 @@ errno_t timerfd_ctx_init(TimerFDCtx *timerfd, int kq, int clockid);
errno_t timerfd_ctx_terminate(TimerFDCtx *timerfd);
errno_t timerfd_ctx_settime(TimerFDCtx *timerfd, int flags,
struct itimerspec const *new, struct itimerspec *old);
struct itimerspec const *new, struct itimerspec *old);
errno_t timerfd_ctx_gettime(TimerFDCtx *timerfd, struct itimerspec *cur);
errno_t timerfd_ctx_read(TimerFDCtx *timerfd, uint64_t *value);

View File

@ -5,7 +5,7 @@
#define ZCHUNK 16384
#define BUFMIN 128
#define BUFCHUNK (1024*128)
#define BUFCHUNK (1024 * 128)
int z_readfile(FILE *F, char **buf, size_t *size)
{
@ -21,7 +21,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
bufsize = *size = 0;
r = inflateInit2(&zs, 47);
if (r != Z_OK) return r;
if (r != Z_OK)
return r;
do
{
@ -31,7 +32,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
r = Z_ERRNO;
goto zerr;
}
if (!zs.avail_in) break;
if (!zs.avail_in)
break;
zs.next_in = in;
do
{
@ -47,9 +49,10 @@ int z_readfile(FILE *F, char **buf, size_t *size)
*buf = newbuf;
}
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);
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;
} while (r == Z_OK && zs.avail_in);
} while (r == Z_OK);
@ -57,7 +60,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
if (*size < bufsize)
{
// free extra space
if ((newbuf = realloc(*buf, *size))) *buf = newbuf;
if ((newbuf = realloc(*buf, *size)))
*buf = newbuf;
}
inflateEnd(&zs);
@ -73,7 +77,7 @@ zerr:
return r;
}
bool is_gzip(FILE* F)
bool is_gzip(FILE *F)
{
unsigned char magic[2];
bool b = !fseek(F, 0, SEEK_SET) && fread(magic, 1, 2, F) == 2 && magic[0] == 0x1F && magic[1] == 0x8B;

View File

@ -4,5 +4,5 @@
#include <zlib.h>
#include <stdbool.h>
int z_readfile(FILE *F,char **buf,size_t *size);
bool is_gzip(FILE* F);
int z_readfile(FILE *F, char **buf, size_t *size);
bool is_gzip(FILE *F);

View File

@ -11,7 +11,7 @@
#include <time.h>
#include <sys/stat.h>
char *strncasestr(const char *s,const char *find, size_t slen)
char *strncasestr(const char *s, const char *find, size_t slen)
{
char c, sc;
size_t len;
@ -23,9 +23,11 @@ char *strncasestr(const char *s,const char *find, size_t slen)
{
do
{
if (slen-- < 1 || (sc = *s++) == '\0') return NULL;
if (slen-- < 1 || (sc = *s++) == '\0')
return NULL;
} while (toupper(c) != toupper(sc));
if (len > slen) return NULL;
if (len > slen)
return NULL;
} while (strncasecmp(s, find, len) != 0);
s--;
}
@ -34,71 +36,73 @@ char *strncasestr(const char *s,const char *find, size_t slen)
bool append_to_list_file(const char *filename, const char *s)
{
FILE *F = fopen(filename,"at");
if (!F) return false;
bool bOK = fprintf(F,"%s\n",s)>0;
FILE *F = fopen(filename, "at");
if (!F)
return false;
bool bOK = fprintf(F, "%s\n", s) > 0;
fclose(F);
return bOK;
}
void ntop46(const struct sockaddr *sa, char *str, size_t len)
{
if (!len) return;
*str=0;
if (!len)
return;
*str = 0;
switch (sa->sa_family)
{
case AF_INET:
inet_ntop(sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr, str, len);
inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, str, len);
break;
case AF_INET6:
inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, str, len);
inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, str, len);
break;
default:
snprintf(str,len,"UNKNOWN_FAMILY_%d",sa->sa_family);
snprintf(str, len, "UNKNOWN_FAMILY_%d", sa->sa_family);
}
}
void ntop46_port(const struct sockaddr *sa, char *str, size_t len)
{
char ip[40];
ntop46(sa,ip,sizeof(ip));
ntop46(sa, ip, sizeof(ip));
switch (sa->sa_family)
{
case AF_INET:
snprintf(str,len,"%s:%u",ip,ntohs(((struct sockaddr_in*)sa)->sin_port));
snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in *)sa)->sin_port));
break;
case AF_INET6:
snprintf(str,len,"[%s]:%u",ip,ntohs(((struct sockaddr_in6*)sa)->sin6_port));
snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6 *)sa)->sin6_port));
break;
default:
snprintf(str,len,"%s",ip);
snprintf(str, len, "%s", ip);
}
}
void print_sockaddr(const struct sockaddr *sa)
{
char ip_port[48];
ntop46_port(sa,ip_port,sizeof(ip_port));
printf("%s",ip_port);
ntop46_port(sa, ip_port, sizeof(ip_port));
printf("%s", ip_port);
}
// -1 = error, 0 = not local, 1 = local
bool check_local_ip(const struct sockaddr *saddr)
{
struct ifaddrs *addrs,*a;
struct ifaddrs *addrs, *a;
if (is_localnet(saddr))
return true;
if (getifaddrs(&addrs)<0) return false;
a = addrs;
if (getifaddrs(&addrs) < 0)
return false;
a = addrs;
bool bres=false;
bool bres = false;
while (a)
{
if (a->ifa_addr && sacmp(a->ifa_addr,saddr))
if (a->ifa_addr && sacmp(a->ifa_addr, saddr))
{
bres=true;
bres = true;
break;
}
a = a->ifa_next;
@ -115,50 +119,48 @@ void print_addrinfo(const struct addrinfo *ai)
switch (ai->ai_family)
{
case AF_INET:
if (inet_ntop(ai->ai_family, &((struct sockaddr_in*)ai->ai_addr)->sin_addr, str, sizeof(str)))
if (inet_ntop(ai->ai_family, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, str, sizeof(str)))
printf("%s\n", str);
break;
case AF_INET6:
if (inet_ntop(ai->ai_family, &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, str, sizeof(str)))
printf( "%s\n", str);
if (inet_ntop(ai->ai_family, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, str, sizeof(str)))
printf("%s\n", str);
break;
}
ai = ai->ai_next;
}
}
bool saismapped(const struct sockaddr_in6 *sa)
{
// ::ffff:1.2.3.4
return !memcmp(sa->sin6_addr.s6_addr,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff",12);
return !memcmp(sa->sin6_addr.s6_addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff", 12);
}
bool samappedcmp(const struct sockaddr_in *sa1,const struct sockaddr_in6 *sa2)
bool samappedcmp(const struct sockaddr_in *sa1, const struct sockaddr_in6 *sa2)
{
return saismapped(sa2) && !memcmp(sa2->sin6_addr.s6_addr+12,&sa1->sin_addr.s_addr,4);
return saismapped(sa2) && !memcmp(sa2->sin6_addr.s6_addr + 12, &sa1->sin_addr.s_addr, 4);
}
bool sacmp(const struct sockaddr *sa1,const struct sockaddr *sa2)
bool sacmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
{
return (sa1->sa_family==AF_INET && sa2->sa_family==AF_INET && !memcmp(&((struct sockaddr_in*)sa1)->sin_addr,&((struct sockaddr_in*)sa2)->sin_addr,sizeof(struct in_addr))) ||
(sa1->sa_family==AF_INET6 && sa2->sa_family==AF_INET6 && !memcmp(&((struct sockaddr_in6*)sa1)->sin6_addr,&((struct sockaddr_in6*)sa2)->sin6_addr,sizeof(struct in6_addr))) ||
(sa1->sa_family==AF_INET && sa2->sa_family==AF_INET6 && samappedcmp((struct sockaddr_in*)sa1,(struct sockaddr_in6*)sa2)) ||
(sa1->sa_family==AF_INET6 && sa2->sa_family==AF_INET && samappedcmp((struct sockaddr_in*)sa2,(struct sockaddr_in6*)sa1));
return (sa1->sa_family == AF_INET && sa2->sa_family == AF_INET && !memcmp(&((struct sockaddr_in *)sa1)->sin_addr, &((struct sockaddr_in *)sa2)->sin_addr, sizeof(struct in_addr))) ||
(sa1->sa_family == AF_INET6 && sa2->sa_family == AF_INET6 && !memcmp(&((struct sockaddr_in6 *)sa1)->sin6_addr, &((struct sockaddr_in6 *)sa2)->sin6_addr, sizeof(struct in6_addr))) ||
(sa1->sa_family == AF_INET && sa2->sa_family == AF_INET6 && samappedcmp((struct sockaddr_in *)sa1, (struct sockaddr_in6 *)sa2)) ||
(sa1->sa_family == AF_INET6 && sa2->sa_family == AF_INET && samappedcmp((struct sockaddr_in *)sa2, (struct sockaddr_in6 *)sa1));
}
uint16_t saport(const struct sockaddr *sa)
{
return htons(sa->sa_family==AF_INET ? ((struct sockaddr_in*)sa)->sin_port :
sa->sa_family==AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0);
return htons(sa->sa_family == AF_INET ? ((struct sockaddr_in *)sa)->sin_port : sa->sa_family == AF_INET6 ? ((struct sockaddr_in6 *)sa)->sin6_port
: 0);
}
bool saconvmapped(struct sockaddr_storage *a)
{
if ((a->ss_family == AF_INET6) && saismapped((struct sockaddr_in6*)a))
if ((a->ss_family == AF_INET6) && saismapped((struct sockaddr_in6 *)a))
{
uint32_t ip4 = IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr);
uint16_t port = ((struct sockaddr_in6*)a)->sin6_port;
uint32_t ip4 = IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr);
uint16_t port = ((struct sockaddr_in6 *)a)->sin6_port;
a->ss_family = AF_INET;
((struct sockaddr_in*)a)->sin_addr.s_addr = ip4;
((struct sockaddr_in*)a)->sin_port = port;
((struct sockaddr_in *)a)->sin_addr.s_addr = ip4;
((struct sockaddr_in *)a)->sin_port = port;
return true;
}
return false;
@ -167,45 +169,43 @@ bool saconvmapped(struct sockaddr_storage *a)
bool is_localnet(const struct sockaddr *a)
{
// match 127.0.0.0/8, 0.0.0.0, ::1, ::0, :ffff:127.0.0.0/104, :ffff:0.0.0.0
return (a->sa_family==AF_INET && (IN_LOOPBACK(ntohl(((struct sockaddr_in *)a)->sin_addr.s_addr)) ||
INADDR_ANY == ntohl((((struct sockaddr_in *)a)->sin_addr.s_addr)))) ||
(a->sa_family==AF_INET6 && (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)a)->sin6_addr) ||
IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)a)->sin6_addr) ||
(IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr) && (IN_LOOPBACK(ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr))) ||
INADDR_ANY == ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr))))));
return (a->sa_family == AF_INET && (IN_LOOPBACK(ntohl(((struct sockaddr_in *)a)->sin_addr.s_addr)) ||
INADDR_ANY == ntohl((((struct sockaddr_in *)a)->sin_addr.s_addr)))) ||
(a->sa_family == AF_INET6 && (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)a)->sin6_addr) ||
IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)a)->sin6_addr) ||
(IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr) && (IN_LOOPBACK(ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr))) ||
INADDR_ANY == ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr))))));
}
bool is_linklocal(const struct sockaddr_in6 *a)
{
// fe80::/10
return a->sin6_addr.s6_addr[0]==0xFE && (a->sin6_addr.s6_addr[1] & 0xC0)==0x80;
return a->sin6_addr.s6_addr[0] == 0xFE && (a->sin6_addr.s6_addr[1] & 0xC0) == 0x80;
}
bool is_private6(const struct sockaddr_in6* a)
bool is_private6(const struct sockaddr_in6 *a)
{
// fc00::/7
return (a->sin6_addr.s6_addr[0] & 0xFE) == 0xFC;
}
bool set_keepalive(int fd)
{
int yes=1;
return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int))!=-1;
int yes = 1;
return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int)) != -1;
}
bool set_ttl(int fd, int ttl)
{
return setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))!=-1;
return setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) != -1;
}
bool set_hl(int fd, int hl)
{
return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hl, sizeof(hl))!=-1;
return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hl, sizeof(hl)) != -1;
}
bool set_ttl_hl(int fd, int ttl)
{
bool b1,b2;
bool b1, b2;
// try to set both but one may fail if family is wrong
b1=set_ttl(fd, ttl);
b2=set_hl(fd, ttl);
b1 = set_ttl(fd, ttl);
b2 = set_hl(fd, ttl);
return b1 || b2;
}
int get_so_error(int fd)
@ -213,8 +213,8 @@ int get_so_error(int fd)
// getsockopt(SO_ERROR) clears error
int errn;
socklen_t optlen = sizeof(errn);
if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1)
errn=errno;
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1)
errn = errno;
return errn;
}
@ -224,42 +224,45 @@ int fprint_localtime(FILE *F)
time_t now;
time(&now);
localtime_r(&now,&t);
localtime_r(&now, &t);
return fprintf(F, "%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
}
time_t file_mod_time(const char *filename)
{
struct stat st;
return stat(filename,&st)==-1 ? 0 : st.st_mtime;
return stat(filename, &st) == -1 ? 0 : st.st_mtime;
}
bool pf_in_range(uint16_t port, const port_filter *pf)
{
return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg);
return port && (((!pf->from && !pf->to) || (port >= pf->from && port <= pf->to)) ^ pf->neg);
}
bool pf_parse(const char *s, port_filter *pf)
{
unsigned int v1,v2;
unsigned int v1, v2;
if (!s) return false;
if (*s=='~')
if (!s)
return false;
if (*s == '~')
{
pf->neg=true;
pf->neg = true;
s++;
}
else
pf->neg=false;
if (sscanf(s,"%u-%u",&v1,&v2)==2)
pf->neg = false;
if (sscanf(s, "%u-%u", &v1, &v2) == 2)
{
if (!v1 || v1>65535 || v2>65535 || v1>v2) return false;
pf->from=(uint16_t)v1;
pf->to=(uint16_t)v2;
if (!v1 || v1 > 65535 || v2 > 65535 || v1 > v2)
return false;
pf->from = (uint16_t)v1;
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;
pf->to=pf->from=(uint16_t)v1;
if (!v1 || v1 > 65535)
return false;
pf->to = pf->from = (uint16_t)v1;
}
else
return false;

View File

@ -8,7 +8,7 @@
#include <stdio.h>
#include <time.h>
char *strncasestr(const char *s,const char *find, size_t slen);
char *strncasestr(const char *s, const char *find, size_t slen);
bool append_to_list_file(const char *filename, const char *s);
@ -19,15 +19,15 @@ void print_addrinfo(const struct addrinfo *ai);
bool check_local_ip(const struct sockaddr *saddr);
bool saismapped(const struct sockaddr_in6 *sa);
bool samappedcmp(const struct sockaddr_in *sa1,const struct sockaddr_in6 *sa2);
bool sacmp(const struct sockaddr *sa1,const struct sockaddr *sa2);
bool samappedcmp(const struct sockaddr_in *sa1, const struct sockaddr_in6 *sa2);
bool sacmp(const struct sockaddr *sa1, const struct sockaddr *sa2);
uint16_t saport(const struct sockaddr *sa);
// true = was converted
bool saconvmapped(struct sockaddr_storage *a);
bool is_localnet(const struct sockaddr *a);
bool is_linklocal(const struct sockaddr_in6* a);
bool is_private6(const struct sockaddr_in6* a);
bool is_linklocal(const struct sockaddr_in6 *a);
bool is_private6(const struct sockaddr_in6 *a);
bool set_keepalive(int fd);
bool set_ttl(int fd, int ttl);
@ -36,11 +36,13 @@ bool set_ttl_hl(int fd, int ttl);
int get_so_error(int fd);
// 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];
}
static inline void phton16(uint8_t *p, uint16_t v) {
p[0] = (uint8_t)(v>>8);
static inline void phton16(uint8_t *p, uint16_t v)
{
p[0] = (uint8_t)(v >> 8);
p[1] = (uint8_t)v;
}
@ -50,21 +52,20 @@ time_t file_mod_time(const char *filename);
typedef struct
{
uint16_t from,to;
uint16_t from, to;
bool neg;
} port_filter;
bool pf_in_range(uint16_t port, const port_filter *pf);
bool pf_parse(const char *s, port_filter *pf);
#ifndef IN_LOOPBACK
#define IN_LOOPBACK(a) ((((uint32_t) (a)) & 0xff000000) == 0x7f000000)
#define IN_LOOPBACK(a) ((((uint32_t)(a)) & 0xff000000) == 0x7f000000)
#endif
#ifdef __GNUC__
#define IN6_EXTRACT_MAP4(a) \
(__extension__ \
({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
(__extension__({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
(((const uint32_t *) (__a))[3]); }))
#else
#define IN6_EXTRACT_MAP4(a) (((const uint32_t *) (a))[3])
#define IN6_EXTRACT_MAP4(a) (((const uint32_t *)(a))[3])
#endif

View File

@ -8,17 +8,19 @@
static bool addpool(strpool **hostlist, char **s, const char *end)
{
char *p;
// advance until eol lowering all chars
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
for (p = *s; p < end && *p && *p != '\r' && *p != '\n'; p++)
*p = tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p - *s))
{
StrPoolDestroy(hostlist);
*hostlist = NULL;
return false;
}
// 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;
return true;
}
@ -31,7 +33,7 @@ bool AppendHostList(strpool **hostlist, char *filename)
FILE *F;
int r;
DLOG_CONDUP("Loading hostlist %s\n",filename);
DLOG_CONDUP("Loading hostlist %s\n", filename);
if (!(F = fopen(filename, "rb")))
{
@ -41,18 +43,19 @@ bool AppendHostList(strpool **hostlist, char *filename)
if (is_gzip(F))
{
r = z_readfile(F,&zbuf,&zsize);
r = z_readfile(F, &zbuf, &zsize);
fclose(F);
if (r==Z_OK)
if (r == Z_OK)
{
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
p = zbuf;
e = zbuf + zsize;
while(p<e)
while (p < e)
{
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,e))
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
continue;
if (!addpool(hostlist, &p, e))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
free(zbuf);
@ -64,19 +67,20 @@ bool AppendHostList(strpool **hostlist, char *filename)
}
else
{
DLOG_ERR("zlib decompression failed : result %d\n",r);
DLOG_ERR("zlib decompression failed : result %d\n", r);
return false;
}
}
else
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, 256, F))
{
p = s;
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,p+strlen(p)))
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
continue;
if (!addpool(hostlist, &p, p + strlen(p)))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
fclose(F);
@ -103,7 +107,8 @@ bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list)
LIST_FOREACH(file, file_list, next)
{
if (!AppendHostList(hostlist, file->str)) return false;
if (!AppendHostList(hostlist, file->str))
return false;
}
return true;
}
@ -114,7 +119,6 @@ bool NonEmptyHostlist(strpool **hostlist)
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
}
bool SearchHostList(strpool *hostlist, const char *host)
{
if (hostlist)
@ -125,9 +129,11 @@ bool SearchHostList(strpool *hostlist, const char *host)
{
bInHostList = StrPoolCheckStr(hostlist, p);
VPRINT("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
if (bInHostList) return true;
if (bInHostList)
return true;
p = strchr(p, '.');
if (p) p++;
if (p)
p++;
}
}
return false;
@ -136,13 +142,15 @@ bool SearchHostList(strpool *hostlist, const char *host)
// return : true = apply fooling, false = do not apply
static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded)
{
if (excluded) *excluded = false;
if (excluded)
*excluded = false;
if (hostlist_exclude)
{
VPRINT("Checking exclude hostlist\n");
if (SearchHostList(hostlist_exclude, host))
{
if (excluded) *excluded = true;
if (excluded)
*excluded = true;
return false;
}
}
@ -160,7 +168,7 @@ bool HostlistCheck(const char *host, bool *excluded)
if (*params.hostlist_auto_filename)
{
time_t t = file_mod_time(params.hostlist_auto_filename);
if (t!=params.hostlist_auto_mod_time)
if (t != params.hostlist_auto_mod_time)
{
DLOG_CONDUP("Autohostlist was modified by another process. Reloading include hostslist.\n");
if (!LoadIncludeHostLists())

View File

@ -6,42 +6,52 @@
// taken from an older apple SDK
// some fields are different from BSDs
#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 };
struct pf_addr {
union {
struct in_addr v4;
struct in6_addr v6;
u_int8_t addr8[16];
u_int16_t addr16[8];
u_int32_t addr32[4];
} pfa; /* 128-bit address */
#define v4 pfa.v4
#define v6 pfa.v6
#define addr8 pfa.addr8
#define addr16 pfa.addr16
#define addr32 pfa.addr32
enum
{
PF_INOUT,
PF_IN,
PF_OUT,
PF_FWD
};
union pf_state_xport {
u_int16_t port;
u_int16_t call_id;
u_int32_t spi;
struct pf_addr
{
union
{
struct in_addr v4;
struct in6_addr v6;
u_int8_t addr8[16];
u_int16_t addr16[8];
u_int32_t addr32[4];
} pfa; /* 128-bit address */
#define v4 pfa.v4
#define v6 pfa.v6
#define addr8 pfa.addr8
#define addr16 pfa.addr16
#define addr32 pfa.addr32
};
struct pfioc_natlook {
struct pf_addr saddr;
struct pf_addr daddr;
struct pf_addr rsaddr;
struct pf_addr rdaddr;
union pf_state_xport sxport;
union pf_state_xport dxport;
union pf_state_xport rsxport;
union pf_state_xport rdxport;
sa_family_t af;
u_int8_t proto;
u_int8_t proto_variant;
u_int8_t direction;
union pf_state_xport
{
u_int16_t port;
u_int16_t call_id;
u_int32_t spi;
};
struct pfioc_natlook
{
struct pf_addr saddr;
struct pf_addr daddr;
struct pf_addr rsaddr;
struct pf_addr rdaddr;
union pf_state_xport sxport;
union pf_state_xport dxport;
union pf_state_xport rsxport;
union pf_state_xport rdxport;
sa_family_t af;
u_int8_t proto;
u_int8_t proto_variant;
u_int8_t direction;
};

File diff suppressed because it is too large Load Diff

View File

@ -9,33 +9,33 @@ int DLOG_FILE(FILE *F, const char *format, va_list args)
}
int DLOG_CON(const char *format, int syslog_priority, va_list args)
{
return DLOG_FILE(syslog_priority==LOG_ERR ? stderr : stdout, format, args);
return DLOG_FILE(syslog_priority == LOG_ERR ? stderr : stdout, format, args);
}
int DLOG_FILENAME(const char *filename, const char *format, va_list args)
{
int r;
FILE *F = fopen(filename,"at");
FILE *F = fopen(filename, "at");
if (F)
{
r = DLOG_FILE(F, format, args);
fclose(F);
}
else
r=-1;
r = -1;
return r;
}
static char syslog_buf[1024];
static size_t syslog_buf_sz=0;
static size_t syslog_buf_sz = 0;
static void syslog_buffered(int priority, const char *format, va_list args)
{
if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0)
if (vsnprintf(syslog_buf + syslog_buf_sz, sizeof(syslog_buf) - syslog_buf_sz, format, args) > 0)
{
syslog_buf_sz=strlen(syslog_buf);
syslog_buf_sz = strlen(syslog_buf);
// log when buffer is full or buffer ends with \n
if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n'))
if (syslog_buf_sz >= (sizeof(syslog_buf) - 1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz - 1] == '\n'))
{
syslog(priority,"%s",syslog_buf);
syslog(priority, "%s", syslog_buf);
syslog_buf_sz = 0;
}
}
@ -43,31 +43,31 @@ static void syslog_buffered(int priority, const char *format, va_list args)
static int DLOG_VA(const char *format, int syslog_priority, bool condup, int level, va_list args)
{
int r=0;
int r = 0;
va_list args2;
if (condup && !(params.debug>=level && params.debug_target==LOG_TARGET_CONSOLE))
if (condup && !(params.debug >= level && params.debug_target == LOG_TARGET_CONSOLE))
{
va_copy(args2,args);
DLOG_CON(format,syslog_priority,args2);
va_copy(args2, args);
DLOG_CON(format, syslog_priority, args2);
}
if (params.debug>=level)
if (params.debug >= level)
{
switch(params.debug_target)
switch (params.debug_target)
{
case LOG_TARGET_CONSOLE:
r = DLOG_CON(format,syslog_priority,args);
break;
case LOG_TARGET_FILE:
r = DLOG_FILENAME(params.debug_logfile,format,args);
break;
case LOG_TARGET_SYSLOG:
// skip newlines
syslog_buffered(syslog_priority,format,args);
r = 1;
break;
default:
break;
case LOG_TARGET_CONSOLE:
r = DLOG_CON(format, syslog_priority, args);
break;
case LOG_TARGET_FILE:
r = DLOG_FILENAME(params.debug_logfile, format, args);
break;
case LOG_TARGET_SYSLOG:
// skip newlines
syslog_buffered(syslog_priority, format, args);
r = 1;
break;
default:
break;
}
}
return r;
@ -105,11 +105,10 @@ int DLOG_PERROR(const char *s)
return DLOG_ERR("%s: %s\n", s, strerror(errno));
}
int LOG_APPEND(const char *filename, const char *format, va_list args)
{
int r;
FILE *F = fopen(filename,"at");
FILE *F = fopen(filename, "at");
if (F)
{
fprint_localtime(F);
@ -119,7 +118,7 @@ int LOG_APPEND(const char *filename, const char *format, va_list args)
fclose(F);
}
else
r=-1;
r = -1;
return r;
}

View File

@ -11,21 +11,32 @@
#include "helpers.h"
#include "protocol.h"
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
enum bindll { unwanted=0, no, prefer, force };
#define MAX_BINDS 32
struct bind_s
enum bindll
{
char bindaddr[64],bindiface[IF_NAMESIZE];
bool bind_if6;
enum bindll bindll;
int bind_wait_ifup,bind_wait_ip,bind_wait_ip_ll;
unwanted = 0,
no,
prefer,
force
};
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
#define MAX_BINDS 32
struct bind_s
{
char bindaddr[64], bindiface[IF_NAMESIZE];
bool bind_if6;
enum bindll bindll;
int bind_wait_ifup, bind_wait_ip, bind_wait_ip_ll;
};
enum log_target
{
LOG_TARGET_CONSOLE = 0,
LOG_TARGET_FILE,
LOG_TARGET_SYSLOG
};
struct params_s
{
@ -41,10 +52,10 @@ struct params_s
uid_t uid;
gid_t gid;
bool daemon;
int maxconn,resolver_threads,maxfiles,max_orphan_time;
int local_rcvbuf,local_sndbuf,remote_rcvbuf,remote_sndbuf;
int maxconn, resolver_threads, maxfiles, max_orphan_time;
int local_rcvbuf, local_sndbuf, remote_rcvbuf, remote_sndbuf;
#if defined(__linux__) || defined(__APPLE__)
int tcp_user_timeout_local,tcp_user_timeout_remote;
int tcp_user_timeout_local, tcp_user_timeout_remote;
#endif
bool tamper; // any tamper option is set
@ -74,8 +85,8 @@ struct params_s
time_t hostlist_auto_mod_time;
hostfail_pool *hostlist_auto_fail_counters;
bool tamper_start_n,tamper_cutoff_n;
unsigned int tamper_start,tamper_cutoff;
bool tamper_start_n, tamper_cutoff_n;
unsigned int tamper_start, tamper_cutoff;
struct sockaddr_in connect_bind4;
struct sockaddr_in6 connect_bind6;

View File

@ -5,33 +5,33 @@
#include <stdio.h>
#define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) { \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) \
{ \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype *)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
}
#undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
@ -65,13 +65,8 @@ void StrPoolDestroy(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);
ADD_STR_POOL(hostfail_pool, pp, s, slen)
@ -79,7 +74,7 @@ hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
elem->counter = 0;
return elem;
}
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s)
hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s)
{
hostfail_pool *elem;
HASH_FIND_STR(p, s, elem);
@ -104,7 +99,7 @@ void HostFailPoolPurge(hostfail_pool **pp)
}
}
}
static time_t host_fail_purge_prev=0;
static time_t host_fail_purge_prev = 0;
void HostFailPoolPurgeRateLimited(hostfail_pool **pp)
{
time_t now = time(NULL);
@ -120,14 +115,14 @@ void HostFailPoolDump(hostfail_pool *p)
hostfail_pool *elem, *tmp;
time_t now = time(NULL);
HASH_ITER(hh, p, elem, tmp)
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)
{
struct str_list *entry = malloc(sizeof(struct str_list));
if (!entry) return false;
if (!entry)
return false;
entry->str = strdup(filename);
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)
{
if (entry->str) free(entry->str);
if (entry->str)
free(entry->str);
free(entry);
}
void strlist_destroy(struct str_list_head *head)

View File

@ -5,38 +5,41 @@
#include <sys/queue.h>
#include <time.h>
//#define HASH_BLOOM 20
// #define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1
#define HASH_FUNCTION HASH_BER
#include "uthash.h"
typedef struct strpool {
char *str; /* key */
UT_hash_handle hh; /* makes this structure hashable */
typedef struct strpool
{
char *str; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} strpool;
void StrPoolDestroy(strpool **pp);
bool StrPoolAddStr(strpool **pp,const char *s);
bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
bool StrPoolCheckStr(strpool *p,const char *s);
bool StrPoolAddStr(strpool **pp, const char *s);
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen);
bool StrPoolCheckStr(strpool *p, const char *s);
struct str_list {
char *str;
LIST_ENTRY(str_list) next;
struct str_list
{
char *str;
LIST_ENTRY(str_list)
next;
};
LIST_HEAD(str_list_head, str_list);
typedef struct hostfail_pool {
char *str; /* key */
int counter; /* value */
time_t expire; /* when to expire record (unixtime) */
UT_hash_handle hh; /* makes this structure hashable */
typedef struct hostfail_pool
{
char *str; /* key */
int counter; /* value */
time_t expire; /* when to expire record (unixtime) */
UT_hash_handle hh; /* makes this structure hashable */
} hostfail_pool;
void HostFailPoolDestroy(hostfail_pool **pp);
hostfail_pool *HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time);
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s);
hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time);
hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s);
void HostFailPoolDel(hostfail_pool **pp, hostfail_pool *elem);
void HostFailPoolPurge(hostfail_pool **pp);
void HostFailPoolPurgeRateLimited(hostfail_pool **pp);

View File

@ -7,8 +7,7 @@
#include <arpa/inet.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 **method;
@ -23,56 +22,63 @@ const char *HttpMethod(const uint8_t *data, size_t len)
}
bool IsHttp(const uint8_t *data, size_t len)
{
return !!HttpMethod(data,len);
return !!HttpMethod(data, len);
}
// pHost points to "Host: ..."
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs)
bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs)
{
if (!*pHost)
{
*pHost = memmem(buf, bs, "\nHost:", 6);
if (*pHost) (*pHost)++;
if (*pHost)
(*pHost)++;
}
return !!*pHost;
}
bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs)
bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs)
{
if (!*pHost)
{
*pHost = memmem(buf, bs, "\nHost:", 6);
if (*pHost) (*pHost)++;
if (*pHost)
(*pHost)++;
}
return !!*pHost;
}
bool IsHttpReply(const uint8_t *data, size_t len)
{
// HTTP/1.x 200\r\n
return len>14 && !memcmp(data,"HTTP/1.",7) && (data[7]=='0' || data[7]=='1') && data[8]==' ' &&
data[9]>='0' && data[9]<='9' &&
data[10]>='0' && data[10]<='9' &&
data[11]>='0' && data[11]<='9';
return len > 14 && !memcmp(data, "HTTP/1.", 7) && (data[7] == '0' || data[7] == '1') && data[8] == ' ' &&
data[9] >= '0' && data[9] <= '9' &&
data[10] >= '0' && data[10] <= '9' &&
data[11] >= '0' && data[11] <= '9';
}
int HttpReplyCode(const uint8_t *data, size_t len)
{
return (data[9]-'0')*100 + (data[10]-'0')*10 + (data[11]-'0');
return (data[9] - '0') * 100 + (data[10] - '0') * 10 + (data[11] - '0');
}
bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf)
{
const uint8_t *p, *s, *e = data + len;
p = (uint8_t*)strncasestr((char*)data, header, len);
if (!p) return false;
p = (uint8_t *)strncasestr((char *)data, header, len);
if (!p)
return false;
p += strlen(header);
while (p < e && (*p == ' ' || *p == '\t')) p++;
while (p < e && (*p == ' ' || *p == '\t'))
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)
{
size_t slen = s - p;
if (buf && len_buf)
{
if (slen >= len_buf) slen = len_buf - 1;
for (size_t i = 0; i < slen; i++) buf[i] = tolower(p[i]);
if (slen >= len_buf)
slen = len_buf - 1;
for (size_t i = 0; i < slen; i++)
buf[i] = tolower(p[i]);
buf[slen] = 0;
}
return true;
@ -85,85 +91,98 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
}
const char *HttpFind2ndLevelDomain(const char *host)
{
const char *p=NULL;
const char *p = NULL;
if (*host)
{
for (p = host + strlen(host)-1; p>host && *p!='.'; p--);
if (*p=='.') for (p--; p>host && *p!='.'; p--);
if (*p=='.') p++;
for (p = host + strlen(host) - 1; p > host && *p != '.'; p--)
;
if (*p == '.')
for (p--; p > host && *p != '.'; p--)
;
if (*p == '.')
p++;
}
return p;
}
// DPI redirects are global redirects to another domain
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host)
{
char loc[256],*redirect_host, *p;
char loc[256], *redirect_host, *p;
int code;
if (!host || !*host) return false;
code = HttpReplyCode(data,len);
if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false;
if (!host || !*host)
return false;
code = HttpReplyCode(data, len);
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
if (!strncmp(loc,"http://",7))
redirect_host=loc+7;
else if (!strncmp(loc,"https://",8))
redirect_host=loc+8;
if (!strncmp(loc, "http://", 7))
redirect_host = loc + 7;
else if (!strncmp(loc, "https://", 8))
redirect_host = loc + 8;
else
return false;
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
for(p=redirect_host; *p && *p!='/' ; p++);
*p=0;
if (!*redirect_host) return false;
for (p = redirect_host; *p && *p != '/'; p++)
;
*p = 0;
if (!*redirect_host)
return false;
// somethinkg like : censor.net
// extract 2nd level domains
const char *dhost = HttpFind2ndLevelDomain(host);
const char *drhost = HttpFind2ndLevelDomain(redirect_host);
return strcasecmp(dhost, drhost)!=0;
return strcasecmp(dhost, drhost) != 0;
}
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
{
const uint8_t *method, *host;
int i;
switch(tpos_type)
switch (tpos_type)
{
case httpreqpos_method:
// recognize some tpws pre-applied hacks
method=http;
if (sz<10) break;
if (*method=='\n' || *method=='\r') method++;
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;
case httpreqpos_host:
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
{
host+=5;
if (*host==' ') host++;
return host-http;
}
case httpreqpos_method:
// recognize some tpws pre-applied hacks
method = http;
if (sz < 10)
break;
case httpreqpos_pos:
if (*method == '\n' || *method == '\r')
method++;
if (*method == '\n' || *method == '\r')
method++;
for (i = 0; i < 7; i++)
if (*method >= 'A' && *method <= 'Z')
method++;
if (i < 3 || *method != ' ')
break;
default:
return 0;
return method - http - 1;
case httpreqpos_host:
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
{
host += 5;
if (*host == ' ')
host++;
return host - http;
}
break;
case httpreqpos_pos:
break;
default:
return 0;
}
return hpos_pos<sz ? hpos_pos : 0;
return hpos_pos < sz ? hpos_pos : 0;
}
uint16_t TLSRecordDataLen(const uint8_t *data)
{
return pntoh16(data + 3);
@ -174,7 +193,7 @@ size_t TLSRecordLen(const uint8_t *data)
}
bool IsTLSRecordFull(const uint8_t *data, size_t len)
{
return TLSRecordLen(data)<=len;
return TLSRecordLen(data) <= len;
}
bool IsTLSClientHello(const uint8_t *data, size_t len, bool bPartialIsOK)
{
@ -201,41 +220,52 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
l = 1 + 3 + 2 + 32;
// SessionIDLength
if (len < (l + 1)) return false;
if (len < (l + 1))
return false;
if (!bPartialIsOK)
{
ll = data[1] << 16 | data[2] << 8 | data[3]; // HandshakeProtocol length
if (len < (ll + 4)) return false;
ll = data[1] << 16 | data[2] << 8 | data[3]; // HandshakeProtocol length
if (len < (ll + 4))
return false;
}
l += data[l] + 1;
// CipherSuitesLength
if (len < (l + 2)) return false;
if (len < (l + 2))
return false;
l += pntoh16(data + l) + 2;
// CompressionMethodsLength
if (len < (l + 1)) return false;
if (len < (l + 1))
return false;
l += data[l] + 1;
// ExtensionsLength
if (len < (l + 2)) return false;
if (len < (l + 2))
return false;
data += l; len -= l;
data += l;
len -= l;
l = pntoh16(data);
data += 2; len -= 2;
data += 2;
len -= 2;
if (bPartialIsOK)
{
if (len < l) l = len;
if (len < l)
l = len;
}
else
{
if (len < l) return false;
if (len < l)
return false;
}
while (l >= 4)
{
uint16_t etype = pntoh16(data);
size_t elen = pntoh16(data + 2);
data += 4; l -= 4;
if (l < elen) break;
data += 4;
l -= 4;
if (l < elen)
break;
if (etype == type)
{
if (ext && len_ext)
@ -245,7 +275,8 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
}
return true;
}
data += elen; l -= elen;
data += elen;
l -= elen;
}
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 Length
size_t reclen;
if (!IsTLSClientHello(data, len, bPartialIsOK)) return false;
reclen=TLSRecordLen(data);
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
if (!IsTLSClientHello(data, len, bPartialIsOK))
return false;
reclen = TLSRecordLen(data);
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);
}
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
// u8 data+2 - server name type. 0=host_name
// 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);
ext += 5; elen -= 5;
if (slen < elen) return false;
ext += 5;
elen -= 5;
if (slen < elen)
return false;
if (host && len_host)
{
if (slen >= len_host) slen = len_host - 1;
for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]);
if (slen >= len_host)
slen = len_host - 1;
for (size_t i = 0; i < slen; i++)
host[i] = tolower(ext[i]);
host[slen] = 0;
}
return true;
@ -284,7 +322,8 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len
const uint8_t *ext;
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);
}
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK)
@ -292,23 +331,24 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
const uint8_t *ext;
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);
}
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
{
size_t elen;
const uint8_t *ext;
switch(tpos_type)
switch (tpos_type)
{
case tlspos_sni:
case tlspos_sniext:
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
// fall through
case tlspos_pos:
return tpos_pos<sz ? tpos_pos : 0;
default:
return 0;
case tlspos_sni:
case tlspos_sniext:
if (TLSFindExt(tls, sz, 0, &ext, &elen, false))
return (tpos_type == tlspos_sni) ? ext - tls + 6 : ext - tls + 1;
// fall through
case tlspos_pos:
return tpos_pos < sz ? tpos_pos : 0;
default:
return 0;
}
}

View File

@ -7,8 +7,8 @@
extern const char *http_methods[9];
const char *HttpMethod(const uint8_t *data, size_t len);
bool IsHttp(const uint8_t *data, size_t len);
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs);
bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs);
bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs);
bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs);
// header must be passed like this : "\nHost:"
bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf);
bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host);
@ -18,7 +18,13 @@ const char *HttpFind2ndLevelDomain(const char *host);
int HttpReplyCode(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply
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);
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 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);
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);

View File

@ -11,23 +11,22 @@
#include "helpers.h"
#ifdef __linux__
#include <linux/netfilter_ipv4.h>
#ifndef IP6T_SO_ORIGINAL_DST
#define IP6T_SO_ORIGINAL_DST 80
#endif
#include <linux/netfilter_ipv4.h>
#ifndef IP6T_SO_ORIGINAL_DST
#define IP6T_SO_ORIGINAL_DST 80
#endif
#endif
#if defined(BSD)
#include <net/if.h>
#include <net/pfvar.h>
static int redirector_fd=-1;
static int redirector_fd = -1;
void redir_close(void)
{
if (redirector_fd!=-1)
if (redirector_fd != -1)
{
close(redirector_fd);
redirector_fd = -1;
@ -43,7 +42,7 @@ static bool redir_open_private(const char *fname, int flags)
DLOG_PERROR("redir_openv_private");
return false;
}
DBGPRINT("opened redirector %s\n",fname);
DBGPRINT("opened redirector %s\n", fname);
return true;
}
bool redir_init(void)
@ -56,74 +55,79 @@ static bool destination_from_pf(const struct sockaddr *accept_sa, struct sockadd
struct pfioc_natlook nl;
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];
*s=0; 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);
char s[48], s2[48];
*s = 0;
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);
}
saconvmapped(orig_dst);
if (accept_sa->sa_family==AF_INET6 && orig_dst->ss_family==AF_INET)
if (accept_sa->sa_family == AF_INET6 && orig_dst->ss_family == AF_INET)
{
memcpy(&asa2,accept_sa,sizeof(struct sockaddr_in6));
memcpy(&asa2, accept_sa, sizeof(struct sockaddr_in6));
saconvmapped(&asa2);
accept_sa = (struct sockaddr*)&asa2;
accept_sa = (struct sockaddr *)&asa2;
}
if (params.debug>=2)
if (params.debug >= 2)
{
char s[48],s2[48];
*s=0; 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);
char s[48], s2[48];
*s = 0;
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);
}
if (accept_sa->sa_family!=orig_dst->ss_family)
if (accept_sa->sa_family != orig_dst->ss_family)
{
DBGPRINT("accept_sa and orig_dst sa_family mismatch : %d %d\n", accept_sa->sa_family, orig_dst->ss_family);
return false;
}
memset(&nl, 0, sizeof(nl));
nl.proto = IPPROTO_TCP;
nl.direction = PF_OUT;
nl.proto = IPPROTO_TCP;
nl.direction = PF_OUT;
nl.af = orig_dst->ss_family;
switch(orig_dst->ss_family)
switch (orig_dst->ss_family)
{
case AF_INET:
{
{
struct sockaddr_in *sin = (struct sockaddr_in *)orig_dst;
nl.daddr.v4.s_addr = sin->sin_addr.s_addr;
nl.saddr.v4.s_addr = ((struct sockaddr_in*)accept_sa)->sin_addr.s_addr;
nl.saddr.v4.s_addr = ((struct sockaddr_in *)accept_sa)->sin_addr.s_addr;
#ifdef __APPLE__
nl.sxport.port = ((struct sockaddr_in*)accept_sa)->sin_port;
nl.dxport.port = sin->sin_port;
nl.sxport.port = ((struct sockaddr_in *)accept_sa)->sin_port;
nl.dxport.port = sin->sin_port;
#else
nl.sport = ((struct sockaddr_in*)accept_sa)->sin_port;
nl.dport = sin->sin_port;
nl.sport = ((struct sockaddr_in *)accept_sa)->sin_port;
nl.dport = sin->sin_port;
#endif
}
break;
}
break;
case AF_INET6:
{
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)orig_dst;
nl.daddr.v6 = sin6->sin6_addr;
nl.saddr.v6 = ((struct sockaddr_in6*)accept_sa)->sin6_addr;
nl.saddr.v6 = ((struct sockaddr_in6 *)accept_sa)->sin6_addr;
#ifdef __APPLE__
nl.sxport.port = ((struct sockaddr_in6*)accept_sa)->sin6_port;
nl.sxport.port = ((struct sockaddr_in6 *)accept_sa)->sin6_port;
nl.dxport.port = sin6->sin6_port;
#else
nl.sport = ((struct sockaddr_in6*)accept_sa)->sin6_port;
nl.sport = ((struct sockaddr_in6 *)accept_sa)->sin6_port;
nl.dport = sin6->sin6_port;
#endif
}
break;
}
break;
default:
DBGPRINT("destination_from_pf : unexpected address family %d\n",orig_dst->ss_family);
DBGPRINT("destination_from_pf : unexpected address family %d\n", orig_dst->ss_family);
return false;
}
@ -134,45 +138,42 @@ static bool destination_from_pf(const struct sockaddr *accept_sa, struct sockadd
}
DBGPRINT("destination_from_pf : got orig dest addr from pf\n");
switch(nl.af)
switch (nl.af)
{
case AF_INET:
orig_dst->ss_family = nl.af;
#ifdef __APPLE__
((struct sockaddr_in*)orig_dst)->sin_port = nl.rdxport.port;
((struct sockaddr_in *)orig_dst)->sin_port = nl.rdxport.port;
#else
((struct sockaddr_in*)orig_dst)->sin_port = nl.rdport;
((struct sockaddr_in *)orig_dst)->sin_port = nl.rdport;
#endif
((struct sockaddr_in*)orig_dst)->sin_addr = nl.rdaddr.v4;
((struct sockaddr_in *)orig_dst)->sin_addr = nl.rdaddr.v4;
break;
case AF_INET6:
orig_dst->ss_family = nl.af;
#ifdef __APPLE__
((struct sockaddr_in6*)orig_dst)->sin6_port = nl.rdxport.port;
((struct sockaddr_in6 *)orig_dst)->sin6_port = nl.rdxport.port;
#else
((struct sockaddr_in6*)orig_dst)->sin6_port = nl.rdport;
((struct sockaddr_in6 *)orig_dst)->sin6_port = nl.rdport;
#endif
((struct sockaddr_in6*)orig_dst)->sin6_addr = nl.rdaddr.v6;
((struct sockaddr_in6 *)orig_dst)->sin6_addr = nl.rdaddr.v6;
break;
default:
DBGPRINT("destination_from_pf : DIOCNATLOOK returned unexpected address family %d\n",nl.af);
DBGPRINT("destination_from_pf : DIOCNATLOOK returned unexpected address family %d\n", nl.af);
return false;
}
return true;
}
#else
bool redir_init(void) {return true;}
bool redir_init(void) { return true; }
void redir_close(void) {};
#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)
{
char orig_dst_str[INET6_ADDRSTRLEN];
@ -181,28 +182,28 @@ bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr
memset(orig_dst, 0, addrlen);
//For UDP transparent proxying:
//Set IP_RECVORIGDSTADDR socket option for getting the original
//destination of a datagram
// For UDP transparent proxying:
// Set IP_RECVORIGDSTADDR socket option for getting the original
// destination of a datagram
#ifdef __linux__
// DNAT
r=getsockopt(sockfd, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr*) orig_dst, &addrlen);
if (r<0)
r = getsockopt(sockfd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, (struct sockaddr*) orig_dst, &addrlen);
if (r<0)
r = getsockopt(sockfd, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr *)orig_dst, &addrlen);
if (r < 0)
r = getsockopt(sockfd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, (struct sockaddr *)orig_dst, &addrlen);
if (r < 0)
{
DBGPRINT("both SO_ORIGINAL_DST and IP6T_SO_ORIGINAL_DST failed !\n");
#endif
// TPROXY : socket is bound to original destination
r=getsockname(sockfd, (struct sockaddr*) orig_dst, &addrlen);
if (r<0)
r = getsockname(sockfd, (struct sockaddr *)orig_dst, &addrlen);
if (r < 0)
{
DLOG_PERROR("getsockname");
return false;
}
if (orig_dst->ss_family==AF_INET6)
((struct sockaddr_in6*)orig_dst)->sin6_scope_id=0; // or MacOS will not connect()
if (orig_dst->ss_family == AF_INET6)
((struct sockaddr_in6 *)orig_dst)->sin6_scope_id = 0; // or macOS will not connect()
#ifdef BSD
if (params.pf_enable && !destination_from_pf(accept_sa, orig_dst))
DBGPRINT("pf filter destination_from_pf failed\n");
@ -217,13 +218,13 @@ bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr
{
if (orig_dst->ss_family == AF_INET)
{
inet_ntop(AF_INET, &(((struct sockaddr_in*) orig_dst)->sin_addr), orig_dst_str, INET_ADDRSTRLEN);
VPRINT("Original destination for socket fd=%d : %s:%d\n", sockfd,orig_dst_str, htons(((struct sockaddr_in*) orig_dst)->sin_port));
inet_ntop(AF_INET, &(((struct sockaddr_in *)orig_dst)->sin_addr), orig_dst_str, INET_ADDRSTRLEN);
VPRINT("Original destination for socket fd=%d : %s:%d\n", sockfd, orig_dst_str, htons(((struct sockaddr_in *)orig_dst)->sin_port));
}
else if (orig_dst->ss_family == AF_INET6)
{
inet_ntop(AF_INET6,&(((struct sockaddr_in6*) orig_dst)->sin6_addr), orig_dst_str, INET6_ADDRSTRLEN);
VPRINT("Original destination for socket fd=%d : [%s]:%d\n", sockfd,orig_dst_str, htons(((struct sockaddr_in6*) orig_dst)->sin6_port));
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)orig_dst)->sin6_addr), orig_dst_str, INET6_ADDRSTRLEN);
VPRINT("Original destination for socket fd=%d : [%s]:%d\n", sockfd, orig_dst_str, htons(((struct sockaddr_in6 *)orig_dst)->sin6_port));
}
}
return true;

View File

@ -7,7 +7,7 @@
#include <stdio.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <sys/syscall.h>
@ -17,7 +17,7 @@
#define SIG_BREAK SIGUSR1
#ifdef __APPLE__
static const char *sem_name="/tpws_resolver";
static const char *sem_name = "/tpws_resolver";
#endif
TAILQ_HEAD(resolve_tailhead, resolve_item);
@ -35,7 +35,7 @@ typedef struct
pthread_t *thread;
bool bInit, bStop;
} t_resolver;
static t_resolver resolver = { .bInit = false };
static t_resolver resolver = {.bInit = false};
#define rlist_lock pthread_mutex_lock(&resolver.resolve_list_lock)
#define rlist_unlock pthread_mutex_unlock(&resolver.resolve_list_lock)
@ -47,7 +47,8 @@ static void resolver_clear_list(void)
for (;;)
{
ri = TAILQ_FIRST(&resolver.resolve_list);
if (!ri) break;
if (!ri)
break;
TAILQ_REMOVE(&resolver.resolve_list, ri, next);
free(ri);
}
@ -57,7 +58,7 @@ int resolver_thread_count(void)
{
return resolver.bInit ? resolver.threads : 0;
}
static void *resolver_thread(void *arg)
{
int r;
@ -66,15 +67,17 @@ static void *resolver_thread(void *arg)
sigemptyset(&signal_mask);
sigaddset(&signal_mask, SIG_BREAK);
//printf("resolver_thread %d start\n",syscall(SYS_gettid));
for(;;)
// printf("resolver_thread %d start\n",syscall(SYS_gettid));
for (;;)
{
if (resolver.bStop) break;
if (resolver.bStop)
break;
r = sem_wait(resolver.sem);
if (resolver.bStop) break;
if (resolver.bStop)
break;
if (r)
{
if (errno!=EINTR)
if (errno != EINTR)
{
DLOG_PERROR("sem_wait (resolver_thread)");
break; // fatal err
@ -87,36 +90,37 @@ static void *resolver_thread(void *arg)
rlist_lock;
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;
if (ri)
{
struct addrinfo *ai,hints;
struct addrinfo *ai, hints;
char sport[6];
//printf("THREAD %d GOT JOB %s\n", syscall(SYS_gettid), ri->dom);
snprintf(sport,sizeof(sport),"%u",ri->port);
// printf("THREAD %d GOT JOB %s\n", syscall(SYS_gettid), ri->dom);
snprintf(sport, sizeof(sport), "%u", ri->port);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
// unfortunately getaddrinfo cannot be interrupted with a signal. we cannot cancel a query
ri->ga_res = getaddrinfo(ri->dom,sport,&hints,&ai);
ri->ga_res = getaddrinfo(ri->dom, sport, &hints, &ai);
if (!ri->ga_res)
{
memcpy(&ri->ss, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
}
//printf("THREAD %d END JOB %s FIRST=%p\n", syscall(SYS_gettid), ri->dom, TAILQ_FIRST(&resolver.resolve_list));
// printf("THREAD %d END JOB %s FIRST=%p\n", syscall(SYS_gettid), ri->dom, TAILQ_FIRST(&resolver.resolve_list));
// never interrupt this
pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);
wr = write(resolver.fd_signal_pipe,&ri,sizeof(void*));
if (wr<0)
wr = write(resolver.fd_signal_pipe, &ri, sizeof(void *));
if (wr < 0)
{
free(ri);
DLOG_PERROR("write resolve_pipe");
}
else if (wr!=sizeof(void*))
else if (wr != sizeof(void *))
{
// partial pointer write is FATAL. in any case it will cause pointer corruption and coredump
free(ri);
@ -127,7 +131,7 @@ static void *resolver_thread(void *arg)
}
}
}
//printf("resolver_thread %d exit\n",syscall(SYS_gettid));
// printf("resolver_thread %d exit\n",syscall(SYS_gettid));
return NULL;
}
@ -149,19 +153,19 @@ void resolver_deinit(void)
pthread_kill(resolver.thread[t], SIGUSR1);
pthread_join(resolver.thread[t], NULL);
}
pthread_mutex_destroy(&resolver.resolve_list_lock);
free(resolver.thread);
#ifdef __APPLE__
sem_close(resolver.sem);
#else
sem_destroy(resolver.sem);
#endif
#ifdef __APPLE__
sem_close(resolver.sem);
#else
sem_destroy(resolver.sem);
#endif
resolver_clear_list();
memset(&resolver,0,sizeof(resolver));
memset(&resolver, 0, sizeof(resolver));
}
}
@ -170,18 +174,19 @@ bool resolver_init(int threads, int fd_signal_pipe)
int t;
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;
#ifdef __APPLE__
// MacOS does not support unnamed semaphores
char sn[64];
snprintf(sn,sizeof(sn),"%s_%d",sem_name,getpid());
resolver.sem = sem_open(sn,O_CREAT,0600,0);
if (resolver.sem==SEM_FAILED)
snprintf(sn, sizeof(sn), "%s_%d", sem_name, getpid());
resolver.sem = sem_open(sn, O_CREAT, 0600, 0);
if (resolver.sem == SEM_FAILED)
{
DLOG_PERROR("sem_open");
goto ex;
@ -189,48 +194,51 @@ bool resolver_init(int threads, int fd_signal_pipe)
// unlink immediately to remove tails
sem_unlink(sn);
#else
if (sem_init(&resolver._sem,0,0)==-1)
{
if (sem_init(&resolver._sem, 0, 0) == -1)
{
DLOG_PERROR("sem_init");
goto ex;
}
resolver.sem = &resolver._sem;
#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;
TAILQ_INIT(&resolver.resolve_list);
// start as many threads as we can up to specified number
resolver.thread = malloc(sizeof(pthread_t)*threads);
if (!resolver.thread) goto ex;
resolver.thread = malloc(sizeof(pthread_t) * threads);
if (!resolver.thread)
goto ex;
memset(&action,0,sizeof(action));
memset(&action, 0, sizeof(action));
action.sa_handler = sigbreak;
sigaction(SIG_BREAK, &action, NULL);
pthread_attr_t attr;
if (pthread_attr_init(&attr)) goto ex;
if (pthread_attr_init(&attr))
goto ex;
// 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))
{
pthread_attr_destroy(&attr);
goto ex;
}
for(t=0, resolver.threads=threads ; t<threads ; t++)
for (t = 0, resolver.threads = threads; t < threads; t++)
{
if (pthread_create(resolver.thread + t, &attr, resolver_thread, NULL))
{
resolver.threads=t;
resolver.threads = t;
break;
}
}
pthread_attr_destroy(&attr);
if (!resolver.threads) goto ex;
if (!resolver.threads)
goto ex;
return true;
@ -239,22 +247,21 @@ ex:
return false;
}
struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr)
{
struct resolve_item *ri = calloc(1,sizeof(struct resolve_item));
if (!ri) return NULL;
struct resolve_item *ri = calloc(1, sizeof(struct resolve_item));
if (!ri)
return NULL;
strncpy(ri->dom,dom,sizeof(ri->dom));
ri->dom[sizeof(ri->dom)-1] = 0;
strncpy(ri->dom, dom, sizeof(ri->dom));
ri->dom[sizeof(ri->dom) - 1] = 0;
ri->port = port;
ri->ptr = ptr;
rlist_lock;
TAILQ_INSERT_TAIL(&resolver.resolve_list, ri, next);
rlist_unlock;
if (sem_post(resolver.sem)<0)
if (sem_post(resolver.sem) < 0)
{
DLOG_PERROR("resolver_queue sem_post");
free(ri);

View File

@ -8,12 +8,13 @@
struct resolve_item
{
char dom[256]; // request dom
char dom[256]; // request dom
struct sockaddr_storage ss; // resolve result
int ga_res; // getaddrinfo result code
uint16_t port; // request port
int ga_res; // getaddrinfo result code
uint16_t port; // request port
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);

View File

@ -23,103 +23,102 @@
// block most of the undesired syscalls to harden against code execution
static long blocked_syscalls[] = {
#ifdef SYS_execv
SYS_execv,
SYS_execv,
#endif
SYS_execve,
SYS_execve,
#ifdef SYS_execveat
SYS_execveat,
SYS_execveat,
#endif
#ifdef SYS_exec_with_loader
SYS_exec_with_loader,
SYS_exec_with_loader,
#endif
#ifdef SYS_osf_execve
SYS_osf_execve,
SYS_osf_execve,
#endif
#ifdef SYS_uselib
SYS_uselib,
SYS_uselib,
#endif
#ifdef SYS_unlink
SYS_unlink,
SYS_unlink,
#endif
SYS_unlinkat,
SYS_unlinkat,
#ifdef SYS_chmod
SYS_chmod,
SYS_chmod,
#endif
SYS_fchmod,SYS_fchmodat,
SYS_fchmod, SYS_fchmodat,
#ifdef SYS_chown
SYS_chown,
SYS_chown,
#endif
#ifdef SYS_chown32
SYS_chown32,
SYS_chown32,
#endif
SYS_fchown,
SYS_fchown,
#ifdef SYS_fchown32
SYS_fchown32,
SYS_fchown32,
#endif
#ifdef SYS_lchown
SYS_lchown,
SYS_lchown,
#endif
#ifdef SYS_lchown32
SYS_lchown32,
SYS_lchown32,
#endif
SYS_fchownat,
SYS_fchownat,
#ifdef SYS_symlink
SYS_symlink,
SYS_symlink,
#endif
SYS_symlinkat,
SYS_symlinkat,
#ifdef SYS_link
SYS_link,
SYS_link,
#endif
SYS_linkat,
SYS_truncate,
SYS_linkat,
SYS_truncate,
#ifdef SYS_truncate64
SYS_truncate64,
SYS_truncate64,
#endif
SYS_ftruncate,
SYS_ftruncate,
#ifdef SYS_ftruncate64
SYS_ftruncate64,
SYS_ftruncate64,
#endif
#ifdef SYS_mknod
SYS_mknod,
SYS_mknod,
#endif
SYS_mknodat,
SYS_mknodat,
#ifdef SYS_mkdir
SYS_mkdir,
SYS_mkdir,
#endif
SYS_mkdirat,
SYS_mkdirat,
#ifdef SYS_rmdir
SYS_rmdir,
SYS_rmdir,
#endif
#ifdef SYS_rename
SYS_rename,
SYS_rename,
#endif
#ifdef SYS_renameat2
SYS_renameat2,
SYS_renameat2,
#endif
#ifdef SYS_renameat
SYS_renameat,
SYS_renameat,
#endif
#ifdef SYS_readdir
SYS_readdir,
SYS_readdir,
#endif
#ifdef SYS_getdents
SYS_getdents,
SYS_getdents,
#endif
#ifdef SYS_getdents64
SYS_getdents64,
SYS_getdents64,
#endif
#ifdef SYS_process_vm_readv
SYS_process_vm_readv,
SYS_process_vm_readv,
#endif
#ifdef SYS_process_vm_writev
SYS_process_vm_writev,
SYS_process_vm_writev,
#endif
#ifdef SYS_process_madvise
SYS_process_madvise,
SYS_process_madvise,
#endif
SYS_kill, SYS_ptrace
};
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls))
SYS_kill, SYS_ptrace};
#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)
{
@ -132,13 +131,13 @@ static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf,
static bool set_seccomp(void)
{
#ifdef __X32_SYSCALL_BIT
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
#else
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
#endif
struct sock_filter sockf[SECCOMP_PROG_SIZE];
struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE, .filter = sockf };
int i,idx=0;
struct sock_fprog prog = {.len = SECCOMP_PROG_SIZE, .filter = sockf};
int i, idx = 0;
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr);
#ifdef __X32_SYSCALL_BIT
@ -151,19 +150,19 @@ static bool set_seccomp(void)
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr);
#endif
/*
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr
*/
for(i=0 ; i<BLOCKED_SYSCALL_COUNT ; i++)
/*
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr
*/
for (i = 0; i < BLOCKED_SYSCALL_COUNT; i++)
{
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, BLOCKED_SYSCALL_COUNT-i, 0, blocked_syscalls[i]);
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, BLOCKED_SYSCALL_COUNT - i, 0, blocked_syscalls[i]);
}
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_ALLOW); // success case
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); // fail case
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); // fail case
return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) >= 0;
}
@ -174,42 +173,41 @@ bool sec_harden(void)
DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)");
return false;
}
#if ARCH_NR!=0
#if ARCH_NR != 0
if (!set_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;
}
#endif
return true;
}
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_data_struct cd[2];
uint32_t c0 = (uint32_t)caps;
uint32_t c1 = (uint32_t)(caps>>32);
uint32_t c1 = (uint32_t)(caps >> 32);
return !capget(&ch,cd) && (cd[0].effective & c0)==c0 && (cd[1].effective & c1)==c1;
return !capget(&ch, cd) && (cd[0].effective & c0) == c0 && (cd[1].effective & c1) == c1;
}
bool setpcap(uint64_t caps)
{
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
struct __user_cap_data_struct cd[2];
cd[0].effective = cd[0].permitted = (uint32_t)caps;
cd[0].inheritable = 0;
cd[1].effective = cd[1].permitted = (uint32_t)(caps>>32);
cd[1].effective = cd[1].permitted = (uint32_t)(caps >> 32);
cd[1].inheritable = 0;
return !capset(&ch,cd);
return !capset(&ch, cd);
}
int getmaxcap(void)
{
@ -221,18 +219,17 @@ int getmaxcap(void)
fclose(F);
}
return maxcap;
}
bool dropcaps(void)
{
uint64_t caps = 0;
int maxcap = getmaxcap();
if (setpcap(caps|(1<<CAP_SETPCAP)))
if (setpcap(caps | (1 << CAP_SETPCAP)))
{
for (int cap = 0; cap <= maxcap; cap++)
{
if (prctl(PR_CAPBSET_DROP, cap)<0)
if (prctl(PR_CAPBSET_DROP, cap) < 0)
{
DLOG_ERR("could not drop bound cap %d\n", cap);
DLOG_PERROR("cap_drop_bound");
@ -257,13 +254,11 @@ bool sec_harden(void)
#endif // __linux__
bool can_drop_root(void)
{
#ifdef __linux__
// has some caps
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID)|(1<<CAP_SETPCAP));
return checkpcap((1 << CAP_SETUID) | (1 << CAP_SETGID) | (1 << CAP_SETPCAP));
#else
// effective root
return !geteuid();
@ -280,7 +275,7 @@ bool droproot(uid_t uid, gid_t gid)
}
#endif
// drop all SGIDs
if (setgroups(0,NULL))
if (setgroups(0, NULL))
{
DLOG_PERROR("setgroups");
return false;
@ -304,19 +299,19 @@ bool droproot(uid_t uid, gid_t gid)
void print_id(void)
{
int i,N;
gid_t g[128];
int i, N;
gid_t g[128];
DLOG_CONDUP("Running as UID=%u GID=",getuid());
N=getgroups(sizeof(g)/sizeof(*g),g);
if (N>0)
{
for(i=0;i<N;i++)
DLOG_CONDUP(i==(N-1) ? "%u" : "%u,", g[i]);
DLOG_CONDUP("\n");
}
else
DLOG_CONDUP("%u\n",getgid());
DLOG_CONDUP("Running as UID=%u GID=", getuid());
N = getgroups(sizeof(g) / sizeof(*g), g);
if (N > 0)
{
for (i = 0; i < N; i++)
DLOG_CONDUP(i == (N - 1) ? "%u" : "%u,", g[i]);
DLOG_CONDUP("\n");
}
else
DLOG_CONDUP("%u\n", getgid());
}
void daemonize(void)

View File

@ -22,61 +22,61 @@ bool dropcaps(void);
#if defined(__aarch64__)
# define ARCH_NR AUDIT_ARCH_AARCH64
#define ARCH_NR AUDIT_ARCH_AARCH64
#elif defined(__amd64__)
# define ARCH_NR AUDIT_ARCH_X86_64
#define ARCH_NR AUDIT_ARCH_X86_64
#elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__))
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_ARM
# else
# define ARCH_NR AUDIT_ARCH_ARMEB
# endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_ARM
#else
#define ARCH_NR AUDIT_ARCH_ARMEB
#endif
#elif defined(__i386__)
# define ARCH_NR AUDIT_ARCH_I386
#define ARCH_NR AUDIT_ARCH_I386
#elif defined(__mips__)
#if _MIPS_SIM == _MIPS_SIM_ABI32
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_MIPSEL
# else
# define ARCH_NR AUDIT_ARCH_MIPS
# endif
#elif _MIPS_SIM == _MIPS_SIM_ABI64
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_MIPSEL64
# else
# define ARCH_NR AUDIT_ARCH_MIPS64
# endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_MIPSEL
#else
# error "Unsupported mips abi"
#define ARCH_NR AUDIT_ARCH_MIPS
#endif
#elif _MIPS_SIM == _MIPS_SIM_ABI64
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_MIPSEL64
#else
#define ARCH_NR AUDIT_ARCH_MIPS64
#endif
#else
#error "Unsupported MIPS ABI"
#endif
#elif defined(__PPC64__)
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_PPC64LE
# else
# define ARCH_NR AUDIT_ARCH_PPC64
# endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_PPC64LE
#else
#define ARCH_NR AUDIT_ARCH_PPC64
#endif
#elif defined(__PPC__)
# define ARCH_NR AUDIT_ARCH_PPC
#define ARCH_NR AUDIT_ARCH_PPC
#elif __riscv && __riscv_xlen == 64
# define ARCH_NR AUDIT_ARCH_RISCV64
#define ARCH_NR AUDIT_ARCH_RISCV64
#else
# error "Platform does not support seccomp filter yet"
#error "Platform does not support seccomp filter yet"
#endif

View File

@ -3,87 +3,91 @@
#include <stdint.h>
#include <arpa/inet.h>
#pragma pack(push,1)
#pragma pack(push, 1)
#define S4_CMD_CONNECT 1
#define S4_CMD_BIND 2
#define S4_CMD_CONNECT 1
#define S4_CMD_BIND 2
typedef struct
{
uint8_t ver,cmd;
uint8_t ver, cmd;
uint16_t port;
uint32_t ip;
} s4_req;
#define S4_REQ_HEADER_VALID(r,l) (l>=sizeof(s4_req) && r->ver==4)
#define S4_REQ_CONNECT_VALID(r,l) (S4_REQ_HEADER_VALID(r,l) && r->cmd==S4_CMD_CONNECT)
#define S4_REQ_HEADER_VALID(r, l) (l >= sizeof(s4_req) && r->ver == 4)
#define S4_REQ_CONNECT_VALID(r, l) (S4_REQ_HEADER_VALID(r, l) && r->cmd == S4_CMD_CONNECT)
#define S4_REP_OK 90
#define S4_REP_FAILED 91
#define S4_REP_OK 90
#define S4_REP_FAILED 91
typedef struct
{
uint8_t zero,rep;
uint8_t zero, rep;
uint16_t port;
uint32_t ip;
} s4_rep;
#define S5_AUTH_NONE 0
#define S5_AUTH_GSSAPI 1
#define S5_AUTH_USERPASS 2
#define S5_AUTH_UNACCEPTABLE 0xFF
#define S5_AUTH_NONE 0
#define S5_AUTH_GSSAPI 1
#define S5_AUTH_USERPASS 2
#define S5_AUTH_UNACCEPTABLE 0xFF
typedef struct
{
uint8_t ver,nmethods,methods[255];
uint8_t ver, nmethods, methods[255];
} s5_handshake;
#define S5_REQ_HANDHSHAKE_VALID(r,l) (l>=3 && r->ver==5 && r->nmethods && l>=(2+r->nmethods))
#define S5_REQ_HANDHSHAKE_VALID(r, l) (l >= 3 && r->ver == 5 && r->nmethods && l >= (2 + r->nmethods))
typedef struct
{
uint8_t ver,method;
uint8_t ver, method;
} s5_handshake_ack;
#define S5_CMD_CONNECT 1
#define S5_CMD_BIND 2
#define S5_CMD_UDP_ASSOC 3
#define S5_ATYP_IP4 1
#define S5_ATYP_DOM 3
#define S5_ATYP_IP6 4
#define S5_CMD_CONNECT 1
#define S5_CMD_BIND 2
#define S5_CMD_UDP_ASSOC 3
#define S5_ATYP_IP4 1
#define S5_ATYP_DOM 3
#define S5_ATYP_IP6 4
typedef struct
{
uint8_t ver,cmd,rsv,atyp;
union {
struct {
uint8_t ver, cmd, rsv, atyp;
union
{
struct
{
struct in_addr addr;
uint16_t port;
} d4;
struct {
struct
{
struct in6_addr addr;
uint16_t port;
} d6;
struct {
struct
{
uint8_t len;
char domport[255+2]; // max hostname + binary port
char domport[255 + 2]; // max hostname + binary port
} dd;
};
} s5_req;
#define S5_REQ_HEADER_VALID(r,l) (l>=4 && r->ver==5)
#define S5_IP46_VALID(r,l) ((r->atyp==S5_ATYP_IP4 && l>=(4+sizeof(r->d4))) || (r->atyp==S5_ATYP_IP6 && l>=(4+sizeof(r->d6))))
#define S5_REQ_CONNECT_VALID(r,l) (S5_REQ_HEADER_VALID(r,l) && r->cmd==S5_CMD_CONNECT && (S5_IP46_VALID(r,l) || (r->atyp==S5_ATYP_DOM && l>=5 && l>=(5+r->dd.len))))
#define S5_PORT_FROM_DD(r,l) (l>=(4+r->dd.len+2) ? ntohs(*(uint16_t*)(r->dd.domport+r->dd.len)) : 0)
#define S5_REQ_HEADER_VALID(r, l) (l >= 4 && r->ver == 5)
#define S5_IP46_VALID(r, l) ((r->atyp == S5_ATYP_IP4 && l >= (4 + sizeof(r->d4))) || (r->atyp == S5_ATYP_IP6 && l >= (4 + sizeof(r->d6))))
#define S5_REQ_CONNECT_VALID(r, l) (S5_REQ_HEADER_VALID(r, l) && r->cmd == S5_CMD_CONNECT && (S5_IP46_VALID(r, l) || (r->atyp == S5_ATYP_DOM && l >= 5 && l >= (5 + r->dd.len))))
#define S5_PORT_FROM_DD(r, l) (l >= (4 + r->dd.len + 2) ? ntohs(*(uint16_t *)(r->dd.domport + r->dd.len)) : 0)
#define S5_REP_OK 0
#define S5_REP_GENERAL_FAILURE 1
#define S5_REP_NOT_ALLOWED_BY_RULESET 2
#define S5_REP_NETWORK_UNREACHABLE 3
#define S5_REP_HOST_UNREACHABLE 4
#define S5_REP_CONN_REFUSED 5
#define S5_REP_TTL_EXPIRED 6
#define S5_REP_COMMAND_NOT_SUPPORTED 7
#define S5_REP_ADDR_TYPE_NOT_SUPPORTED 8
#define S5_REP_OK 0
#define S5_REP_GENERAL_FAILURE 1
#define S5_REP_NOT_ALLOWED_BY_RULESET 2
#define S5_REP_NETWORK_UNREACHABLE 3
#define S5_REP_HOST_UNREACHABLE 4
#define S5_REP_CONN_REFUSED 5
#define S5_REP_TTL_EXPIRED 6
#define S5_REP_COMMAND_NOT_SUPPORTED 7
#define S5_REP_ADDR_TYPE_NOT_SUPPORTED 8
typedef struct
{
uint8_t ver,rep,rsv,atyp;
union {
struct {
uint8_t ver, rep, rsv, atyp;
union
{
struct
{
struct in_addr addr;
uint16_t port;
} d4;

View File

@ -9,36 +9,40 @@
#include <stdio.h>
// segment buffer has at least 5 extra bytes to extend data block
void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags)
void tamper_out(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size, size_t *split_pos, uint8_t *split_flags)
{
uint8_t *p, *pp, *pHost = NULL;
size_t method_len = 0, pos;
const char *method;
bool bBypass = false, bHaveHost = false, bHostExcluded = false;
char *pc, Host[256];
DBGPRINT("tamper_out\n");
*split_pos=0;
*split_flags=0;
*split_pos = 0;
*split_flags = 0;
if ((method = HttpMethod(segment,*size)))
if ((method = HttpMethod(segment, *size)))
{
method_len = strlen(method)-2;
VPRINT("Data block looks like http request start : %s\n", method);
if (!ctrack->l7proto) ctrack->l7proto=HTTP;
method_len = strlen(method) - 2;
VPRINT("Data block looks like HTTP request start : %s\n", method);
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
if ((params.hostlist || params.hostlist_exclude) && HttpFindHost(&pHost,segment,*size))
if ((params.hostlist || params.hostlist_exclude) && HttpFindHost(&pHost, segment, *size))
{
p = pHost + 5;
while (p < (segment + *size) && (*p == ' ' || *p == '\t')) p++;
while (p < (segment + *size) && (*p == ' ' || *p == '\t'))
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);
Host[pp - p] = '\0';
bHaveHost = true;
VPRINT("Requested Host is : %s\n", Host);
for(pc = Host; *pc; pc++) *pc=tolower(*pc);
for (pc = Host; *pc; pc++)
*pc = tolower(*pc);
bBypass = !HostlistCheck(Host, &bHostExcluded);
}
if (!bBypass)
@ -48,7 +52,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
p = pp = segment;
while ((p = memmem(p, segment + *size - p, "\r\n", 2)))
{
*p = '\n'; p++;
*p = '\n';
p++;
memmove(p, p + 1, segment + *size - p - 1);
(*size)--;
if (pp == (p - 1))
@ -61,13 +66,14 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
}
pHost = NULL; // invalidate
}
if (params.methodeol && (*size+1+!params.unixeol)<=segment_buffer_size)
if (params.methodeol && (*size + 1 + !params.unixeol) <= segment_buffer_size)
{
VPRINT("Adding EOL before method\n");
if (params.unixeol)
{
memmove(segment + 1, segment, *size);
(*size)++;;
(*size)++;
;
segment[0] = '\n';
}
else
@ -79,39 +85,41 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
}
pHost = NULL; // invalidate
}
if (params.methodspace && *size<segment_buffer_size)
if (params.methodspace && *size < segment_buffer_size)
{
// we only work with data blocks looking as HTTP query, so method is at the beginning
VPRINT("Adding extra space after method\n");
p = segment + method_len + 1;
pos = method_len + 1;
memmove(p + 1, p, *size - pos);
*p = ' '; // insert extra space
*p = ' '; // insert extra space
(*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;
while (p < (segment + *size) && *p != '\r' && *p != '\n') p++;
while (p < (segment + *size) && *p != '\r' && *p != '\n')
p++;
if (p < (segment + *size))
{
pos = p - segment;
VPRINT("Adding %s to host name at pos %zu\n", params.hostdot ? "dot" : "tab", pos);
memmove(p + 1, p, *size - pos);
*p = params.hostdot ? '.' : '\t'; // insert dot or tab
(*size)++; // block will grow by 1 byte
(*size)++; // block will grow by 1 byte
}
}
if (params.domcase && HttpFindHost(&pHost,segment,*size))
if (params.domcase && HttpFindHost(&pHost, segment, *size))
{
p = pHost + 5;
pos = p - segment;
VPRINT("Mixing domain case at pos %zu\n",pos);
VPRINT("Mixing domain case at pos %zu\n", pos);
for (; p < (segment + *size) && *p != '\r' && *p != '\n'; p++)
*p = (((size_t)p) & 1) ? tolower(*p) : toupper(*p);
}
if (params.hostnospace && HttpFindHost(&pHost,segment,*size) && (pHost+5)<(segment+*size) && pHost[5] == ' ')
if (params.hostnospace && HttpFindHost(&pHost, segment, *size) && (pHost + 5) < (segment + *size) && pHost[5] == ' ')
{
p = pHost + 6;
pos = p - segment;
@ -119,78 +127,83 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
memmove(p - 1, p, *size - pos);
(*size)--; // block will shrink by 1 byte
}
if (params.hostcase && HttpFindHost(&pHost,segment,*size))
if (params.hostcase && HttpFindHost(&pHost, segment, *size))
{
VPRINT("Changing 'Host:' => '%c%c%c%c:' at pos %td\n", params.hostspell[0], params.hostspell[1], params.hostspell[2], params.hostspell[3], pHost - segment);
memcpy(pHost, params.hostspell, 4);
}
if (params.hostpad && HttpFindHost(&pHost,segment,*size))
if (params.hostpad && HttpFindHost(&pHost, segment, *size))
{
// add : XXXXX: <padding?[\r\n|\n]
char s[8];
size_t hsize = params.unixeol ? 8 : 9;
size_t hostpad = params.hostpad<hsize ? hsize : params.hostpad;
size_t hostpad = params.hostpad < hsize ? hsize : params.hostpad;
if ((hsize+*size)>segment_buffer_size)
if ((hsize + *size) > segment_buffer_size)
VPRINT("could not add host padding : buffer too small\n");
else
{
if ((hostpad+*size)>segment_buffer_size)
if ((hostpad + *size) > segment_buffer_size)
{
hostpad=segment_buffer_size-*size;
hostpad = segment_buffer_size - *size;
VPRINT("host padding reduced to %zu bytes : buffer too small\n", hostpad);
}
else
VPRINT("host padding with %zu bytes\n", hostpad);
p = pHost;
pos = p - segment;
memmove(p + hostpad, p, *size - pos);
(*size) += hostpad;
while(hostpad)
while (hostpad)
{
#define MAX_HDR_SIZE 2048
size_t padsize = hostpad > hsize ? hostpad-hsize : 0;
if (padsize>MAX_HDR_SIZE) padsize=MAX_HDR_SIZE;
#define MAX_HDR_SIZE 2048
size_t padsize = hostpad > hsize ? hostpad - hsize : 0;
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 ((hostpad-padsize-hsize)<hsize) padsize+=hostpad-padsize-hsize;
snprintf(s,sizeof(s),"%c%04x: ", 'a'+rand()%('z'-'a'+1), rand() & 0xFFFF);
memcpy(p,s,7);
p+=7;
memset(p,'a'+rand()%('z'-'a'+1),padsize);
p+=padsize;
if ((hostpad - padsize - hsize) < hsize)
padsize += hostpad - padsize - hsize;
snprintf(s, sizeof(s), "%c%04x: ", 'a' + rand() % ('z' - 'a' + 1), rand() & 0xFFFF);
memcpy(p, s, 7);
p += 7;
memset(p, 'a' + rand() % ('z' - 'a' + 1), padsize);
p += padsize;
if (params.unixeol)
*p++='\n';
*p++ = '\n';
else
{
*p++='\r';
*p++='\n';
*p++ = '\r';
*p++ = '\n';
}
hostpad-=hsize+padsize;
hostpad -= hsize + padsize;
}
pHost = NULL; // invalidate
}
}
*split_pos = HttpPos(params.split_http_req, params.split_pos, segment, *size);
if (params.disorder_http) *split_flags |= SPLIT_FLAG_DISORDER;
if (params.oob_http) *split_flags |= SPLIT_FLAG_OOB;
if (params.disorder_http)
*split_flags |= SPLIT_FLAG_DISORDER;
if (params.oob_http)
*split_flags |= SPLIT_FLAG_OOB;
}
else
{
VPRINT("Not acting on this request\n");
}
}
else if (IsTLSClientHello(segment,*size,false))
else if (IsTLSClientHello(segment, *size, false))
{
size_t tpos=0,spos=0;
if (!ctrack->l7proto) ctrack->l7proto=TLS;
size_t tpos = 0, spos = 0;
if (!ctrack->l7proto)
ctrack->l7proto = TLS;
VPRINT("packet contains TLS ClientHello\n");
// we need host only if hostlist is present
if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false))
if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t *)segment, *size, Host, sizeof(Host), false))
{
VPRINT("hostname: %s\n",Host);
VPRINT("hostname: %s\n", Host);
bHaveHost = true;
bBypass = !HostlistCheck(Host, &bHostExcluded);
}
@ -202,52 +215,59 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
{
spos = TLSPos(params.split_tls, params.split_pos, segment, *size, 0);
if ((5+*size)<=segment_buffer_size)
if ((5 + *size) <= segment_buffer_size)
{
tpos = TLSPos(params.tlsrec, params.tlsrec_pos+5, segment, *size, 0);
if (tpos>5)
tpos = TLSPos(params.tlsrec, params.tlsrec_pos + 5, segment, *size, 0);
if (tpos > 5)
{
// construct 2 TLS records from one
uint16_t l = pntoh16(segment+3); // length
if (l>=2)
uint16_t l = pntoh16(segment + 3); // length
if (l >= 2)
{
// length is checked in IsTLSClientHello and cannot exceed buffer size
if ((tpos-5)>=l) tpos=5+1;
VPRINT("making 2 TLS records at pos %zu\n",tpos);
memmove(segment+tpos+5,segment+tpos,*size-tpos);
if ((tpos - 5) >= l)
tpos = 5 + 1;
VPRINT("making 2 TLS records at pos %zu\n", tpos);
memmove(segment + tpos + 5, segment + tpos, *size - tpos);
segment[tpos] = segment[0];
segment[tpos+1] = segment[1];
segment[tpos+2] = segment[2];
phton16(segment+tpos+3,l-(tpos-5));
phton16(segment+3,tpos-5);
segment[tpos + 1] = segment[1];
segment[tpos + 2] = segment[2];
phton16(segment + tpos + 3, l - (tpos - 5));
phton16(segment + 3, tpos - 5);
*size += 5;
// 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;
}
}
}
if (spos && spos < *size)
{
VPRINT("split pos %zu\n",spos);
VPRINT("split pos %zu\n", spos);
*split_pos = spos;
}
if (params.disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER;
if (params.oob_tls) *split_flags |= SPLIT_FLAG_OOB;
if (params.disorder_tls)
*split_flags |= SPLIT_FLAG_DISORDER;
if (params.oob_tls)
*split_flags |= SPLIT_FLAG_OOB;
}
}
else if (params.split_any_protocol && params.split_pos < *size)
*split_pos = params.split_pos;
if (bHaveHost && bBypass && !bHostExcluded && *params.hostlist_auto_filename)
{
DBGPRINT("tamper_out put hostname : %s\n", Host);
if (ctrack->hostname) free(ctrack->hostname);
ctrack->hostname=strdup(Host);
if (ctrack->hostname)
free(ctrack->hostname);
ctrack->hostname = strdup(Host);
}
if (params.disorder) *split_flags |= SPLIT_FLAG_DISORDER;
if (params.oob) *split_flags |= SPLIT_FLAG_OOB;
if (params.disorder)
*split_flags |= SPLIT_FLAG_DISORDER;
if (params.oob)
*split_flags |= SPLIT_FLAG_OOB;
}
static void auto_hostlist_reset_fail_counter(const char *hostname)
@ -255,7 +275,7 @@ static void auto_hostlist_reset_fail_counter(const char *hostname)
if (hostname)
{
hostfail_pool *fail_counter;
fail_counter = HostFailPoolFind(params.hostlist_auto_fail_counters, hostname);
if (fail_counter)
{
@ -287,9 +307,9 @@ static void auto_hostlist_failed(const char *hostname)
{
VPRINT("auto hostlist : fail threshold reached. adding %s to auto hostlist\n", hostname);
HostFailPoolDel(&params.hostlist_auto_fail_counters, fail_counter);
VPRINT("auto hostlist : rechecking %s to avoid duplicates\n", hostname);
bool bExcluded=false;
bool bExcluded = false;
if (!HostlistCheck(hostname, &bExcluded) && !bExcluded)
{
VPRINT("auto hostlist : adding %s\n", hostname);
@ -314,9 +334,9 @@ static void auto_hostlist_failed(const char *hostname)
}
}
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size)
void tamper_in(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size)
{
bool bFail=false;
bool bFail = false;
DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname);
@ -324,9 +344,9 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
{
HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters);
if (ctrack->l7proto==HTTP && ctrack->hostname)
if (ctrack->l7proto == HTTP && ctrack->hostname)
{
if (IsHttpReply(segment,*size))
if (IsHttpReply(segment, *size))
{
VPRINT("incoming HTTP reply detected for hostname %s\n", ctrack->hostname);
bFail = HttpReplyLooksLikeDPIRedirect(segment, *size, ctrack->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
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;
}
@ -356,7 +376,8 @@ void rst_in(t_ctrack *ctrack)
{
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);
@ -371,7 +392,8 @@ void hup_out(t_ctrack *ctrack)
{
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);

View File

@ -4,10 +4,15 @@
#include <stdint.h>
#include <sys/types.h>
#define SPLIT_FLAG_DISORDER 0x01
#define SPLIT_FLAG_OOB 0x02
#define SPLIT_FLAG_DISORDER 0x01
#define SPLIT_FLAG_OOB 0x02
typedef enum {UNKNOWN=0, HTTP, TLS} t_l7proto;
typedef enum
{
UNKNOWN = 0,
HTTP,
TLS
} t_l7proto;
typedef struct
{
// common state
@ -17,8 +22,8 @@ typedef struct
char *hostname;
} t_ctrack;
void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags);
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size);
void tamper_out(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size, size_t *split_pos, uint8_t *split_flags);
void tamper_in(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size);
// connection reset by remote leg
void rst_in(t_ctrack *ctrack);
// local leg closed connection (timeout waiting response ?)

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
#pragma once
#ifdef __linux__
#define SPLICE_PRESENT
#define SPLICE_PRESENT
#endif
#include <sys/param.h>

File diff suppressed because it is too large Load Diff

View File

@ -10,21 +10,22 @@
#define BACKLOG 10
#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 DEFAULT_MAX_CONN 512
#define DEFAULT_MAX_ORPHAN_TIME 5
#define DEFAULT_TCP_USER_TIMEOUT_LOCAL 10
#define DEFAULT_TCP_USER_TIMEOUT_REMOTE 20
#define DEFAULT_MAX_CONN 512
#define DEFAULT_MAX_ORPHAN_TIME 5
#define DEFAULT_TCP_USER_TIMEOUT_LOCAL 10
#define DEFAULT_TCP_USER_TIMEOUT_REMOTE 20
int event_loop(const int *listen_fd, size_t listen_fd_ct);
//Three different states of a connection
enum{
CONN_UNAVAILABLE=0, // connecting
CONN_AVAILABLE, // operational
CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked
CONN_CLOSED // will be deleted soon
// Three different states of a connection
enum
{
CONN_UNAVAILABLE = 0, // connecting
CONN_AVAILABLE, // operational
CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked
CONN_CLOSED // will be deleted soon
};
typedef uint8_t conn_state_t;
@ -34,13 +35,14 @@ typedef uint8_t conn_state_t;
struct send_buffer
{
uint8_t *data;
size_t len,pos;
size_t len, pos;
int ttl, flags;
};
typedef struct send_buffer send_buffer_t;
enum{
CONN_TYPE_TRANSPARENT=0,
enum
{
CONN_TYPE_TRANSPARENT = 0,
CONN_TYPE_SOCKS
};
typedef uint8_t conn_type_t;
@ -48,8 +50,8 @@ typedef uint8_t conn_type_t;
struct tproxy_conn
{
bool listener; // true - listening socket. false = connecion socket
bool remote; // false - accepted, true - connected
int efd; // epoll fd
bool remote; // false - accepted, true - connected
int efd; // epoll fd
int fd;
int splice_pipe[2];
conn_state_t state;
@ -59,8 +61,9 @@ struct tproxy_conn
time_t orphan_since;
// socks5 state machine
enum {
S_WAIT_HANDSHAKE=0,
enum
{
S_WAIT_HANDSHAKE = 0,
S_WAIT_REQUEST,
S_WAIT_RESOLVE,
S_WAIT_CONNECTION,
@ -70,11 +73,11 @@ struct tproxy_conn
struct resolve_item *socks_ri;
// 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
bool bFlowIn,bFlowOut, bShutdown, bFlowInPrev,bFlowOutPrev, bPrevRdhup;
// 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;
// total read,write
uint64_t trd,twr, tnrd;
uint64_t trd, twr, tnrd;
// number of epoll_wait events
unsigned int event_count;
@ -94,14 +97,14 @@ struct tproxy_conn
t_ctrack track;
//Create the struct which contains ptrs to next/prev element
TAILQ_ENTRY(tproxy_conn) conn_ptrs;
// Create the struct which contains ptrs to next/prev element
TAILQ_ENTRY(tproxy_conn)
conn_ptrs;
};
typedef struct tproxy_conn tproxy_conn_t;
//Define the struct tailhead (code in sys/queue.h is quite intuitive)
//Use tail queue for efficient delete
// Define the struct tailhead (code in sys/queue.h is quite intuitive)
// Use tail queue for efficient delete
TAILQ_HEAD(tailhead, tproxy_conn);
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);

File diff suppressed because it is too large Load Diff