mirror of
https://github.com/bol-van/zapret.git
synced 2025-04-30 02:42:58 +03:00
Linting and formatting of .c
and .h
with C/C++ IntelliSence
This commit is contained in:
parent
8c94e3230e
commit
c1db09b19e
183
ip2net/ip2net.c
183
ip2net/ip2net.c
@ -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(¶ms, 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", ¶ms.pctmult, ¶ms.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", ¶ms.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)
|
||||
|
269
ip2net/qsort.c
269
ip2net/qsort.c
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
128
mdig/mdig.c
128
mdig/mdig.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
220
nfq/conntrack.c
220
nfq/conntrack.c
@ -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;
|
||||
}
|
||||
|
@ -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); }
|
||||
|
@ -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);
|
||||
|
494
nfq/crypto/aes.c
494
nfq/crypto/aes.c
@ -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 */
|
||||
|
@ -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
|
||||
|
404
nfq/crypto/gcm.c
404
nfq/crypto/gcm.c
@ -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);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
158
nfq/crypto/gcm.h
158
nfq/crypto/gcm.h
@ -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
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) ||
|
||||
|
@ -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))
|
||||
|
161
nfq/crypto/sha.h
161
nfq/crypto/sha.h
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
1153
nfq/darkmagic.c
1153
nfq/darkmagic.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
1401
nfq/desync.c
1401
nfq/desync.c
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
18
nfq/gzip.c
18
nfq/gzip.c
@ -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;
|
||||
|
@ -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);
|
||||
|
203
nfq/helpers.c
203
nfq/helpers.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
@ -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())
|
||||
|
937
nfq/nfqws.c
937
nfq/nfqws.c
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
|
@ -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);
|
||||
|
58
nfq/params.c
58
nfq/params.c
@ -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;
|
||||
}
|
||||
|
||||
|
49
nfq/params.h
49
nfq/params.h
@ -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;
|
||||
|
72
nfq/pools.c
72
nfq/pools.c
@ -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)
|
||||
|
39
nfq/pools.h
39
nfq/pools.h
@ -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);
|
||||
|
555
nfq/protocol.c
555
nfq/protocol.c
@ -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';
|
||||
}
|
||||
|
@ -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
186
nfq/sec.c
@ -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;
|
||||
|
57
nfq/sec.h
57
nfq/sec.h
@ -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);
|
||||
|
1880
nfq/uthash.h
1880
nfq/uthash.h
File diff suppressed because it is too large
Load Diff
@ -18,8 +18,7 @@ bool service_run(int argc, char *argv[])
|
||||
{
|
||||
SERVICE_TABLE_ENTRY ServiceTable[] = {
|
||||
{SERVICE_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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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, /**/
|
||||
¤t_time) < 0) {
|
||||
¤t_time) < 0)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
timespecsub(deadline, ¤t_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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -7,7 +7,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int kq; // non owning
|
||||
} SignalFDCtx;
|
||||
|
||||
|
@ -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);
|
||||
|
18
tpws/gzip.c
18
tpws/gzip.c
@ -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;
|
||||
|
@ -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);
|
||||
|
159
tpws/helpers.c
159
tpws/helpers.c
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
72
tpws/pools.c
72
tpws/pools.c
@ -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)
|
||||
|
39
tpws/pools.h
39
tpws/pools.h
@ -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);
|
||||
|
242
tpws/protocol.c
242
tpws/protocol.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
139
tpws/redirect.c
139
tpws/redirect.c
@ -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;
|
||||
|
109
tpws/resolver.c
109
tpws/resolver.c
@ -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);
|
||||
|
@ -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);
|
||||
|
167
tpws/sec.c
167
tpws/sec.c
@ -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)
|
||||
|
56
tpws/sec.h
56
tpws/sec.h
@ -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
|
||||
|
||||
|
96
tpws/socks.h
96
tpws/socks.h
@ -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;
|
||||
|
196
tpws/tamper.c
196
tpws/tamper.c
@ -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(¶ms.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(¶ms.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(¶ms.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(¶ms.hostlist_auto_fail_counters);
|
||||
|
||||
|
@ -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 ?)
|
||||
|
673
tpws/tpws.c
673
tpws/tpws.c
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __linux__
|
||||
#define SPLICE_PRESENT
|
||||
#define SPLICE_PRESENT
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
|
1082
tpws/tpws_conn.c
1082
tpws/tpws_conn.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
1880
tpws/uthash.h
1880
tpws/uthash.h
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user