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

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

View File

@ -35,21 +35,21 @@
#define DEFAULT_V4_ZCT_MIN 2 // /30 #define DEFAULT_V4_ZCT_MIN 2 // /30
#define DEFAULT_V6_ZCT_MAX 72 // /56 #define DEFAULT_V6_ZCT_MAX 72 // /56
#define DEFAULT_V6_ZCT_MIN 64 // /64 #define DEFAULT_V6_ZCT_MIN 64 // /64
// must be no less than N ipv6 in subnet // must be no less than N IPv6 in subnet
#define DEFAULT_V6_THRESHOLD 5 #define DEFAULT_V6_THRESHOLD 5
static int ucmp(const void * a, const void * b, void *arg) static int ucmp(const void *a, const void *b, void *arg)
{ {
if (*(uint32_t*)a < *(uint32_t*)b) if (*(uint32_t *)a < *(uint32_t *)b)
return -1; return -1;
else if (*(uint32_t*)a > *(uint32_t*)b) else if (*(uint32_t *)a > *(uint32_t *)b)
return 1; return 1;
else else
return 0; return 0;
} }
static uint32_t mask_from_bitcount(uint32_t zct) 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. // 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) // 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++) for (i = j = 0; j < ct; i++)
{ {
u = pu[j++]; u = pu[j++];
for (; j < ct && pu[j] == u; j++); for (; j < ct && pu[j] == u; j++)
;
pu[i] = u; pu[i] = u;
} }
return i; return i;
} }
#if defined(__GNUC__) && !defined(__llvm__) #if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing"))) __attribute__((optimize("no-strict-aliasing")))
#endif #endif
static int cmp6(const void * a, const void * b, void *arg) static int
cmp6(const void *a, const void *b, void *arg)
{ {
// this function is critical for sort performance // this function is critical for sort performance
// on big endian systems cpu byte order is equal to network byte order // on big endian systems cpu byte order is equal to network byte order
@ -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 // 64-bit archs often have cpu command to reverse byte order
// assume that a and b are properly aligned // 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; uint64_t aa, bb;
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
aa = __builtin_bswap64(((uint64_t*)((struct in6_addr *)a)->s6_addr)[0]); aa = __builtin_bswap64(((uint64_t *)((struct in6_addr *)a)->s6_addr)[0]);
bb = __builtin_bswap64(((uint64_t*)((struct in6_addr *)b)->s6_addr)[0]); bb = __builtin_bswap64(((uint64_t *)((struct in6_addr *)b)->s6_addr)[0]);
#else #else
aa = ((uint64_t*)((struct in6_addr *)a)->s6_addr)[0]; aa = ((uint64_t *)((struct in6_addr *)a)->s6_addr)[0];
bb = ((uint64_t*)((struct in6_addr *)b)->s6_addr)[0]; bb = ((uint64_t *)((struct in6_addr *)b)->s6_addr)[0];
#endif #endif
if (aa < bb) if (aa < bb)
return -1; return -1;
@ -95,14 +95,15 @@ static int cmp6(const void * a, const void * b, void *arg)
return 1; return 1;
else else
{ {
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
aa = __builtin_bswap64(((uint64_t*)((struct in6_addr *)a)->s6_addr)[1]); aa = __builtin_bswap64(((uint64_t *)((struct in6_addr *)a)->s6_addr)[1]);
bb = __builtin_bswap64(((uint64_t*)((struct in6_addr *)b)->s6_addr)[1]); bb = __builtin_bswap64(((uint64_t *)((struct in6_addr *)b)->s6_addr)[1]);
#else #else
aa = ((uint64_t*)((struct in6_addr *)a)->s6_addr)[1]; aa = ((uint64_t *)((struct in6_addr *)a)->s6_addr)[1];
bb = ((uint64_t*)((struct in6_addr *)b)->s6_addr)[1]; bb = ((uint64_t *)((struct in6_addr *)b)->s6_addr)[1];
#endif #endif
return aa < bb ? -1 : aa > bb ? 1 : 0; return aa < bb ? -1 : aa > bb ? 1
: 0;
} }
#else #else
@ -124,7 +125,8 @@ static uint32_t unique6(struct in6_addr *pu, uint32_t ct)
uint32_t i, j, k; uint32_t i, j, k;
for (i = j = 0; j < ct; i++) for (i = j = 0; j < ct; i++)
{ {
for (k = j++; j < ct && !memcmp(pu + j, pu + k, sizeof(struct in6_addr)); j++); for (k = j++; j < ct && !memcmp(pu + j, pu + k, sizeof(struct in6_addr)); j++)
;
pu[i] = pu[k]; pu[i] = pu[k];
} }
return i; return i;
@ -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) static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a)
{ {
if (zct >= 128) if (zct >= 128)
memset(a->s6_addr,0x00,16); memset(a->s6_addr, 0x00, 16);
else else
{ {
int32_t n = (127 - zct) >> 3; int32_t n = (127 - zct) >> 3;
memset(a->s6_addr,0xFF,n); memset(a->s6_addr, 0xFF, n);
memset(a->s6_addr+n,0x00,16-n); memset(a->s6_addr + n, 0x00, 16 - n);
a->s6_addr[n] = ~((1 << (zct & 7)) - 1); a->s6_addr[n] = ~((1 << (zct & 7)) - 1);
} }
} }
static struct in6_addr ip6_mask[129]; static struct in6_addr ip6_mask[129];
static void mask_from_bitcount6_prepare(void) static void mask_from_bitcount6_prepare(void)
{ {
for (int zct=0;zct<=128;zct++) mask_from_bitcount6_make(zct, ip6_mask+zct); for (int zct = 0; zct <= 128; zct++)
mask_from_bitcount6_make(zct, ip6_mask + zct);
} }
static inline const struct in6_addr *mask_from_bitcount6(uint32_t zct) static inline const struct in6_addr *mask_from_bitcount6(uint32_t zct)
{ {
return ip6_mask+zct; return ip6_mask + zct;
} }
/* /*
// this is "correct" solution for strict aliasing feature // this is "correct" solution for strict aliasing feature
// but I don't like this style of coding // but I don't like this style of coding
@ -176,26 +178,27 @@ static void ip6_and(const struct in6_addr *a, const struct in6_addr *b, struct i
// result = a & b // result = a & b
// assume that a and b are properly aligned // assume that a and b are properly aligned
#if defined(__GNUC__) && !defined(__llvm__) #if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing"))) __attribute__((optimize("no-strict-aliasing")))
#endif #endif
static void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result) static void
ip6_and(const struct in6_addr *restrict a, const struct in6_addr *restrict b, struct in6_addr *restrict result)
{ {
#ifdef __SIZEOF_INT128__ #ifdef __SIZEOF_INT128__
// gcc and clang have 128 bit int types on some 64-bit archs. take some advantage // gcc and clang have 128 bit int types on some 64-bit archs. take some advantage
*((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 #else
((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0]; ((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)[1] = ((uint64_t *)a->s6_addr)[1] & ((uint64_t *)b->s6_addr)[1];
#endif #endif
} }
static void rtrim(char *s) static void rtrim(char *s)
{ {
if (s) if (s)
for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0'; for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--)
*p = '\0';
} }
static struct params_s static struct params_s
{ {
bool ipv6; bool ipv6;
@ -204,16 +207,14 @@ static struct params_s
uint32_t v6_threshold; // for v6 uint32_t v6_threshold; // for v6
} params; } params;
static void exithelp(void) static void exithelp(void)
{ {
printf( printf(
" -4\t\t\t\t; ipv4 list (default)\n" " -4\t\t\t\t; IPv4 list (default)\n"
" -6\t\t\t\t; ipv6 list\n" " -6\t\t\t\t; IPv6 list\n"
" --prefix-length=min[-max]\t; consider prefix lengths from 'min' to 'max'. examples : 22-30 (ipv4), 56-64 (ipv6)\n" " --prefix-length=min[-max]\t; consider prefix lengths from 'min' to 'max'. examples : 22-30 (IPv4), 56-64 (IPv6)\n"
" --v4-threshold=mul/div\t\t; ipv4 only : include subnets with more than mul/div ips. example : 3/4\n" " --v4-threshold=mul/div\t\t; IPv4 only : include subnets with more than mul/div ips. example : 3/4\n"
" --v6-threshold=N\t\t; ipv6 only : include subnets with more than N v6 ips. example : 5\n" " --v6-threshold=N\t\t; IPv6 only : include subnets with more than N v6 ips. example : 5\n");
);
exit(1); exit(1);
} }
@ -221,7 +222,7 @@ static void parse_params(int argc, char *argv[])
{ {
int option_index = 0; int option_index = 0;
int v, i; int v, i;
uint32_t plen1=-1, plen2=-1; uint32_t plen1 = -1, plen2 = -1;
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
params.pctmult = DEFAULT_PCTMULT; params.pctmult = DEFAULT_PCTMULT;
@ -229,18 +230,18 @@ static void parse_params(int argc, char *argv[])
params.v6_threshold = DEFAULT_V6_THRESHOLD; params.v6_threshold = DEFAULT_V6_THRESHOLD;
const struct option long_options[] = { const struct option long_options[] = {
{ "help",no_argument,0,0 },// optidx=0 {"help", no_argument, 0, 0}, // optidx=0
{ "h",no_argument,0,0 },// optidx=1 {"h", no_argument, 0, 0}, // optidx=1
{ "4",no_argument,0,0 },// optidx=2 {"4", no_argument, 0, 0}, // optidx=2
{ "6",no_argument,0,0 },// optidx=3 {"6", no_argument, 0, 0}, // optidx=3
{ "prefix-length",required_argument,0,0 },// optidx=4 {"prefix-length", required_argument, 0, 0}, // optidx=4
{ "v4-threshold",required_argument,0,0 },// optidx=5 {"v4-threshold", required_argument, 0, 0}, // optidx=5
{ "v6-threshold",required_argument,0,0 },// optidx=6 {"v6-threshold", required_argument, 0, 0}, // optidx=6
{ NULL,0,NULL,0 } {NULL, 0, NULL, 0}};
};
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{ {
if (v) exithelp(); if (v)
exithelp();
switch (option_index) switch (option_index)
{ {
case 0: case 0:
@ -254,9 +255,10 @@ static void parse_params(int argc, char *argv[])
params.ipv6 = true; params.ipv6 = true;
break; break;
case 4: case 4:
i = sscanf(optarg,"%u-%u",&plen1,&plen2); i = sscanf(optarg, "%u-%u", &plen1, &plen2);
if (i == 1) plen2 = plen1; if (i == 1)
if (i<=0 || plen2<plen1 || !plen1 || !plen2) plen2 = plen1;
if (i <= 0 || plen2 < plen1 || !plen1 || !plen2)
{ {
fprintf(stderr, "invalid parameter for prefix-length : %s\n", optarg); fprintf(stderr, "invalid parameter for prefix-length : %s\n", optarg);
exit(1); exit(1);
@ -264,7 +266,7 @@ static void parse_params(int argc, char *argv[])
break; break;
case 5: case 5:
i = sscanf(optarg, "%u/%u", &params.pctmult, &params.pctdiv); i = sscanf(optarg, "%u/%u", &params.pctmult, &params.pctdiv);
if (i!=2 || params.pctdiv<2 || params.pctmult<1 || params.pctmult>=params.pctdiv) if (i != 2 || params.pctdiv < 2 || params.pctmult < 1 || params.pctmult >= params.pctdiv)
{ {
fprintf(stderr, "invalid parameter for v4-threshold : %s\n", optarg); fprintf(stderr, "invalid parameter for v4-threshold : %s\n", optarg);
exit(1); exit(1);
@ -272,7 +274,7 @@ static void parse_params(int argc, char *argv[])
break; break;
case 6: case 6:
i = sscanf(optarg, "%u", &params.v6_threshold); i = sscanf(optarg, "%u", &params.v6_threshold);
if (i != 1 || params.v6_threshold<1) if (i != 1 || params.v6_threshold < 1)
{ {
fprintf(stderr, "invalid parameter for v6-threshold : %s\n", optarg); fprintf(stderr, "invalid parameter for v6-threshold : %s\n", optarg);
exit(1); exit(1);
@ -280,19 +282,20 @@ static void parse_params(int argc, char *argv[])
break; 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"); fprintf(stderr, "invalid parameter for prefix-length\n");
exit(1); exit(1);
} }
params.zct_min = params.ipv6 ? plen2==-1 ? DEFAULT_V6_ZCT_MIN : 128-plen2 : plen2==-1 ? DEFAULT_V4_ZCT_MIN : 32-plen2; params.zct_min = params.ipv6 ? plen2 == -1 ? DEFAULT_V6_ZCT_MIN : 128 - plen2 : plen2 == -1 ? DEFAULT_V4_ZCT_MIN
params.zct_max = params.ipv6 ? plen1==-1 ? DEFAULT_V6_ZCT_MAX : 128-plen1 : plen1==-1 ? DEFAULT_V4_ZCT_MAX : 32-plen1; : 32 - plen2;
params.zct_max = params.ipv6 ? plen1 == -1 ? DEFAULT_V6_ZCT_MAX : 128 - plen1 : plen1 == -1 ? DEFAULT_V4_ZCT_MAX
: 32 - plen1;
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char str[256],d; char str[256], d;
uint32_t ipct = 0, iplist_size = 0, pos = 0, p, zct, ip_ct, pos_end; uint32_t ipct = 0, iplist_size = 0, pos = 0, p, zct, ip_ct, pos_end;
parse_params(argc, argv); parse_params(argc, argv);
@ -313,25 +316,27 @@ int main(int argc, char **argv)
} }
if (inet_pton(AF_INET6, str, &a)) if (inet_pton(AF_INET6, str, &a))
{ {
if (d=='/') if (d == '/')
{ {
// we have subnet ip6/y // we have subnet ip6/y
// output it as is // output it as is
if (sscanf(s + 1, "%u", &zct)==1 && zct!=128) if (sscanf(s + 1, "%u", &zct) == 1 && zct != 128)
{ {
if (zct<128) printf("%s/%u\n", str, zct); if (zct < 128)
printf("%s/%u\n", str, zct);
continue; continue;
} }
} }
else if (d=='-') else if (d == '-')
{ {
if (inet_pton(AF_INET6, s+1, &a)) printf("%s-%s\n", str, s+1); if (inet_pton(AF_INET6, s + 1, &a))
printf("%s-%s\n", str, s + 1);
continue; continue;
} }
if (ipct >= iplist_size) if (ipct >= iplist_size)
{ {
iplist_size += ALLOC_STEP; 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) if (!iplist_new)
{ {
free(iplist); free(iplist);
@ -371,7 +376,8 @@ int main(int argc, char **argv)
if (memcmp(&ip_start, &ip, sizeof(ip))) if (memcmp(&ip_start, &ip, sizeof(ip)))
break; break;
} }
if (ip_ct == 1) break; if (ip_ct == 1)
break;
if (ip_ct >= params.v6_threshold) if (ip_ct >= params.v6_threshold)
{ {
// network found. but is there smaller network with the same ip_ct ? dont do carpet bombing if possible, use smaller subnets // network found. but is there smaller network with the same ip_ct ? dont do carpet bombing if possible, use smaller subnets
@ -400,7 +406,7 @@ int main(int argc, char **argv)
} }
else // ipv4 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; uint32_t *iplist = NULL, *iplist_new, i;
while (fgets(str, sizeof(str), stdin)) while (fgets(str, sizeof(str), stdin))
@ -411,8 +417,7 @@ int main(int argc, char **argv)
{ {
printf("%u.%u.%u.%u-%u.%u.%u.%u\n", u1, u2, u3, u4, u11, u22, u33, u44); printf("%u.%u.%u.%u-%u.%u.%u.%u\n", u1, u2, u3, u4, u11, u22, u33, u44);
} }
else else if ((i = sscanf(str, "%u.%u.%u.%u/%u", &u1, &u2, &u3, &u4, &zct)) >= 4 &&
if ((i = sscanf(str, "%u.%u.%u.%u/%u", &u1, &u2, &u3, &u4, &zct)) >= 4 &&
!(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00)) !(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00))
{ {
if (i == 5 && zct != 32) if (i == 5 && zct != 32)
@ -428,7 +433,7 @@ int main(int argc, char **argv)
if (ipct >= iplist_size) if (ipct >= iplist_size)
{ {
iplist_size += ALLOC_STEP; 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) if (!iplist_new)
{ {
free(iplist); free(iplist);
@ -456,12 +461,14 @@ int main(int argc, char **argv)
mask = mask_from_bitcount(zct); mask = mask_from_bitcount(zct);
ip_start = iplist[pos] & mask; ip_start = iplist[pos] & mask;
subnet_ct = ~mask + 1; 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 continue; // ip is higher than (1-PCT). definitely coverage is not enough. skip searching
ip_end = ip_start | ~mask; ip_end = ip_start | ~mask;
for (p=pos+1, ip_ct=1; p < ipct && iplist[p] <= ip_end; p++) ip_ct++; // count ips within subnet range for (p = pos + 1, ip_ct = 1; p < ipct && iplist[p] <= ip_end; p++)
if (ip_ct == 1) break; ip_ct++; // count ips within subnet range
if (ip_ct >= (subnet_ct*params.pctmult / params.pctdiv)) 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 // 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) if (!ip_ct_best || ip_ct == ip_ct_best)

View File

@ -20,10 +20,10 @@
Engineering a sort function; Jon Bentley and M. Douglas McIlroy; Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */ Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
//#include <alloca.h> // #include <alloca.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
//#include <string.h> // #include <string.h>
#include "qsort.h" #include "qsort.h"
/* Byte-wise swap two items of size SIZE. */ /* Byte-wise swap two items of size SIZE. */
@ -46,10 +46,10 @@
/* Stack node declarations used to store unfulfilled partition obligations. */ /* Stack node declarations used to store unfulfilled partition obligations. */
typedef struct typedef struct
{ {
char *lo; char *lo;
char *hi; char *hi;
} stack_node; } stack_node;
/* The next 4 #defines implement a very fast in-line stack abstraction. */ /* The next 4 #defines implement a very fast in-line stack abstraction. */
/* The stack needs log (total_elements) entries (we could even subtract /* The stack needs log (total_elements) entries (we could even subtract
@ -57,11 +57,10 @@ typedef struct
upper bound for log (total_elements): upper bound for log (total_elements):
bits per byte (CHAR_BIT) * sizeof(size_t). */ bits per byte (CHAR_BIT) * sizeof(size_t). */
#define STACK_SIZE (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 PUSH(low, high) ((void)((top->lo = (low)), (top->hi = (high)), ++top))
#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) #define POP(low, high) ((void)(--top, (low = top->lo), (high = top->hi)))
#define STACK_NOT_EMPTY (stack < top) #define STACK_NOT_EMPTY (stack < top)
/* Order size using quicksort. This implementation incorporates /* Order size using quicksort. This implementation incorporates
four optimizations discussed in Sedgewick: four optimizations discussed in Sedgewick:
@ -86,11 +85,10 @@ typedef struct
smaller partition. This *guarantees* no more than log (total_elems) smaller partition. This *guarantees* no more than log (total_elems)
stack size is needed (actually O(1) in this case)! */ stack size is needed (actually O(1) in this case)! */
void void gnu_quicksort(void *const pbase, size_t total_elems, size_t size,
gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
__gnu_compar_d_fn_t cmp, void *arg) __gnu_compar_d_fn_t cmp, void *arg)
{ {
char *base_ptr = (char *) pbase; char *base_ptr = (char *)pbase;
const size_t max_thresh = MAX_THRESH * size; const size_t max_thresh = MAX_THRESH * size;
@ -105,7 +103,7 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
stack_node stack[STACK_SIZE]; stack_node stack[STACK_SIZE];
stack_node *top = stack; stack_node *top = stack;
PUSH (NULL, NULL); PUSH(NULL, NULL);
while (STACK_NOT_EMPTY) while (STACK_NOT_EMPTY)
{ {
@ -120,14 +118,14 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
char *mid = lo + size * ((hi - lo) / size >> 1); char *mid = lo + size * ((hi - lo) / size >> 1);
if ((*cmp) ((void *) mid, (void *) lo, arg) < 0) if ((*cmp)((void *)mid, (void *)lo, arg) < 0)
SWAP (mid, lo, size); SWAP(mid, lo, size);
if ((*cmp) ((void *) hi, (void *) mid, arg) < 0) if ((*cmp)((void *)hi, (void *)mid, arg) < 0)
SWAP (mid, hi, size); SWAP(mid, hi, size);
else else
goto jump_over; goto jump_over;
if ((*cmp) ((void *) mid, (void *) lo, arg) < 0) if ((*cmp)((void *)mid, (void *)lo, arg) < 0)
SWAP (mid, lo, size); SWAP(mid, lo, size);
jump_over:; jump_over:;
left_ptr = lo + size; left_ptr = lo + size;
@ -138,15 +136,15 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
that this algorithm runs much faster than others. */ that this algorithm runs much faster than others. */
do do
{ {
while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0) while ((*cmp)((void *)left_ptr, (void *)mid, arg) < 0)
left_ptr += size; left_ptr += size;
while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0) while ((*cmp)((void *)mid, (void *)right_ptr, arg) < 0)
right_ptr -= size; right_ptr -= size;
if (left_ptr < right_ptr) if (left_ptr < right_ptr)
{ {
SWAP (left_ptr, right_ptr, size); SWAP(left_ptr, right_ptr, size);
if (mid == left_ptr) if (mid == left_ptr)
mid = right_ptr; mid = right_ptr;
else if (mid == right_ptr) else if (mid == right_ptr)
@ -160,36 +158,35 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
right_ptr -= size; right_ptr -= size;
break; break;
} }
} } while (left_ptr <= right_ptr);
while (left_ptr <= right_ptr);
/* Set up pointers for next iteration. First determine whether /* Set up pointers for next iteration. First determine whether
left and right partitions are below the threshold size. If so, left and right partitions are below the threshold size. If so,
ignore one or both. Otherwise, push the larger partition's ignore one or both. Otherwise, push the larger partition's
bounds on the stack and continue sorting the smaller one. */ bounds on the stack and continue sorting the smaller one. */
if ((size_t) (right_ptr - lo) <= max_thresh) if ((size_t)(right_ptr - lo) <= max_thresh)
{ {
if ((size_t) (hi - left_ptr) <= max_thresh) if ((size_t)(hi - left_ptr) <= max_thresh)
/* Ignore both small partitions. */ /* Ignore both small partitions. */
POP (lo, hi); POP(lo, hi);
else else
/* Ignore small left partition. */ /* Ignore small left partition. */
lo = left_ptr; lo = left_ptr;
} }
else if ((size_t) (hi - left_ptr) <= max_thresh) else if ((size_t)(hi - left_ptr) <= max_thresh)
/* Ignore small right partition. */ /* Ignore small right partition. */
hi = right_ptr; hi = right_ptr;
else if ((right_ptr - lo) > (hi - left_ptr)) else if ((right_ptr - lo) > (hi - left_ptr))
{ {
/* Push larger left partition indices. */ /* Push larger left partition indices. */
PUSH (lo, right_ptr); PUSH(lo, right_ptr);
lo = left_ptr; lo = left_ptr;
} }
else else
{ {
/* Push larger right partition indices. */ /* Push larger right partition indices. */
PUSH (left_ptr, hi); PUSH(left_ptr, hi);
hi = right_ptr; hi = right_ptr;
} }
} }
@ -214,11 +211,11 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
and the operation speeds up insertion sort's inner loop. */ and the operation speeds up insertion sort's inner loop. */
for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) 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; tmp_ptr = run_ptr;
if (tmp_ptr != base_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. */ /* Insertion sort, running from left-hand-side up to right-hand-side. */
@ -226,7 +223,7 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
while ((run_ptr += size) <= end_ptr) while ((run_ptr += size) <= end_ptr)
{ {
tmp_ptr = run_ptr - size; tmp_ptr = run_ptr - size;
while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0) while ((*cmp)((void *)run_ptr, (void *)tmp_ptr, arg) < 0)
tmp_ptr -= size; tmp_ptr -= size;
tmp_ptr += size; tmp_ptr += size;

View File

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

View File

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

View File

@ -2,32 +2,33 @@
#include "checksum.h" #include "checksum.h"
#include <netinet/in.h> #include <netinet/in.h>
//#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((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)) // #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
static uint16_t from64to16(uint64_t x) 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); 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); return (uint16_t)u + (uint16_t)(u >> 16);
} }
// this function preserves data alignment requirements (otherwise it will be damn slow on mips arch) // this function preserves data alignment requirements (otherwise it will be damn slow on mips arch)
// and uses 64-bit arithmetics to improve speed // and uses 64-bit arithmetics to improve speed
// taken from linux source code // taken from Linux source code
static uint16_t do_csum(const uint8_t * buff, size_t len) static uint16_t do_csum(const uint8_t *buff, size_t len)
{ {
uint8_t odd; uint8_t odd;
size_t count; size_t count;
uint64_t result,w,carry=0; uint64_t result, w, carry = 0;
uint16_t u16; uint16_t u16;
if (!len) return 0; if (!len)
return 0;
odd = (uint8_t)(1 & (size_t)buff); odd = (uint8_t)(1 & (size_t)buff);
if (odd) if (odd)
{ {
// any endian compatible // any endian compatible
u16 = 0; u16 = 0;
*((uint8_t*)&u16+1) = *buff; *((uint8_t *)&u16 + 1) = *buff;
result = u16; result = u16;
len--; len--;
buff++; buff++;
@ -37,9 +38,9 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
count = len >> 1; /* nr of 16-bit words.. */ count = len >> 1; /* nr of 16-bit words.. */
if (count) if (count)
{ {
if (2 & (size_t) buff) if (2 & (size_t)buff)
{ {
result += *(uint16_t *) buff; result += *(uint16_t *)buff;
count--; count--;
len -= 2; len -= 2;
buff += 2; buff += 2;
@ -47,9 +48,9 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
count >>= 1; /* nr of 32-bit words.. */ count >>= 1; /* nr of 32-bit words.. */
if (count) if (count)
{ {
if (4 & (size_t) buff) if (4 & (size_t)buff)
{ {
result += *(uint32_t *) buff; result += *(uint32_t *)buff;
count--; count--;
len -= 4; len -= 4;
buff += 4; buff += 4;
@ -59,7 +60,7 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
{ {
do do
{ {
w = *(uint64_t *) buff; w = *(uint64_t *)buff;
count--; count--;
buff += 8; buff += 8;
result += carry; result += carry;
@ -71,13 +72,13 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
} }
if (len & 4) if (len & 4)
{ {
result += *(uint32_t *) buff; result += *(uint32_t *)buff;
buff += 4; buff += 4;
} }
} }
if (len & 2) if (len & 2)
{ {
result += *(uint16_t *) buff; result += *(uint16_t *)buff;
buff += 2; buff += 2;
} }
} }
@ -85,54 +86,54 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
{ {
// any endian compatible // any endian compatible
u16 = 0; u16 = 0;
*(uint8_t*)&u16 = *buff; *(uint8_t *)&u16 = *buff;
result += u16; result += u16;
} }
u16 = from64to16(result); u16 = from64to16(result);
if (odd) u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8); if (odd)
u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8);
return u16; return u16;
} }
uint16_t csum_partial(const void *buff, size_t len) 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) 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) 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) void ip4_fix_checksum(struct ip *ip)
{ {
ip->ip_sum = 0; 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) 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) + 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 *)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); *(uint32_t *)daddr + *((uint32_t *)daddr + 1) + *((uint32_t *)daddr + 2) + *((uint32_t *)daddr + 3);
return ~from64to16(a); return ~from64to16(a);
} }
void tcp4_fix_checksum(struct tcphdr *tcp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
void tcp4_fix_checksum(struct tcphdr *tcp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
{ {
tcp->th_sum = 0; tcp->th_sum = 0;
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 = 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) if (ip)
tcp4_fix_checksum(tcp, len, &ip->ip_src, &ip->ip_dst); 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); 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 = 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 = 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) if (ip)
udp4_fix_checksum(udp, len, &ip->ip_src, &ip->ip_dst); udp4_fix_checksum(udp, len, &ip->ip_src, &ip->ip_dst);

View File

@ -18,10 +18,10 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8
uint16_t ip4_compute_csum(const void *buff, size_t len); uint16_t ip4_compute_csum(const void *buff, size_t len);
void ip4_fix_checksum(struct ip *ip); 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 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 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 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 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 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 udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr);

View File

@ -12,11 +12,11 @@ static void ut_oom_recover(void *elem)
oom = true; 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) 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->l3proto = c->l3proto;
c2->l4proto = c->l4proto; c2->l4proto = c->l4proto;
c2->src = c->dst; c2->src = c->dst;
@ -49,7 +49,11 @@ static void ConntrackFreeElem(t_conntrack_pool *elem)
static void ConntrackPoolDestroyPool(t_conntrack_pool **pp) static void ConntrackPoolDestroyPool(t_conntrack_pool **pp)
{ {
t_conntrack_pool *elem, *tmp; t_conntrack_pool *elem, *tmp;
HASH_ITER(hh, *pp, elem, tmp) { HASH_DEL(*pp, elem); ConntrackFreeElem(elem); } HASH_ITER(hh, *pp, elem, tmp)
{
HASH_DEL(*pp, elem);
ConntrackFreeElem(elem);
}
} }
void ConntrackPoolDestroy(t_conntrack *p) void ConntrackPoolDestroy(t_conntrack *p)
{ {
@ -61,7 +65,7 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s
p->timeout_syn = timeout_syn; p->timeout_syn = timeout_syn;
p->timeout_established = timeout_established; p->timeout_established = timeout_established;
p->timeout_fin = timeout_fin; p->timeout_fin = timeout_fin;
p->timeout_udp= timeout_udp; p->timeout_udp = timeout_udp;
p->t_purge_interval = purge_interval; p->t_purge_interval = purge_interval;
time(&p->t_last_purge); time(&p->t_last_purge);
p->pool = NULL; 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) 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) if (ip)
{ {
c->l3proto = IPPROTO_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); extract_ports(tcphdr, udphdr, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport);
} }
static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *c) static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *c)
{ {
t_conntrack_pool *t; t_conntrack_pool *t;
@ -97,7 +100,7 @@ static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *
static void ConntrackInitTrack(t_ctrack *t) static void ConntrackInitTrack(t_ctrack *t)
{ {
memset(t,0,sizeof(*t)); memset(t, 0, sizeof(*t));
t->scale_orig = t->scale_reply = SCALE_NONE; t->scale_orig = t->scale_reply = SCALE_NONE;
time(&t->t_start); time(&t->t_start);
rawpacket_queue_init(&t->delayed); 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) static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c)
{ {
t_conntrack_pool *ctnew; t_conntrack_pool *ctnew;
if (!(ctnew = malloc(sizeof(*ctnew)))) return NULL; if (!(ctnew = malloc(sizeof(*ctnew))))
return NULL;
ctnew->conn = *c; ctnew->conn = *c;
oom = false; oom = false;
HASH_ADD(hh, *pp, conn, sizeof(*c), ctnew); HASH_ADD(hh, *pp, conn, sizeof(*c), ctnew);
if (oom) { free(ctnew); return NULL; } if (oom)
{
free(ctnew);
return NULL;
}
ConntrackInitTrack(&ctnew->track); ConntrackInitTrack(&ctnew->track);
return ctnew; return ctnew;
} }
@ -128,38 +136,41 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (bReverse) if (bReverse)
{ {
t->pcounter_reply++; t->pcounter_reply++;
t->pdcounter_reply+=!!len_payload; t->pdcounter_reply += !!len_payload;
} }
else else
{ {
t->pcounter_orig++; t->pcounter_orig++;
t->pdcounter_orig+=!!len_payload; t->pdcounter_orig += !!len_payload;
} }
if (tcphdr) if (tcphdr)
{ {
if (tcp_syn_segment(tcphdr)) if (tcp_syn_segment(tcphdr))
{ {
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry if (t->state != SYN)
ConntrackReInitTrack(t); // erase current entry
t->seq0 = ntohl(tcphdr->th_seq); t->seq0 = ntohl(tcphdr->th_seq);
} }
else if (tcp_synack_segment(tcphdr)) else if (tcp_synack_segment(tcphdr))
{ {
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry if (t->state != SYN)
if (!t->seq0) t->seq0 = ntohl(tcphdr->th_ack)-1; ConntrackReInitTrack(t); // erase current entry
if (!t->seq0)
t->seq0 = ntohl(tcphdr->th_ack) - 1;
t->ack0 = ntohl(tcphdr->th_seq); t->ack0 = ntohl(tcphdr->th_seq);
} }
else if (tcphdr->th_flags & (TH_FIN|TH_RST)) else if (tcphdr->th_flags & (TH_FIN | TH_RST))
{ {
t->state = FIN; t->state = FIN;
} }
else else
{ {
if (t->state==SYN) if (t->state == SYN)
{ {
t->state=ESTABLISHED; t->state = ESTABLISHED;
if (!bReverse && !t->ack0) t->ack0 = ntohl(tcphdr->th_ack)-1; if (!bReverse && !t->ack0)
t->ack0 = ntohl(tcphdr->th_ack) - 1;
} }
} }
scale = tcp_find_scale_factor(tcphdr); scale = tcp_find_scale_factor(tcphdr);
@ -169,8 +180,8 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
t->ack_last = ntohl(tcphdr->th_seq); t->ack_last = ntohl(tcphdr->th_seq);
t->pos_reply = t->ack_last + len_payload; t->pos_reply = t->ack_last + len_payload;
t->winsize_reply = ntohs(tcphdr->th_win); t->winsize_reply = ntohs(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_reply = scale; if (scale != SCALE_NONE)
t->scale_reply = scale;
} }
else else
{ {
@ -178,20 +189,21 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
t->pos_orig = t->seq_last + len_payload; t->pos_orig = t->seq_last + len_payload;
t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack); t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack);
t->winsize_orig = ntohs(tcphdr->th_win); t->winsize_orig = ntohs(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_orig = scale; if (scale != SCALE_NONE)
t->scale_orig = scale;
} }
} }
else else
{ {
if (bReverse) if (bReverse)
{ {
t->ack_last=t->pos_reply; t->ack_last = t->pos_reply;
t->pos_reply+=len_payload; t->pos_reply += len_payload;
} }
else else
{ {
t->seq_last=t->pos_orig; t->seq_last = t->pos_orig;
t->pos_orig+=len_payload; 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) 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; t_conntrack_pool *ctr;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr); ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
if ((ctr=ConntrackPoolSearch(*pp,&conn))) if ((ctr = ConntrackPoolSearch(*pp, &conn)))
{ {
if (bReverse) *bReverse = false; if (bReverse)
if (ctrack) *ctrack = &ctr->track; *bReverse = false;
if (ctrack)
*ctrack = &ctr->track;
return true; return true;
} }
else else
{ {
connswap(&conn,&connswp); connswap(&conn, &connswp);
if ((ctr=ConntrackPoolSearch(*pp,&connswp))) if ((ctr = ConntrackPoolSearch(*pp, &connswp)))
{ {
if (bReverse) *bReverse = true; if (bReverse)
if (ctrack) *ctrack = &ctr->track; *bReverse = true;
if (ctrack)
*ctrack = &ctr->track;
return true; return true;
} }
} }
@ -233,25 +249,25 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co
t_conntrack_pool *ctr; t_conntrack_pool *ctr;
bool b_rev; bool b_rev;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr); ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
if ((ctr=ConntrackPoolSearch(*pp,&conn))) 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; goto ok;
} }
else else
{ {
connswap(&conn,&connswp); connswap(&conn, &connswp);
if ((ctr=ConntrackPoolSearch(*pp,&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; goto ok;
} }
} }
b_rev = tcphdr && tcp_synack_segment(tcphdr); b_rev = tcphdr && tcp_synack_segment(tcphdr);
if ((tcphdr && tcp_syn_segment(tcphdr)) || b_rev || udphdr) 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); ConntrackFeedPacket(&ctr->track, b_rev, tcphdr, len_payload);
goto ok; goto ok;
@ -259,32 +275,36 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co
} }
return false; return false;
ok: ok:
if (ctrack) *ctrack = &ctr->track; if (ctrack)
if (bReverse) *bReverse = b_rev; *ctrack = &ctr->track;
if (bReverse)
*bReverse = b_rev;
return true; return true;
} }
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse) bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse)
{ {
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) 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_conn conn, connswp;
t_conntrack_pool *t; t_conntrack_pool *t;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr); ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
if (!(t=ConntrackPoolSearch(*pp,&conn))) if (!(t = ConntrackPoolSearch(*pp, &conn)))
{ {
connswap(&conn,&connswp); connswap(&conn, &connswp);
t=ConntrackPoolSearch(*pp,&connswp); t = ConntrackPoolSearch(*pp, &connswp);
} }
if (!t) return false; if (!t)
HASH_DEL(*pp, t); ConntrackFreeElem(t); return false;
HASH_DEL(*pp, t);
ConntrackFreeElem(t);
return true; return true;
} }
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr) bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{ {
return ConntrackPoolDropPool(&p->pool,ip,ip6,tcphdr,udphdr); return ConntrackPoolDropPool(&p->pool, ip, ip6, tcphdr, udphdr);
} }
void ConntrackPoolPurge(t_conntrack *p) void ConntrackPoolPurge(t_conntrack *p)
@ -292,19 +312,19 @@ void ConntrackPoolPurge(t_conntrack *p)
time_t tidle, tnow = time(NULL); time_t tidle, tnow = time(NULL);
t_conntrack_pool *t, *tmp; 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; tidle = tnow - t->track.t_last;
if ( t->track.b_cutoff || if (t->track.b_cutoff ||
(t->conn.l4proto==IPPROTO_TCP && ( (t->conn.l4proto == IPPROTO_TCP && ((t->track.state == SYN && tidle >= p->timeout_syn) ||
(t->track.state==SYN && tidle>=p->timeout_syn) || (t->track.state == ESTABLISHED && tidle >= p->timeout_established) ||
(t->track.state==ESTABLISHED && tidle>=p->timeout_established) || (t->track.state == FIN && tidle >= p->timeout_fin))) ||
(t->track.state==FIN && tidle>=p->timeout_fin)) (t->conn.l4proto == IPPROTO_UDP && tidle >= p->timeout_udp))
) || (t->conn.l4proto==IPPROTO_UDP && tidle>=p->timeout_udp)
)
{ {
HASH_DEL(p->pool, t); ConntrackFreeElem(t); HASH_DEL(p->pool, t);
ConntrackFreeElem(t);
} }
} }
p->t_last_purge = tnow; p->t_last_purge = tnow;
@ -313,42 +333,50 @@ void ConntrackPoolPurge(t_conntrack *p)
static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsize) static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsize)
{ {
if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize) *buf=0; if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize)
*buf = 0;
} }
static const char *ConntrackProtoName(t_l7proto proto) static const char *ConntrackProtoName(t_l7proto proto)
{ {
switch(proto) switch (proto)
{ {
case HTTP: return "HTTP"; case HTTP:
case TLS: return "TLS"; return "HTTP";
case QUIC: return "QUIC"; case TLS:
case WIREGUARD: return "WIREGUARD"; return "TLS";
case DHT: return "DHT"; case QUIC:
default: return "UNKNOWN"; return "QUIC";
case WIREGUARD:
return "WIREGUARD";
case DHT:
return "DHT";
default:
return "UNKNOWN";
} }
} }
void ConntrackPoolDump(const t_conntrack *p) void ConntrackPoolDump(const t_conntrack *p)
{ {
t_conntrack_pool *t, *tmp; t_conntrack_pool *t, *tmp;
char sa1[40],sa2[40]; char sa1[40], sa2[40];
time_t tnow = time(NULL); time_t tnow = time(NULL);
HASH_ITER(hh, p->pool, t, tmp) { HASH_ITER(hh, p->pool, t, tmp)
{
taddr2str(t->conn.l3proto, &t->conn.src, sa1, sizeof(sa1)); taddr2str(t->conn.l3proto, &t->conn.src, sa1, sizeof(sa1));
taddr2str(t->conn.l3proto, &t->conn.dst, sa2, sizeof(sa2)); taddr2str(t->conn.l3proto, &t->conn.dst, sa2, sizeof(sa2));
printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu packets_orig=d%llu/n%llu packets_reply=d%llu/n%llu ", printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu packets_orig=d%llu/n%llu packets_reply=d%llu/n%llu ",
proto_name(t->conn.l4proto), proto_name(t->conn.l4proto),
sa1, t->conn.sport, sa2, t->conn.dport, sa1, t->conn.sport, sa2, t->conn.dport,
t->conn.l4proto==IPPROTO_TCP ? connstate_s[t->track.state] : "-", 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.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_orig, (unsigned long long)t->track.pcounter_orig,
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply); (unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply);
if (t->conn.l4proto==IPPROTO_TCP) 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", 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.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.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_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.winsize_reply, t->track.scale_reply == SCALE_NONE ? -1 : t->track.scale_reply);
else else
printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u", printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u",
t->track.seq_last, t->track.pos_orig, t->track.seq_last, t->track.pos_orig,
@ -358,7 +386,6 @@ void ConntrackPoolDump(const t_conntrack *p)
}; };
} }
void ReasmClear(t_reassemble *reasm) void ReasmClear(t_reassemble *reasm)
{ {
if (reasm->packet) if (reasm->packet)
@ -371,7 +398,8 @@ void ReasmClear(t_reassemble *reasm)
bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start) bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
{ {
reasm->packet = malloc(size_requested); reasm->packet = malloc(size_requested);
if (!reasm->packet) return false; if (!reasm->packet)
return false;
reasm->size = size_requested; reasm->size = size_requested;
reasm->size_present = 0; reasm->size_present = 0;
reasm->seq = seq_start; reasm->seq = seq_start;
@ -380,19 +408,23 @@ bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
bool ReasmResize(t_reassemble *reasm, size_t new_size) bool ReasmResize(t_reassemble *reasm, size_t new_size)
{ {
uint8_t *p = realloc(reasm->packet, new_size); uint8_t *p = realloc(reasm->packet, new_size);
if (!p) return false; if (!p)
return false;
reasm->packet = p; reasm->packet = p;
reasm->size = new_size; reasm->size = new_size;
if (reasm->size_present > new_size) reasm->size_present = new_size; if (reasm->size_present > new_size)
reasm->size_present = new_size;
return true; return true;
} }
bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len) bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len)
{ {
if (reasm->seq!=seq) return false; // fail session if out of sequence if (reasm->seq != seq)
return false; // fail session if out of sequence
size_t szcopy; size_t szcopy;
szcopy = reasm->size - reasm->size_present; szcopy = reasm->size - reasm->size_present;
if (len<szcopy) szcopy = len; if (len < szcopy)
szcopy = len;
memcpy(reasm->packet + reasm->size_present, payload, szcopy); memcpy(reasm->packet + reasm->size_present, payload, szcopy);
reasm->size_present += szcopy; reasm->size_present += szcopy;
reasm->seq += (uint32_t)szcopy; reasm->seq += (uint32_t)szcopy;
@ -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) bool ReasmHasSpace(t_reassemble *reasm, size_t len)
{ {
return (reasm->size_present+len)<=reasm->size; return (reasm->size_present + len) <= reasm->size;
} }

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
// this conntrack is not bullet-proof // this conntrack is not bullet-proof
// its designed to satisfy dpi desync needs only // its designed to satisfy dpi desync needs only
@ -19,29 +18,30 @@
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <netinet/udp.h> #include <netinet/udp.h>
// #define HASH_BLOOM 20
//#define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1 #define HASH_NONFATAL_OOM 1
#undef HASH_FUNCTION #undef HASH_FUNCTION
#define HASH_FUNCTION HASH_BER #define HASH_FUNCTION HASH_BER
#include "uthash.h" #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 in_addr ip;
struct in6_addr ip6; struct in6_addr ip6;
} t_addr; } t_addr;
typedef struct typedef struct
{ {
t_addr src, dst; t_addr src, dst;
uint16_t sport,dport; uint16_t sport, dport;
uint8_t l3proto; // IPPROTO_IP, IPPROTO_IPV6 uint8_t l3proto; // IPPROTO_IP, IPPROTO_IPV6
uint8_t l4proto; // IPPROTO_TCP, IPPROTO_UDP uint8_t l4proto; // IPPROTO_TCP, IPPROTO_UDP
} t_conn; } t_conn;
// this structure helps to reassemble continuous packets streams. it does not support out-of-orders // this structure helps to reassemble continuous packets streams. it does not support out-of-orders
typedef struct { typedef struct
{
uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size. uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size.
uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session. uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session.
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet' size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
@ -51,8 +51,21 @@ typedef struct {
// SYN - SYN or SYN/ACK received // SYN - SYN or SYN/ACK received
// ESTABLISHED - any except SYN or SYN/ACK received // ESTABLISHED - any except SYN or SYN/ACK received
// FIN - FIN or RST received // FIN - FIN or RST received
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate; typedef enum
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto; {
SYN = 0,
ESTABLISHED,
FIN
} t_connstate;
typedef enum
{
UNKNOWN = 0,
HTTP,
TLS,
QUIC,
WIREGUARD,
DHT
} t_l7proto;
typedef struct typedef struct
{ {
// common state // common state
@ -69,8 +82,8 @@ typedef struct
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
uint8_t req_retrans_counter; // number of request retransmissions uint8_t req_retrans_counter; // number of request retransmissions
bool req_seq_present,req_seq_finalized,req_seq_abandoned; 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 req_seq_start, req_seq_end; // sequence interval of the request (to track retransmissions)
uint8_t autottl; uint8_t autottl;
@ -94,7 +107,7 @@ typedef struct
typedef struct typedef struct
{ {
// inactivity time to purge an entry in each connection state // 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; time_t t_purge_interval, t_last_purge;
t_conntrack_pool *pool; t_conntrack_pool *pool;
} t_conntrack; } 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); bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len);
// check if it has enough space to buffer 'len' bytes // check if it has enough space to buffer 'len' bytes
bool ReasmHasSpace(t_reassemble *reasm, size_t len); bool ReasmHasSpace(t_reassemble *reasm, size_t len);
inline static bool ReasmIsEmpty(t_reassemble *reasm) {return !reasm->size;} 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 ReasmIsFull(t_reassemble *reasm) { return !ReasmIsEmpty(reasm) && (reasm->size == reasm->size_present); }

View File

@ -1,24 +1,24 @@
/****************************************************************************** /******************************************************************************
* *
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL * 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 * This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus * 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 * of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory * particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly. * 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. * 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 * 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. * reference implementation of the SQRL (Secure Quick Reliable Login) client.
* *
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html * See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
* *
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE * 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. * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
* *
*******************************************************************************/ *******************************************************************************/
#include "aes.h" #include "aes.h"
@ -37,7 +37,7 @@ 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 * 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. * decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
*/ */
// We always need our forward tables // We always need our forward tables
static uchar FSb[256]; // Forward substitution box (FSb) static uchar FSb[256]; // Forward substitution box (FSb)
static uint32_t FT0[256]; // Forward key schedule assembly tables static uint32_t FT0[256]; // Forward key schedule assembly tables
static uint32_t FT1[256]; static uint32_t FT1[256];
@ -58,80 +58,90 @@ static uint32_t RCON[10]; // AES round constants
* Platform Endianness Neutralizing Load and Store Macro definitions * Platform Endianness Neutralizing Load and Store Macro definitions
* AES wants platform-neutral Little Endian (LE) byte ordering * AES wants platform-neutral Little Endian (LE) byte ordering
*/ */
#define GET_UINT32_LE(n,b,i) { \ #define GET_UINT32_LE(n, b, i) \
(n) = ( (uint32_t) (b)[(i) ] ) \ { \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \ (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \ }
| ( (uint32_t) (b)[(i) + 3] << 24 ); }
#define PUT_UINT32_LE(n,b,i) { \ #define PUT_UINT32_LE(n, b, i) \
(b)[(i) ] = (uchar) ( (n) ); \ { \
(b)[(i) + 1] = (uchar) ( (n) >> 8 ); \ (b)[(i)] = (uchar)((n)); \
(b)[(i) + 2] = (uchar) ( (n) >> 16 ); \ (b)[(i) + 1] = (uchar)((n) >> 8); \
(b)[(i) + 3] = (uchar) ( (n) >> 24 ); } (b)[(i) + 2] = (uchar)((n) >> 16); \
(b)[(i) + 3] = (uchar)((n) >> 24); \
}
/* /*
* AES forward and reverse encryption round processing macros * AES forward and reverse encryption round processing macros
*/ */
#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ #define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \ { \
X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ X0 = *RK++ ^ FT0[(Y0) & 0xFF] ^ \
FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ FT1[(Y1 >> 8) & 0xFF] ^ \
FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ FT2[(Y2 >> 16) & 0xFF] ^ \
FT3[ ( Y3 >> 24 ) & 0xFF ]; \ FT3[(Y3 >> 24) & 0xFF]; \
\ \
X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ X1 = *RK++ ^ FT0[(Y1) & 0xFF] ^ \
FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ FT1[(Y2 >> 8) & 0xFF] ^ \
FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ FT2[(Y3 >> 16) & 0xFF] ^ \
FT3[ ( Y0 >> 24 ) & 0xFF ]; \ FT3[(Y0 >> 24) & 0xFF]; \
\ \
X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ X2 = *RK++ ^ FT0[(Y2) & 0xFF] ^ \
FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ FT1[(Y3 >> 8) & 0xFF] ^ \
FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ FT2[(Y0 >> 16) & 0xFF] ^ \
FT3[ ( Y1 >> 24 ) & 0xFF ]; \ FT3[(Y1 >> 24) & 0xFF]; \
\ \
X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ X3 = *RK++ ^ FT0[(Y3) & 0xFF] ^ \
FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ FT1[(Y0 >> 8) & 0xFF] ^ \
FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ FT2[(Y1 >> 16) & 0xFF] ^ \
FT3[ ( Y2 >> 24 ) & 0xFF ]; \ FT3[(Y2 >> 24) & 0xFF]; \
} }
#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ #define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \ { \
X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ X0 = *RK++ ^ RT0[(Y0) & 0xFF] ^ \
RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ RT1[(Y3 >> 8) & 0xFF] ^ \
RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ RT2[(Y2 >> 16) & 0xFF] ^ \
RT3[ ( Y1 >> 24 ) & 0xFF ]; \ RT3[(Y1 >> 24) & 0xFF]; \
\ \
X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ X1 = *RK++ ^ RT0[(Y1) & 0xFF] ^ \
RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ RT1[(Y0 >> 8) & 0xFF] ^ \
RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ RT2[(Y3 >> 16) & 0xFF] ^ \
RT3[ ( Y2 >> 24 ) & 0xFF ]; \ RT3[(Y2 >> 24) & 0xFF]; \
\ \
X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ X2 = *RK++ ^ RT0[(Y2) & 0xFF] ^ \
RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ RT1[(Y1 >> 8) & 0xFF] ^ \
RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ RT2[(Y0 >> 16) & 0xFF] ^ \
RT3[ ( Y3 >> 24 ) & 0xFF ]; \ RT3[(Y3 >> 24) & 0xFF]; \
\ \
X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ X3 = *RK++ ^ RT0[(Y3) & 0xFF] ^ \
RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ RT1[(Y2 >> 8) & 0xFF] ^ \
RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ RT2[(Y1 >> 16) & 0xFF] ^ \
RT3[ ( Y0 >> 24 ) & 0xFF ]; \ RT3[(Y0 >> 24) & 0xFF]; \
} }
/* /*
* These macros improve the readability of the key * These macros improve the readability of the key
* generation initialization code by collapsing * generation initialization code by collapsing
* repetitive common operations into logical pieces. * repetitive common operations into logical pieces.
*/ */
#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) #define ROTL8(x) ((x << 8) & 0xFFFFFFFF) | (x >> 24)
#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) #define XTIME(x) ((x << 1) ^ ((x & 0x80) ? 0x1B : 0x00))
#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) #define MUL(x, y) ((x && y) ? pow[(log[x] + log[y]) % 255] : 0)
#define MIX(x,y) { y = ( (y << 1) | (y >> 7) ) & 0xFF; x ^= y; } #define MIX(x, y) \
#define CPY128 { *RK++ = *SK++; *RK++ = *SK++; \ { \
*RK++ = *SK++; *RK++ = *SK++; } y = ((y << 1) | (y >> 7)) & 0xFF; \
x ^= y; \
}
#define CPY128 \
{ \
*RK++ = *SK++; \
*RK++ = *SK++; \
*RK++ = *SK++; \
*RK++ = *SK++; \
}
/****************************************************************************** /******************************************************************************
* *
* AES_INIT_KEYGEN_TABLES * AES_INIT_KEYGEN_TABLES
* *
@ -147,16 +157,19 @@ void aes_init_keygen_tables(void)
int pow[256]; int pow[256];
int log[256]; int log[256];
if (aes_tables_inited) return; if (aes_tables_inited)
return;
// fill the 'pow' and 'log' tables over GF(2^8) // fill the 'pow' and 'log' tables over GF(2^8)
for (i = 0, x = 1; i < 256; i++) { for (i = 0, x = 1; i < 256; i++)
{
pow[i] = x; pow[i] = x;
log[x] = i; log[x] = i;
x = (x ^ XTIME(x)) & 0xFF; x = (x ^ XTIME(x)) & 0xFF;
} }
// compute the round constants // compute the round constants
for (i = 0, x = 1; i < 10; i++) { for (i = 0, x = 1; i < 10; i++)
{
RCON[i] = (uint32_t)x; RCON[i] = (uint32_t)x;
x = XTIME(x) & 0xFF; x = XTIME(x) & 0xFF;
} }
@ -166,7 +179,8 @@ void aes_init_keygen_tables(void)
RSb[0x63] = 0x00; RSb[0x63] = 0x00;
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
for (i = 1; i < 256; i++) { for (i = 1; i < 256; i++)
{
x = y = pow[255 - log[i]]; x = y = pow[255 - log[i]];
MIX(x, y); MIX(x, y);
MIX(x, y); MIX(x, y);
@ -176,10 +190,10 @@ void aes_init_keygen_tables(void)
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
RSb[x] = (uchar)i; RSb[x] = (uchar)i;
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
} }
// generate the forward and reverse key expansion tables // generate the forward and reverse key expansion tables
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++)
{
x = FSb[i]; x = FSb[i];
y = XTIME(x) & 0xFF; y = XTIME(x) & 0xFF;
z = (y ^ x) & 0xFF; z = (y ^ x) & 0xFF;
@ -224,14 +238,16 @@ int aes_set_encryption_key(aes_context *ctx,
uint i; // general purpose iteration local uint i; // general purpose iteration local
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
for (i = 0; i < (keysize >> 2); i++) { for (i = 0; i < (keysize >> 2); i++)
{
GET_UINT32_LE(RK[i], key, i << 2); GET_UINT32_LE(RK[i], key, i << 2);
} }
switch (ctx->rounds) switch (ctx->rounds)
{ {
case 10: case 10:
for (i = 0; i < 10; i++, RK += 4) { for (i = 0; i < 10; i++, RK += 4)
{
RK[4] = RK[0] ^ RCON[i] ^ RK[4] = RK[0] ^ RCON[i] ^
((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^ ((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^ ((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^
@ -245,7 +261,8 @@ int aes_set_encryption_key(aes_context *ctx,
break; break;
case 12: case 12:
for (i = 0; i < 8; i++, RK += 6) { for (i = 0; i < 8; i++, RK += 6)
{
RK[6] = RK[0] ^ RCON[i] ^ RK[6] = RK[0] ^ RCON[i] ^
((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^ ((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^ ((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^
@ -261,7 +278,8 @@ int aes_set_encryption_key(aes_context *ctx,
break; break;
case 14: case 14:
for (i = 0; i < 7; i++, RK += 8) { for (i = 0; i < 7; i++, RK += 8)
{
RK[8] = RK[0] ^ RCON[i] ^ RK[8] = RK[0] ^ RCON[i] ^
((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^ ((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^ ((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^
@ -287,7 +305,7 @@ int aes_set_encryption_key(aes_context *ctx,
default: default:
return -1; return -1;
} }
return(0); return (0);
} }
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
@ -316,14 +334,16 @@ int aes_set_decryption_key(aes_context *ctx,
cty.rk = cty.buf; // round count and key buf pointer cty.rk = cty.buf; // round count and key buf pointer
if ((ret = aes_set_encryption_key(&cty, key, keysize)) != 0) if ((ret = aes_set_encryption_key(&cty, key, keysize)) != 0)
return(ret); return (ret);
SK = cty.rk + cty.rounds * 4; 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 (i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8)
for (j = 0; j < 4; j++, SK++) { {
for (j = 0; j < 4; j++, SK++)
{
*RK++ = RT0[FSb[(*SK) & 0xFF]] ^ *RK++ = RT0[FSb[(*SK) & 0xFF]] ^
RT1[FSb[(*SK >> 8) & 0xFF]] ^ RT1[FSb[(*SK >> 8) & 0xFF]] ^
RT2[FSb[(*SK >> 16) & 0xFF]] ^ RT2[FSb[(*SK >> 16) & 0xFF]] ^
@ -332,7 +352,7 @@ int aes_set_decryption_key(aes_context *ctx,
} }
CPY128 // copy a 128-bit block from *SK to *RK CPY128 // copy a 128-bit block from *SK to *RK
memset(&cty, 0, sizeof(aes_context)); // clear local aes context memset(&cty, 0, sizeof(aes_context)); // clear local aes context
return(0); return (0);
} }
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
@ -353,25 +373,33 @@ int aes_setkey(aes_context *ctx, // AES context provided by our caller
// system-specific mutexes and init the AES key generation tables on // system-specific mutexes and init the AES key generation tables on
// demand, or ask the developer to simply call "gcm_initialize" once during // demand, or ask the developer to simply call "gcm_initialize" once during
// application startup before threading begins. That's what we choose. // application startup before threading begins. That's what we choose.
if (!aes_tables_inited) return (-1); // fail the call when not inited. if (!aes_tables_inited)
return (-1); // fail the call when not inited.
ctx->mode = mode; // capture the key type we're creating ctx->mode = mode; // capture the key type we're creating
ctx->rk = ctx->buf; // initialize our round key pointer ctx->rk = ctx->buf; // initialize our round key pointer
switch (keysize) // set the rounds count based upon the keysize switch (keysize) // set the rounds count based upon the keysize
{ {
case 16: ctx->rounds = 10; break; // 16-byte, 128-bit key case 16:
case 24: ctx->rounds = 12; break; // 24-byte, 192-bit key ctx->rounds = 10;
case 32: ctx->rounds = 14; break; // 32-byte, 256-bit key break; // 16-byte, 128-bit key
default: return(-1); case 24:
ctx->rounds = 12;
break; // 24-byte, 192-bit key
case 32:
ctx->rounds = 14;
break; // 32-byte, 256-bit key
default:
return (-1);
} }
#if AES_DECRYPTION #if AES_DECRYPTION
if (mode == DECRYPT) // expand our key for encryption or decryption if (mode == DECRYPT) // expand our key for encryption or decryption
return(aes_set_decryption_key(ctx, key, keysize)); return (aes_set_decryption_key(ctx, key, keysize));
else /* ENCRYPT */ else /* ENCRYPT */
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
return(aes_set_encryption_key(ctx, key, keysize)); return (aes_set_encryption_key(ctx, key, keysize));
} }
/****************************************************************************** /******************************************************************************
@ -392,10 +420,14 @@ int aes_cipher(aes_context *ctx,
RK = ctx->rk; RK = ctx->rk;
GET_UINT32_LE(X0, input, 0); X0 ^= *RK++; // load our 128-bit GET_UINT32_LE(X0, input, 0);
GET_UINT32_LE(X1, input, 4); X1 ^= *RK++; // input buffer in a storage X0 ^= *RK++; // load our 128-bit
GET_UINT32_LE(X2, input, 8); X2 ^= *RK++; // memory endian-neutral way GET_UINT32_LE(X1, input, 4);
GET_UINT32_LE(X3, input, 12); X3 ^= *RK++; X1 ^= *RK++; // input buffer in a storage
GET_UINT32_LE(X2, input, 8);
X2 ^= *RK++; // memory endian-neutral way
GET_UINT32_LE(X3, input, 12);
X3 ^= *RK++;
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
@ -409,25 +441,25 @@ int aes_cipher(aes_context *ctx,
AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ \ X0 = *RK++ ^
((uint32_t)RSb[(Y0) & 0xFF]) ^ ((uint32_t)RSb[(Y0) & 0xFF]) ^
((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^ ((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24); ((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24);
X1 = *RK++ ^ \ X1 = *RK++ ^
((uint32_t)RSb[(Y1) & 0xFF]) ^ ((uint32_t)RSb[(Y1) & 0xFF]) ^
((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^ ((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24); ((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24);
X2 = *RK++ ^ \ X2 = *RK++ ^
((uint32_t)RSb[(Y2) & 0xFF]) ^ ((uint32_t)RSb[(Y2) & 0xFF]) ^
((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^ ((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24); ((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24);
X3 = *RK++ ^ \ X3 = *RK++ ^
((uint32_t)RSb[(Y3) & 0xFF]) ^ ((uint32_t)RSb[(Y3) & 0xFF]) ^
((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^ ((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^
@ -445,25 +477,25 @@ int aes_cipher(aes_context *ctx,
AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ \ X0 = *RK++ ^
((uint32_t)FSb[(Y0) & 0xFF]) ^ ((uint32_t)FSb[(Y0) & 0xFF]) ^
((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^ ((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24); ((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24);
X1 = *RK++ ^ \ X1 = *RK++ ^
((uint32_t)FSb[(Y1) & 0xFF]) ^ ((uint32_t)FSb[(Y1) & 0xFF]) ^
((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^ ((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24); ((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24);
X2 = *RK++ ^ \ X2 = *RK++ ^
((uint32_t)FSb[(Y2) & 0xFF]) ^ ((uint32_t)FSb[(Y2) & 0xFF]) ^
((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^ ((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24); ((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24);
X3 = *RK++ ^ \ X3 = *RK++ ^
((uint32_t)FSb[(Y3) & 0xFF]) ^ ((uint32_t)FSb[(Y3) & 0xFF]) ^
((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^ ((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^
@ -478,6 +510,6 @@ int aes_cipher(aes_context *ctx,
PUT_UINT32_LE(X2, output, 8); PUT_UINT32_LE(X2, output, 8);
PUT_UINT32_LE(X3, output, 12); PUT_UINT32_LE(X3, output, 12);
return(0); return (0);
} }
/* end of aes.c */ /* end of aes.c */

View File

@ -1,24 +1,24 @@
/****************************************************************************** /******************************************************************************
* *
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL * 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 * This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus * 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 * of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory * particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly. * 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. * 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 * 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. * reference implementation of the SQRL (Secure Quick Reliable Login) client.
* *
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html * See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
* *
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE * 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. * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
* *
*******************************************************************************/ *******************************************************************************/
#pragma once #pragma once
@ -41,24 +41,22 @@ typedef UINT32 uint32_t;
typedef unsigned char uchar; // add some convienent shorter types typedef unsigned char uchar; // add some convienent shorter types
typedef unsigned int uint; typedef unsigned int uint;
/****************************************************************************** /******************************************************************************
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use * AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
******************************************************************************/ ******************************************************************************/
void aes_init_keygen_tables(void); void aes_init_keygen_tables(void);
/****************************************************************************** /******************************************************************************
* AES_CONTEXT : cipher context / holds inter-call data * AES_CONTEXT : cipher context / holds inter-call data
******************************************************************************/ ******************************************************************************/
typedef struct { typedef struct
{
int mode; // 1 for Encryption, 0 for Decryption int mode; // 1 for Encryption, 0 for Decryption
int rounds; // keysize-based rounds count int rounds; // keysize-based rounds count
uint32_t *rk; // pointer to current round key uint32_t *rk; // pointer to current round key
uint32_t buf[68]; // key expansion buffer uint32_t buf[68]; // key expansion buffer
} aes_context; } aes_context;
/****************************************************************************** /******************************************************************************
* AES_SETKEY : called to expand the key for encryption or decryption * AES_SETKEY : called to expand the key for encryption or decryption
******************************************************************************/ ******************************************************************************/

View File

@ -1,26 +1,26 @@
/****************************************************************************** /******************************************************************************
* *
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL * 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 * This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written * encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It * 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 * should be endian (memory byte order) neutral since the few places that care
* are handled explicitly. * are handled explicitly.
* *
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com. * 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 * 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. * reference implementation of the SQRL (Secure Quick Reliable Login) client.
* *
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf * See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/
* gcm/gcm-revised-spec.pdf * gcm/gcm-revised-spec.pdf
* *
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE * 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. * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
* *
*******************************************************************************/ *******************************************************************************/
#include "gcm.h" #include "gcm.h"
#include "aes.h" #include "aes.h"
@ -41,7 +41,7 @@
* *
******************************************************************************/ ******************************************************************************/
/* Calculating the "GHASH" /* Calculating the "GHASH"
* *
* There are many ways of calculating the so-called GHASH in software, each with * 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 * a traditional size vs performance tradeoff. The GHASH (Galois field hash) is
@ -70,33 +70,33 @@
* See, also section 4.1 of the "gcm-revised-spec" cited above. * See, also section 4.1 of the "gcm-revised-spec" cited above.
*/ */
/* /*
* This 16-entry table of pre-computed constants is used by the * This 16-entry table of pre-computed constants is used by the
* GHASH multiplier to improve over a strictly table-free but * GHASH multiplier to improve over a strictly table-free but
* significantly slower 128x128 bit multiple within GF(2^128). * significantly slower 128x128 bit multiple within GF(2^128).
*/ */
static const uint64_t last4[16] = { static const uint64_t last4[16] = {
0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0, 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 * Platform Endianness Neutralizing Load and Store Macro definitions
* GCM wants platform-neutral Big Endian (BE) byte ordering * GCM wants platform-neutral Big Endian (BE) byte ordering
*/ */
#define GET_UINT32_BE(n,b,i) { \ #define GET_UINT32_BE(n, b, i) \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \ { \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \ (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \ }
| ( (uint32_t) (b)[(i) + 3] ); }
#define PUT_UINT32_BE(n,b,i) { \ #define PUT_UINT32_BE(n, b, i) \
(b)[(i) ] = (uchar) ( (n) >> 24 ); \ { \
(b)[(i) + 1] = (uchar) ( (n) >> 16 ); \ (b)[(i)] = (uchar)((n) >> 24); \
(b)[(i) + 2] = (uchar) ( (n) >> 8 ); \ (b)[(i) + 1] = (uchar)((n) >> 16); \
(b)[(i) + 3] = (uchar) ( (n) ); } (b)[(i) + 2] = (uchar)((n) >> 8); \
(b)[(i) + 3] = (uchar)((n)); \
}
/******************************************************************************
/******************************************************************************
* *
* GCM_INITIALIZE * GCM_INITIALIZE
* *
@ -111,10 +111,9 @@ static const uint64_t last4[16] = {
int gcm_initialize(void) int gcm_initialize(void)
{ {
aes_init_keygen_tables(); aes_init_keygen_tables();
return(0); return (0);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM_MULT * GCM_MULT
@ -137,11 +136,13 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
zh = ctx->HH[lo]; zh = ctx->HH[lo];
zl = ctx->HL[lo]; zl = ctx->HL[lo];
for (i = 15; i >= 0; i--) { for (i = 15; i >= 0; i--)
{
lo = (uchar)(x[i] & 0x0f); lo = (uchar)(x[i] & 0x0f);
hi = (uchar)(x[i] >> 4); hi = (uchar)(x[i] >> 4);
if (i != 15) { if (i != 15)
{
rem = (uchar)(zl & 0x0f); rem = (uchar)(zl & 0x0f);
zl = (zh << 60) | (zl >> 4); zl = (zh << 60) | (zl >> 4);
zh = (zh >> 4); zh = (zh >> 4);
@ -162,7 +163,6 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
PUT_UINT32_BE(zl, output, 12); PUT_UINT32_BE(zl, output, 12);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM_SETKEY * GCM_SETKEY
@ -187,9 +187,9 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
// encrypt the null 128-bit block to generate a key-based value // encrypt the null 128-bit block to generate a key-based value
// which is then used to initialize our GHASH lookup tables // which is then used to initialize our GHASH lookup tables
if ((ret = aes_setkey(&ctx->aes_ctx, AES_ENCRYPT, key, keysize)) != 0) 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) 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); GET_UINT32_BE(lo, h, 4);
@ -204,26 +204,28 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128) ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128)
ctx->HL[0] = 0; ctx->HL[0] = 0;
for (i = 4; i > 0; i >>= 1) { for (i = 4; i > 0; i >>= 1)
{
uint32_t T = (uint32_t)(vl & 1) * 0xe1000000U; uint32_t T = (uint32_t)(vl & 1) * 0xe1000000U;
vl = (vh << 63) | (vl >> 1); vl = (vh << 63) | (vl >> 1);
vh = (vh >> 1) ^ ((uint64_t)T << 32); vh = (vh >> 1) ^ ((uint64_t)T << 32);
ctx->HL[i] = vl; ctx->HL[i] = vl;
ctx->HH[i] = vh; ctx->HH[i] = vh;
} }
for (i = 2; i < 16; i <<= 1) { for (i = 2; i < 16; i <<= 1)
{
uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i;
vh = *HiH; vh = *HiH;
vl = *HiL; vl = *HiL;
for (j = 1; j < i; j++) { for (j = 1; j < i; j++)
{
HiH[j] = vh ^ ctx->HH[j]; HiH[j] = vh ^ ctx->HH[j];
HiL[j] = vl ^ ctx->HL[j]; HiL[j] = vl ^ ctx->HL[j];
} }
} }
return(0); return (0);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH. * GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH.
@ -268,7 +270,8 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
ctx->mode = mode; // set the GCM encryption/decryption mode ctx->mode = mode; // set the GCM encryption/decryption mode
ctx->aes_ctx.mode = AES_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode ctx->aes_ctx.mode = AES_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode
if (iv_len == 12) { // GCM natively uses a 12-byte, 96-bit IV if (iv_len == 12)
{ // GCM natively uses a 12-byte, 96-bit IV
memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff
ctx->y[15] = 1; // start "counting" from 1 (not 0) ctx->y[15] = 1; // start "counting" from 1 (not 0)
} }
@ -278,29 +281,34 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer
p = iv; p = iv;
while (iv_len > 0) { while (iv_len > 0)
{
use_len = (iv_len < 16) ? iv_len : 16; use_len = (iv_len < 16) ? iv_len : 16;
for (i = 0; i < use_len; i++) ctx->y[i] ^= p[i]; for (i = 0; i < use_len; i++)
ctx->y[i] ^= p[i];
gcm_mult(ctx, ctx->y, ctx->y); gcm_mult(ctx, ctx->y, ctx->y);
iv_len -= use_len; iv_len -= use_len;
p += use_len; p += use_len;
} }
for (i = 0; i < 16; i++) ctx->y[i] ^= work_buf[i]; for (i = 0; i < 16; i++)
ctx->y[i] ^= work_buf[i];
gcm_mult(ctx, ctx->y, ctx->y); gcm_mult(ctx, ctx->y, ctx->y);
} }
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0) if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0)
return(ret); return (ret);
ctx->add_len = add_len; ctx->add_len = add_len;
p = add; p = add;
while (add_len > 0) { while (add_len > 0)
{
use_len = (add_len < 16) ? add_len : 16; use_len = (add_len < 16) ? add_len : 16;
for (i = 0; i < use_len; i++) ctx->buf[i] ^= p[i]; for (i = 0; i < use_len; i++)
ctx->buf[i] ^= p[i];
gcm_mult(ctx, ctx->buf, ctx->buf); gcm_mult(ctx, ctx->buf, ctx->buf);
add_len -= use_len; add_len -= use_len;
p += use_len; p += use_len;
} }
return(0); return (0);
} }
/****************************************************************************** /******************************************************************************
@ -326,21 +334,25 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
ctx->len += length; // bump the GCM context's running length count ctx->len += length; // bump the GCM context's running length count
while (length > 0) { while (length > 0)
{
// clamp the length to process at 16 bytes // clamp the length to process at 16 bytes
use_len = (length < 16) ? length : 16; use_len = (length < 16) ? length : 16;
// increment the context's 128-bit IV||Counter 'y' vector // increment the context's 128-bit IV||Counter 'y' vector
for (i = 16; i > 12; i--) if (++ctx->y[i - 1] != 0) break; for (i = 16; i > 12; i--)
if (++ctx->y[i - 1] != 0)
break;
// encrypt the context's 'y' vector under the established key // encrypt the context's 'y' vector under the established key
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ectr)) != 0) if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ectr)) != 0)
return(ret); return (ret);
// encrypt or decrypt the input to the output // encrypt or decrypt the input to the output
if (ctx->mode == AES_ENCRYPT) if (ctx->mode == AES_ENCRYPT)
{ {
for (i = 0; i < use_len; i++) { for (i = 0; i < use_len; i++)
{
// XOR the cipher's ouptut vector (ectr) with our input // XOR the cipher's ouptut vector (ectr) with our input
output[i] = (uchar)(ectr[i] ^ input[i]); output[i] = (uchar)(ectr[i] ^ input[i]);
// now we mix in our data into the authentication hash. // now we mix in our data into the authentication hash.
@ -352,7 +364,8 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
} }
else else
{ {
for (i = 0; i < use_len; i++) { for (i = 0; i < use_len; i++)
{
// but if we're DEcrypting we XOR in the input data first, // but if we're DEcrypting we XOR in the input data first,
// i.e. before saving to ouput data, otherwise if the input // i.e. before saving to ouput data, otherwise if the input
// and output buffer are the same (inplace decryption) we // and output buffer are the same (inplace decryption) we
@ -370,7 +383,7 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
input += use_len; // bump our input pointer forward 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);
} }
/****************************************************************************** /******************************************************************************
@ -390,9 +403,11 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uint64_t orig_add_len = ctx->add_len * 8; uint64_t orig_add_len = ctx->add_len * 8;
size_t i; size_t i;
if (tag_len != 0) memcpy(tag, ctx->base_ectr, tag_len); if (tag_len != 0)
memcpy(tag, ctx->base_ectr, tag_len);
if (orig_len || orig_add_len) { if (orig_len || orig_add_len)
{
memset(work_buf, 0x00, 16); memset(work_buf, 0x00, 16);
PUT_UINT32_BE((orig_add_len >> 32), work_buf, 0); PUT_UINT32_BE((orig_add_len >> 32), work_buf, 0);
@ -400,14 +415,15 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
PUT_UINT32_BE((orig_len >> 32), work_buf, 8); PUT_UINT32_BE((orig_len >> 32), work_buf, 8);
PUT_UINT32_BE((orig_len), work_buf, 12); PUT_UINT32_BE((orig_len), work_buf, 12);
for (i = 0; i < 16; i++) ctx->buf[i] ^= work_buf[i]; for (i = 0; i < 16; i++)
ctx->buf[i] ^= work_buf[i];
gcm_mult(ctx, ctx->buf, ctx->buf); gcm_mult(ctx, ctx->buf, ctx->buf);
for (i = 0; i < tag_len; i++) tag[i] ^= ctx->buf[i]; for (i = 0; i < tag_len; i++)
tag[i] ^= ctx->buf[i];
} }
return(0); return (0);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM_CRYPT_AND_TAG * GCM_CRYPT_AND_TAG
@ -445,10 +461,9 @@ int gcm_crypt_and_tag(
gcm_start(ctx, mode, iv, iv_len, add, add_len); gcm_start(ctx, mode, iv, iv_len, add, add_len);
gcm_update(ctx, length, input, output); gcm_update(ctx, length, input, output);
gcm_finish(ctx, tag, tag_len); gcm_finish(ctx, tag, tag_len);
return(0); return (0);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM_AUTH_DECRYPT * GCM_AUTH_DECRYPT
@ -488,11 +503,12 @@ int gcm_auth_decrypt(
for (diff = 0, i = 0; i < tag_len; i++) for (diff = 0, i = 0; i < tag_len; i++)
diff |= tag[i] ^ check_tag[i]; diff |= tag[i] ^ check_tag[i];
if (diff != 0) { // see whether any bits differed? if (diff != 0)
{ // see whether any bits differed?
memset(output, 0, length); // if so... wipe the output data memset(output, 0, length); // if so... wipe the output data
return(GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE return (GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
} }
return(0); return (0);
} }
/****************************************************************************** /******************************************************************************

View File

@ -1,26 +1,26 @@
/****************************************************************************** /******************************************************************************
* *
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL * 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 * This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written * encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It * 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 * should be endian (memory byte order) neutral since the few places that care
* are handled explicitly. * are handled explicitly.
* *
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com. * 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 * 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. * reference implementation of the SQRL (Secure Quick Reliable Login) client.
* *
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf * See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \ * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \
* gcm/gcm-revised-spec.pdf * gcm/gcm-revised-spec.pdf
* *
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE * 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. * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
* *
*******************************************************************************/ *******************************************************************************/
#pragma once #pragma once
#define GCM_AUTH_FAILURE 0x55555555 // authentication failure #define GCM_AUTH_FAILURE 0x55555555 // authentication failure
@ -29,18 +29,18 @@
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <basetsd.h> #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 UINT32 uint32_t;
typedef UINT64 uint64_t; typedef UINT64 uint64_t;
#else #else
#include <stdint.h> #include <stdint.h>
#endif #endif
/****************************************************************************** /******************************************************************************
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx * GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
******************************************************************************/ ******************************************************************************/
typedef struct { typedef struct
{
int mode; // cipher direction: encrypt/decrypt int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length uint64_t add_len; // total add data length
@ -52,13 +52,11 @@ typedef struct {
aes_context aes_ctx; // cipher context used aes_context aes_ctx; // cipher context used
} gcm_context; } gcm_context;
/****************************************************************************** /******************************************************************************
* GCM_CONTEXT : MUST be called once before ANY use of this library * GCM_CONTEXT : MUST be called once before ANY use of this library
******************************************************************************/ ******************************************************************************/
int gcm_initialize(void); int gcm_initialize(void);
/****************************************************************************** /******************************************************************************
* GCM_SETKEY : sets the GCM (and AES) keying material for use * GCM_SETKEY : sets the GCM (and AES) keying material for use
******************************************************************************/ ******************************************************************************/
@ -68,7 +66,6 @@ int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
// 128, 192 or 256-bit keys respectively) // 128, 192 or 256-bit keys respectively)
); // returns 0 for success ); // returns 0 for success
/****************************************************************************** /******************************************************************************
* *
* GCM_CRYPT_AND_TAG * GCM_CRYPT_AND_TAG
@ -99,7 +96,6 @@ int gcm_crypt_and_tag(
uchar *tag, // pointer to the tag to be generated uchar *tag, // pointer to the tag to be generated
size_t tag_len); // byte length of the tag to be generated size_t tag_len); // byte length of the tag to be generated
/****************************************************************************** /******************************************************************************
* *
* GCM_AUTH_DECRYPT * GCM_AUTH_DECRYPT
@ -124,7 +120,6 @@ int gcm_auth_decrypt(
const uchar *tag, // pointer to the tag to be authenticated const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len); // byte length of the tag <= 16 size_t tag_len); // byte length of the tag <= 16
/****************************************************************************** /******************************************************************************
* *
* GCM_START * GCM_START
@ -140,7 +135,6 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
const uchar *add, // pointer to additional AEAD data (NULL if none) const uchar *add, // pointer to additional AEAD data (NULL if none)
size_t add_len); // length of additional AEAD data (bytes) size_t add_len); // length of additional AEAD data (bytes)
/****************************************************************************** /******************************************************************************
* *
* GCM_UPDATE * GCM_UPDATE
@ -157,7 +151,6 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
const uchar *input, // pointer to source data const uchar *input, // pointer to source data
uchar *output); // pointer to destination data uchar *output); // pointer to destination data
/****************************************************************************** /******************************************************************************
* *
* GCM_FINISH * GCM_FINISH
@ -170,7 +163,6 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0 uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf size_t tag_len); // length, in bytes, of the tag-receiving buf
/****************************************************************************** /******************************************************************************
* *
* GCM_ZERO_CTX * GCM_ZERO_CTX

View File

@ -15,7 +15,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
/* /*
* hkdf * hkdf
* *
* Description: * Description:
@ -98,12 +98,14 @@ int hkdfExtract(SHAversion whichSha,
uint8_t prk[USHAMaxHashSize]) uint8_t prk[USHAMaxHashSize])
{ {
unsigned char nullSalt[USHAMaxHashSize]; unsigned char nullSalt[USHAMaxHashSize];
if (salt == 0) { if (salt == 0)
{
salt = nullSalt; salt = nullSalt;
salt_len = USHAHashSize(whichSha); salt_len = USHAHashSize(whichSha);
memset(nullSalt, '\0', salt_len); memset(nullSalt, '\0', salt_len);
} }
else if (salt_len < 0) { else if (salt_len < 0)
{
return shaBadParam; return shaBadParam;
} }
return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk); return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
@ -150,25 +152,33 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
unsigned char T[USHAMaxHashSize]; unsigned char T[USHAMaxHashSize];
size_t Tlen, where, i; size_t Tlen, where, i;
if (info == 0) { if (info == 0)
{
info = (const unsigned char *)""; info = (const unsigned char *)"";
info_len = 0; info_len = 0;
} }
else if (info_len < 0) { else if (info_len < 0)
{
return shaBadParam; return shaBadParam;
} }
if (okm_len <= 0) return shaBadParam; if (okm_len <= 0)
if (!okm) return shaBadParam; return shaBadParam;
if (!okm)
return shaBadParam;
hash_len = USHAHashSize(whichSha); hash_len = USHAHashSize(whichSha);
if (prk_len < hash_len) return shaBadParam; if (prk_len < hash_len)
return shaBadParam;
N = okm_len / hash_len; N = okm_len / hash_len;
if ((okm_len % hash_len) != 0) N++; if ((okm_len % hash_len) != 0)
if (N > 255) return shaBadParam; N++;
if (N > 255)
return shaBadParam;
Tlen = 0; Tlen = 0;
where = 0; where = 0;
for (i = 1; i <= N; i++) { for (i = 1; i <= N; i++)
{
HMACContext context; HMACContext context;
unsigned char c = i; unsigned char c = i;
int ret = hmacReset(&context, whichSha, prk, prk_len) || int ret = hmacReset(&context, whichSha, prk, prk_len) ||
@ -176,7 +186,8 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
hmacInput(&context, info, info_len) || hmacInput(&context, info, info_len) ||
hmacInput(&context, &c, 1) || hmacInput(&context, &c, 1) ||
hmacResult(&context, T); hmacResult(&context, T);
if (ret != shaSuccess) return ret; if (ret != shaSuccess)
return ret;
memcpy(okm + where, T, memcpy(okm + where, T,
(i != N) ? hash_len : (okm_len - where)); (i != N) ? hash_len : (okm_len - where));
where += hash_len; where += hash_len;
@ -213,11 +224,13 @@ int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
const unsigned char *salt, size_t salt_len) const unsigned char *salt, size_t salt_len)
{ {
unsigned char nullSalt[USHAMaxHashSize]; unsigned char nullSalt[USHAMaxHashSize];
if (!context) return shaNull; if (!context)
return shaNull;
context->whichSha = whichSha; context->whichSha = whichSha;
context->hashSize = USHAHashSize(whichSha); context->hashSize = USHAHashSize(whichSha);
if (salt == 0) { if (salt == 0)
{
salt = nullSalt; salt = nullSalt;
salt_len = context->hashSize; salt_len = context->hashSize;
memset(nullSalt, '\0', salt_len); memset(nullSalt, '\0', salt_len);
@ -249,9 +262,12 @@ int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
int hkdfInput(HKDFContext *context, const unsigned char *ikm, int hkdfInput(HKDFContext *context, const unsigned char *ikm,
size_t ikm_len) size_t ikm_len)
{ {
if (!context) return shaNull; if (!context)
if (context->Corrupted) return context->Corrupted; return shaNull;
if (context->Computed) return context->Corrupted = shaStateError; if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
return hmacInput(&context->hmacContext, ikm, ikm_len); return hmacInput(&context->hmacContext, ikm, ikm_len);
} }
@ -278,9 +294,12 @@ int hkdfInput(HKDFContext *context, const unsigned char *ikm,
int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
unsigned int ikm_bit_count) unsigned int ikm_bit_count)
{ {
if (!context) return shaNull; if (!context)
if (context->Corrupted) return context->Corrupted; return shaNull;
if (context->Computed) return context->Corrupted = shaStateError; if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count); return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count);
} }
@ -322,11 +341,16 @@ int hkdfResult(HKDFContext *context,
uint8_t prkbuf[USHAMaxHashSize]; uint8_t prkbuf[USHAMaxHashSize];
int ret; int ret;
if (!context) return shaNull; if (!context)
if (context->Corrupted) return context->Corrupted; return shaNull;
if (context->Computed) return context->Corrupted = shaStateError; if (context->Corrupted)
if (!okm) return context->Corrupted = shaBadParam; return context->Corrupted;
if (!prk) prk = prkbuf; if (context->Computed)
return context->Corrupted = shaStateError;
if (!okm)
return context->Corrupted = shaBadParam;
if (!prk)
prk = prkbuf;
ret = hmacResult(&context->hmacContext, prk) || ret = hmacResult(&context->hmacContext, prk) ||
hkdfExpand(context->whichSha, prk, context->hashSize, info, hkdfExpand(context->whichSha, prk, context->hashSize, info,
@ -334,4 +358,3 @@ int hkdfResult(HKDFContext *context,
context->Computed = 1; context->Computed = 1;
return context->Corrupted = ret; return context->Corrupted = ret;
} }

View File

@ -14,7 +14,7 @@
#include "sha.h" #include "sha.h"
#include <stddef.h> #include <stddef.h>
/* /*
* hmac * hmac
* *
* Description: * Description:
@ -87,7 +87,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
/* temporary buffer when keylen > blocksize */ /* temporary buffer when keylen > blocksize */
unsigned char tempkey[USHAMaxHashSize]; unsigned char tempkey[USHAMaxHashSize];
if (!context) return shaNull; if (!context)
return shaNull;
context->Computed = 0; context->Computed = 0;
context->Corrupted = shaSuccess; context->Corrupted = shaSuccess;
@ -99,12 +100,14 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
* If key is longer than the hash blocksize, * If key is longer than the hash blocksize,
* reset it to key = HASH(key). * reset it to key = HASH(key).
*/ */
if (key_len > blocksize) { if (key_len > blocksize)
{
USHAContext tcontext; USHAContext tcontext;
int err = USHAReset(&tcontext, whichSha) || int err = USHAReset(&tcontext, whichSha) ||
USHAInput(&tcontext, key, key_len) || USHAInput(&tcontext, key, key_len) ||
USHAResult(&tcontext, tempkey); USHAResult(&tcontext, tempkey);
if (err != shaSuccess) return err; if (err != shaSuccess)
return err;
key = tempkey; key = tempkey;
key_len = hashsize; key_len = hashsize;
@ -122,12 +125,14 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
*/ */
/* store key into the pads, XOR'd with ipad and opad values */ /* store key into the pads, XOR'd with ipad and opad values */
for (i = 0; i < key_len; i++) { for (i = 0; i < key_len; i++)
{
k_ipad[i] = key[i] ^ 0x36; k_ipad[i] = key[i] ^ 0x36;
context->k_opad[i] = key[i] ^ 0x5c; context->k_opad[i] = key[i] ^ 0x5c;
} }
/* remaining pad bytes are '\0' XOR'd with ipad and opad values */ /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
for (; i < blocksize; i++) { for (; i < blocksize; i++)
{
k_ipad[i] = 0x36; k_ipad[i] = 0x36;
context->k_opad[i] = 0x5c; context->k_opad[i] = 0x5c;
} }
@ -163,9 +168,12 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
int hmacInput(HMACContext *context, const unsigned char *text, int hmacInput(HMACContext *context, const unsigned char *text,
size_t text_len) size_t text_len)
{ {
if (!context) return shaNull; if (!context)
if (context->Corrupted) return context->Corrupted; return shaNull;
if (context->Computed) return context->Corrupted = shaStateError; if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
/* then text of datagram */ /* then text of datagram */
return context->Corrupted = return context->Corrupted =
USHAInput(&context->shaContext, text, text_len); USHAInput(&context->shaContext, text, text_len);
@ -193,9 +201,12 @@ int hmacInput(HMACContext *context, const unsigned char *text,
int hmacFinalBits(HMACContext *context, int hmacFinalBits(HMACContext *context,
uint8_t bits, unsigned int bit_count) uint8_t bits, unsigned int bit_count)
{ {
if (!context) return shaNull; if (!context)
if (context->Corrupted) return context->Corrupted; return shaNull;
if (context->Computed) return context->Corrupted = shaStateError; if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
/* then final bits of datagram */ /* then final bits of datagram */
return context->Corrupted = return context->Corrupted =
USHAFinalBits(&context->shaContext, bits, bit_count); USHAFinalBits(&context->shaContext, bits, bit_count);
@ -223,9 +234,12 @@ int hmacFinalBits(HMACContext *context,
int hmacResult(HMACContext *context, uint8_t *digest) int hmacResult(HMACContext *context, uint8_t *digest)
{ {
int ret; int ret;
if (!context) return shaNull; if (!context)
if (context->Corrupted) return context->Corrupted; return shaNull;
if (context->Computed) return context->Corrupted = shaStateError; if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
/* finish up 1st pass */ /* finish up 1st pass */
/* (Use digest here as a temporary buffer.) */ /* (Use digest here as a temporary buffer.) */

View File

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

View File

@ -85,7 +85,8 @@
/* /*
* All SHA functions return one of these values. * All SHA functions return one of these values.
*/ */
enum { enum
{
shaSuccess = 0, shaSuccess = 0,
shaNull, /* Null pointer parameter */ shaNull, /* Null pointer parameter */
shaInputTooLong, /* input data too long */ shaInputTooLong, /* input data too long */
@ -98,31 +99,40 @@ enum {
* These constants hold size information for each of the SHA * These constants hold size information for each of the SHA
* hashing operations * hashing operations
*/ */
enum { enum
SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64, {
SHA1_Message_Block_Size = 64,
SHA224_Message_Block_Size = 64,
SHA256_Message_Block_Size = 64, SHA256_Message_Block_Size = 64,
USHA_Max_Message_Block_Size = SHA256_Message_Block_Size, USHA_Max_Message_Block_Size = SHA256_Message_Block_Size,
SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32, SHA1HashSize = 20,
SHA224HashSize = 28,
SHA256HashSize = 32,
USHAMaxHashSize = SHA256HashSize, USHAMaxHashSize = SHA256HashSize,
SHA1HashSizeBits = 160, SHA224HashSizeBits = 224, SHA1HashSizeBits = 160,
SHA256HashSizeBits = 256, USHAMaxHashSizeBits = SHA256HashSizeBits SHA224HashSizeBits = 224,
SHA256HashSizeBits = 256,
USHAMaxHashSizeBits = SHA256HashSizeBits
}; };
/* /*
* These constants are used in the USHA (Unified SHA) functions. * These constants are used in the USHA (Unified SHA) functions.
*/ */
typedef enum SHAversion { typedef enum SHAversion
SHA224, SHA256 {
SHA224,
SHA256
} SHAversion; } SHAversion;
/* /*
* This structure will hold context information for the SHA-256 * This structure will hold context information for the SHA-256
* hashing operation. * hashing operation.
*/ */
typedef struct SHA256Context { typedef struct SHA256Context
uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */ {
uint32_t Intermediate_Hash[SHA256HashSize / 4]; /* Message Digest */
uint32_t Length_High; /* Message length in bits */ uint32_t Length_High; /* Message length in bits */
uint32_t Length_Low; /* Message length in bits */ uint32_t Length_Low; /* Message length in bits */
@ -145,10 +155,13 @@ typedef struct SHA256Context SHA224Context;
* This structure holds context information for all SHA * This structure holds context information for all SHA
* hashing operations. * hashing operations.
*/ */
typedef struct USHAContext { typedef struct USHAContext
{
int whichSha; /* which SHA is being used */ int whichSha; /* which SHA is being used */
union { union
SHA224Context sha224Context; SHA256Context sha256Context; {
SHA224Context sha224Context;
SHA256Context sha256Context;
} ctx; } ctx;
} USHAContext; } USHAContext;
@ -157,7 +170,8 @@ typedef struct USHAContext {
* This structure will hold context information for the HMAC * This structure will hold context information for the HMAC
* keyed-hashing operation. * keyed-hashing operation.
*/ */
typedef struct HMACContext { typedef struct HMACContext
{
int whichSha; /* which SHA is being used */ int whichSha; /* which SHA is being used */
int hashSize; /* hash size of SHA being used */ int hashSize; /* hash size of SHA being used */
int blockSize; /* block size of SHA being used */ int blockSize; /* block size of SHA being used */
@ -173,7 +187,8 @@ typedef struct HMACContext {
* This structure will hold context information for the HKDF * This structure will hold context information for the HKDF
* extract-and-expand Key Derivation Functions. * extract-and-expand Key Derivation Functions.
*/ */
typedef struct HKDFContext { typedef struct HKDFContext
{
int whichSha; /* which SHA is being used */ int whichSha; /* which SHA is being used */
HMACContext hmacContext; HMACContext hmacContext;
int hashSize; /* hash size of SHA being used */ int hashSize; /* hash size of SHA being used */
@ -187,7 +202,6 @@ typedef struct HKDFContext {
* Function Prototypes * Function Prototypes
*/ */
/* SHA-224 */ /* SHA-224 */
int SHA224Reset(SHA224Context *); int SHA224Reset(SHA224Context *);
int SHA224Input(SHA224Context *, const uint8_t *bytes, int SHA224Input(SHA224Context *, const uint8_t *bytes,
@ -243,7 +257,6 @@ int hmacFinalBits(HMACContext *context, uint8_t bits,
int hmacResult(HMACContext *context, int hmacResult(HMACContext *context,
uint8_t digest[USHAMaxHashSize]); uint8_t digest[USHAMaxHashSize]);
/* /*
* HKDF HMAC-based Extract-and-Expand Key Derivation Function, * HKDF HMAC-based Extract-and-Expand Key Derivation Function,
* RFC 5869, for all SHAs. * RFC 5869, for all SHAs.
@ -252,14 +265,14 @@ int hkdf(SHAversion whichSha,
const unsigned char *salt, size_t salt_len, const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len, const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len, const unsigned char *info, size_t info_len,
uint8_t okm[ ], size_t okm_len); uint8_t okm[], size_t okm_len);
int hkdfExtract(SHAversion whichSha, const unsigned char *salt, int hkdfExtract(SHAversion whichSha, const unsigned char *salt,
size_t salt_len, const unsigned char *ikm, size_t salt_len, const unsigned char *ikm,
size_t ikm_len, uint8_t prk[USHAMaxHashSize]); size_t ikm_len, uint8_t prk[USHAMaxHashSize]);
int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], int hkdfExpand(SHAversion whichSha, const uint8_t prk[],
size_t prk_len, const unsigned char *info, size_t prk_len, const unsigned char *info,
size_t info_len, uint8_t okm[ ], size_t okm_len); size_t info_len, uint8_t okm[], size_t okm_len);
/* /*
* HKDF HMAC-based Extract-and-Expand Key Derivation Function, * HKDF HMAC-based Extract-and-Expand Key Derivation Function,

View File

@ -44,21 +44,21 @@
#include "sha-private.h" #include "sha-private.h"
/* Define the SHA shift, rotate left, and rotate right macros */ /* Define the SHA shift, rotate left, and rotate right macros */
#define SHA256_SHR(bits,word) ((word) >> (bits)) #define SHA256_SHR(bits, word) ((word) >> (bits))
#define SHA256_ROTL(bits,word) \ #define SHA256_ROTL(bits, word) \
(((word) << (bits)) | ((word) >> (32-(bits)))) (((word) << (bits)) | ((word) >> (32 - (bits))))
#define SHA256_ROTR(bits,word) \ #define SHA256_ROTR(bits, word) \
(((word) >> (bits)) | ((word) << (32-(bits)))) (((word) >> (bits)) | ((word) << (32 - (bits))))
/* Define the SHA SIGMA and sigma macros */ /* Define the SHA SIGMA and sigma macros */
#define SHA256_SIGMA0(word) \ #define SHA256_SIGMA0(word) \
(SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word)) (SHA256_ROTR(2, word) ^ SHA256_ROTR(13, word) ^ SHA256_ROTR(22, word))
#define SHA256_SIGMA1(word) \ #define SHA256_SIGMA1(word) \
(SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word)) (SHA256_ROTR(6, word) ^ SHA256_ROTR(11, word) ^ SHA256_ROTR(25, word))
#define SHA256_sigma0(word) \ #define SHA256_sigma0(word) \
(SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word)) (SHA256_ROTR(7, word) ^ SHA256_ROTR(18, word) ^ SHA256_SHR(3, word))
#define SHA256_sigma1(word) \ #define SHA256_sigma1(word) \
(SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word)) (SHA256_ROTR(17, word) ^ SHA256_ROTR(19, word) ^ SHA256_SHR(10, word))
/* /*
* Add "length" to the length. * Add "length" to the length.
@ -68,8 +68,9 @@ static uint32_t addTemp;
#define SHA224_256AddLength(context, length) \ #define SHA224_256AddLength(context, length) \
(addTemp = (context)->Length_Low, (context)->Corrupted = \ (addTemp = (context)->Length_Low, (context)->Corrupted = \
(((context)->Length_Low += (length)) < addTemp) && \ (((context)->Length_Low += (length)) < addTemp) && \
(++(context)->Length_High == 0) ? shaInputTooLong : \ (++(context)->Length_High == 0) \
(context)->Corrupted ) ? shaInputTooLong \
: (context)->Corrupted)
/* Local Function Prototypes */ /* Local Function Prototypes */
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0); static int SHA224_256Reset(SHA256Context *context, uint32_t *H0);
@ -79,19 +80,17 @@ static void SHA224_256Finalize(SHA256Context *context,
static void SHA224_256PadMessage(SHA256Context *context, static void SHA224_256PadMessage(SHA256Context *context,
uint8_t Pad_Byte); uint8_t Pad_Byte);
static int SHA224_256ResultN(SHA256Context *context, 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 */ /* Initial Hash Values: FIPS 180-3 section 5.3.2 */
static uint32_t SHA224_H0[SHA256HashSize/4] = { static uint32_t SHA224_H0[SHA256HashSize / 4] = {
0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939,
0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4};
};
/* Initial Hash Values: FIPS 180-3 section 5.3.3 */ /* Initial Hash Values: FIPS 180-3 section 5.3.3 */
static uint32_t SHA256_H0[SHA256HashSize/4] = { static uint32_t SHA256_H0[SHA256HashSize / 4] = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19};
};
/* /*
* SHA224Reset * SHA224Reset
@ -229,13 +228,19 @@ int SHA256Reset(SHA256Context *context)
int SHA256Input(SHA256Context *context, const uint8_t *message_array, int SHA256Input(SHA256Context *context, const uint8_t *message_array,
unsigned int length) unsigned int length)
{ {
if (!context) return shaNull; if (!context)
if (!length) return shaSuccess; return shaNull;
if (!message_array) return shaNull; if (!length)
if (context->Computed) return context->Corrupted = shaStateError; return shaSuccess;
if (context->Corrupted) return context->Corrupted; if (!message_array)
return shaNull;
if (context->Computed)
return context->Corrupted = shaStateError;
if (context->Corrupted)
return context->Corrupted;
while (length--) { while (length--)
{
context->Message_Block[context->Message_Block_Index++] = context->Message_Block[context->Message_Block_Index++] =
*message_array; *message_array;
@ -247,7 +252,6 @@ int SHA256Input(SHA256Context *context, const uint8_t *message_array,
} }
return context->Corrupted; return context->Corrupted;
} }
/* /*
@ -276,24 +280,26 @@ int SHA256FinalBits(SHA256Context *context,
/* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80,
/* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0,
/* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8,
/* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE};
};
static uint8_t markbit[8] = { static uint8_t markbit[8] = {
/* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40,
/* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10,
/* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04,
/* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01};
};
if (!context) return shaNull; if (!context)
if (!length) return shaSuccess; return shaNull;
if (context->Corrupted) return context->Corrupted; if (!length)
if (context->Computed) return context->Corrupted = shaStateError; return shaSuccess;
if (length >= 8) return context->Corrupted = shaBadParam; if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
if (length >= 8)
return context->Corrupted = shaBadParam;
SHA224_256AddLength(context, length); SHA224_256AddLength(context, length);
SHA224_256Finalize(context, (uint8_t) SHA224_256Finalize(context, (uint8_t)((message_bits & masks[length]) | markbit[length]));
((message_bits & masks[length]) | markbit[length]));
return context->Corrupted; return context->Corrupted;
} }
@ -341,7 +347,8 @@ int SHA256Result(SHA256Context *context,
*/ */
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0) static int SHA224_256Reset(SHA256Context *context, uint32_t *H0)
{ {
if (!context) return shaNull; if (!context)
return shaNull;
context->Length_High = context->Length_Low = 0; context->Length_High = context->Length_Low = 0;
context->Message_Block_Index = 0; context->Message_Block_Index = 0;
@ -396,8 +403,7 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
};
int t, t4; /* Loop counter */ int t, t4; /* Loop counter */
uint32_t temp1, temp2; /* Temporary word value */ uint32_t temp1, temp2; /* Temporary word value */
uint32_t W[64]; /* Word sequence */ uint32_t W[64]; /* Word sequence */
@ -412,8 +418,8 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
(((uint32_t)context->Message_Block[t4 + 2]) << 8) | (((uint32_t)context->Message_Block[t4 + 2]) << 8) |
(((uint32_t)context->Message_Block[t4 + 3])); (((uint32_t)context->Message_Block[t4 + 3]));
for (t = 16; t < 64; t++) for (t = 16; t < 64; t++)
W[t] = SHA256_sigma1(W[t-2]) + W[t-7] + W[t] = SHA256_sigma1(W[t - 2]) + W[t - 7] +
SHA256_sigma0(W[t-15]) + W[t-16]; SHA256_sigma0(W[t - 15]) + W[t - 16];
A = context->Intermediate_Hash[0]; A = context->Intermediate_Hash[0];
B = context->Intermediate_Hash[1]; B = context->Intermediate_Hash[1];
@ -424,9 +430,10 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
G = context->Intermediate_Hash[6]; G = context->Intermediate_Hash[6];
H = context->Intermediate_Hash[7]; H = context->Intermediate_Hash[7];
for (t = 0; t < 64; t++) { for (t = 0; t < 64; t++)
temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; {
temp2 = SHA256_SIGMA0(A) + SHA_Maj(A,B,C); 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; H = G;
G = F; G = F;
F = E; F = E;
@ -513,15 +520,17 @@ static void SHA224_256PadMessage(SHA256Context *context,
* block, process it, and then continue padding into a second * block, process it, and then continue padding into a second
* block. * block.
*/ */
if (context->Message_Block_Index >= (SHA256_Message_Block_Size-8)) { if (context->Message_Block_Index >= (SHA256_Message_Block_Size - 8))
{
context->Message_Block[context->Message_Block_Index++] = Pad_Byte; context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
while (context->Message_Block_Index < SHA256_Message_Block_Size) while (context->Message_Block_Index < SHA256_Message_Block_Size)
context->Message_Block[context->Message_Block_Index++] = 0; context->Message_Block[context->Message_Block_Index++] = 0;
SHA224_256ProcessMessageBlock(context); SHA224_256ProcessMessageBlock(context);
} else }
else
context->Message_Block[context->Message_Block_Index++] = Pad_Byte; context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
while (context->Message_Block_Index < (SHA256_Message_Block_Size-8)) while (context->Message_Block_Index < (SHA256_Message_Block_Size - 8))
context->Message_Block[context->Message_Block_Index++] = 0; context->Message_Block[context->Message_Block_Index++] = 0;
/* /*
@ -561,21 +570,22 @@ static void SHA224_256PadMessage(SHA256Context *context,
* sha Error Code. * sha Error Code.
*/ */
static int SHA224_256ResultN(SHA256Context *context, static int SHA224_256ResultN(SHA256Context *context,
uint8_t Message_Digest[ ], int HashSize) uint8_t Message_Digest[], int HashSize)
{ {
int i; int i;
if (!context) return shaNull; if (!context)
if (!Message_Digest) return shaNull; return shaNull;
if (context->Corrupted) return context->Corrupted; if (!Message_Digest)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (!context->Computed) if (!context->Computed)
SHA224_256Finalize(context, 0x80); SHA224_256Finalize(context, 0x80);
for (i = 0; i < HashSize; ++i) for (i = 0; i < HashSize; ++i)
Message_Digest[i] = (uint8_t) Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03)));
(context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ));
return shaSuccess; return shaSuccess;
} }

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
#define FOOL_IPFRAG1 0x80 #define FOOL_IPFRAG1 0x80
#define FOOL_DATANOACK 0x100 #define FOOL_DATANOACK 0x100
#define SCALE_NONE ((uint8_t)-1) #define SCALE_NONE ((uint8_t) - 1)
#define VERDICT_PASS 0 #define VERDICT_PASS 0
#define VERDICT_MODIFY 1 #define VERDICT_MODIFY 1
@ -100,7 +100,6 @@ bool prepare_tcp_segment(
const void *data, uint16_t len, const void *data, uint16_t len,
uint8_t *buf, size_t *buflen); uint8_t *buf, size_t *buflen);
bool prepare_udp_segment4( bool prepare_udp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst, const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t ttl, uint8_t ttl,
@ -148,7 +147,7 @@ bool ip_frag(
void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl); void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl);
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport); void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport);
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); uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind);
uint32_t *tcp_find_timestamps(struct tcphdr *tcp); uint32_t *tcp_find_timestamps(struct tcphdr *tcp);
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp); uint8_t tcp_find_scale_factor(const struct tcphdr *tcp);
@ -170,7 +169,7 @@ bool rawsend_preinit(bool bind_fix4, bool bind_fix6);
#endif #endif
// auto creates internal socket and uses it for subsequent calls // 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); bool rawsend_rp(const struct rawpacket *rp);
// return trues if all packets were send successfully // return trues if all packets were send successfully
bool rawsend_queue(struct rawpacket_tailhead *q); 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 print_udphdr(const struct udphdr *udphdr);
void str_ip(char *s, size_t s_len, const struct ip *ip); 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_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_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr);
void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr); 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_MIN 3
#define AUTOTTL_DEFAULT_MAX 20 #define AUTOTTL_DEFAULT_MAX 20
#define AUTOTTL_ENABLED(a) (!!(a).delta) #define AUTOTTL_ENABLED(a) (!!(a).delta)
#define AUTOTTL_SET_DEFAULT(a) {(a).delta=AUTOTTL_DEFAULT_DELTA; (a).min=AUTOTTL_DEFAULT_MIN; (a).max=AUTOTTL_DEFAULT_MAX;} #define AUTOTTL_SET_DEFAULT(a) \
{ \
(a).delta = AUTOTTL_DEFAULT_DELTA; \
(a).min = AUTOTTL_DEFAULT_MIN; \
(a).max = AUTOTTL_DEFAULT_MAX; \
}
uint8_t autottl_guess(uint8_t ttl, const autottl *attl); uint8_t autottl_guess(uint8_t ttl, const autottl *attl);
void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6); void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6);

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -7,7 +7,6 @@
#include <ctype.h> #include <ctype.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "params.h" #include "params.h"
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit) void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
@ -19,11 +18,15 @@ void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
size = limit; size = limit;
bcut = true; bcut = true;
} }
if (!size) return; if (!size)
for (k = 0; k < size; k++) DLOG("%02X ", data[k]); return;
for (k = 0; k < size; k++)
DLOG("%02X ", data[k]);
DLOG(bcut ? "... : " : ": "); DLOG(bcut ? "... : " : ": ");
for (k = 0; k < size; k++) DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.'); for (k = 0; k < size; k++)
if (bcut) DLOG(" ..."); DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.');
if (bcut)
DLOG(" ...");
} }
char *strncasestr(const char *s, const char *find, size_t slen) char *strncasestr(const char *s, const char *find, size_t slen)
@ -38,9 +41,11 @@ char *strncasestr(const char *s, const char *find, size_t slen)
{ {
do do
{ {
if (slen-- < 1 || (sc = *s++) == '\0') return NULL; if (slen-- < 1 || (sc = *s++) == '\0')
return NULL;
} while (toupper(c) != toupper(sc)); } while (toupper(c) != toupper(sc));
if (len > slen) return NULL; if (len > slen)
return NULL;
} while (strncasecmp(s, find, len) != 0); } while (strncasecmp(s, find, len) != 0);
s--; s--;
} }
@ -52,7 +57,8 @@ bool load_file(const char *filename, void *buffer, size_t *buffer_size)
FILE *F; FILE *F;
F = fopen(filename, "rb"); F = fopen(filename, "rb");
if (!F) return false; if (!F)
return false;
*buffer_size = fread(buffer, 1, *buffer_size, F); *buffer_size = fread(buffer, 1, *buffer_size, F);
if (ferror(F)) if (ferror(F))
@ -74,7 +80,8 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size)
FILE *F; FILE *F;
F = fopen(filename, "wb"); F = fopen(filename, "wb");
if (!F) return false; if (!F)
return false;
fwrite(buffer, 1, buffer_size, F); fwrite(buffer, 1, buffer_size, F);
if (ferror(F)) if (ferror(F))
@ -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) bool append_to_list_file(const char *filename, const char *s)
{ {
FILE *F = fopen(filename,"at"); FILE *F = fopen(filename, "at");
if (!F) return false; if (!F)
bool bOK = fprintf(F,"%s\n",s)>0; return false;
bool bOK = fprintf(F, "%s\n", s) > 0;
fclose(F); fclose(F);
return bOK; return bOK;
} }
void ntop46(const struct sockaddr *sa, char *str, size_t len) void ntop46(const struct sockaddr *sa, char *str, size_t len)
{ {
if (!len) return; if (!len)
return;
*str = 0; *str = 0;
switch (sa->sa_family) switch (sa->sa_family)
{ {
case AF_INET: 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; break;
case AF_INET6: 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; break;
default: default:
snprintf(str, len, "UNKNOWN_FAMILY_%d", sa->sa_family); 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) switch (sa->sa_family)
{ {
case AF_INET: 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; break;
case AF_INET6: 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; break;
default: default:
snprintf(str, len, "%s", ip); snprintf(str, len, "%s", ip);
@ -138,41 +146,48 @@ void print_sockaddr(const struct sockaddr *sa)
bool pton4_port(const char *s, struct sockaddr_in *sa) bool pton4_port(const char *s, struct sockaddr_in *sa)
{ {
char ip[16],*p; char ip[16], *p;
size_t l; size_t l;
unsigned int u; unsigned int u;
p = strchr(s,':'); p = strchr(s, ':');
if (!p) return false; if (!p)
l = p-s; return false;
if (l<7 || l>15) return false; l = p - s;
memcpy(ip,s,l); if (l < 7 || l > 15)
ip[l]=0; return false;
memcpy(ip, s, l);
ip[l] = 0;
p++; p++;
sa->sin_family = AF_INET; sa->sin_family = AF_INET;
if (inet_pton(AF_INET,ip,&sa->sin_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false; if (inet_pton(AF_INET, ip, &sa->sin_addr) != 1 || sscanf(p, "%u", &u) != 1 || !u || u > 0xFFFF)
return false;
sa->sin_port = htons((uint16_t)u); sa->sin_port = htons((uint16_t)u);
return true; return true;
} }
bool pton6_port(const char *s, struct sockaddr_in6 *sa) bool pton6_port(const char *s, struct sockaddr_in6 *sa)
{ {
char ip[40],*p; char ip[40], *p;
size_t l; size_t l;
unsigned int u; unsigned int u;
if (*s++!='[') return false; if (*s++ != '[')
p = strchr(s,']'); return false;
if (!p || p[1]!=':') return false; p = strchr(s, ']');
l = p-s; if (!p || p[1] != ':')
if (l<2 || l>39) return false; return false;
p+=2; l = p - s;
memcpy(ip,s,l); if (l < 2 || l > 39)
ip[l]=0; return false;
p += 2;
memcpy(ip, s, l);
ip[l] = 0;
sa->sin6_family = AF_INET6; sa->sin6_family = AF_INET6;
if (inet_pton(AF_INET6,ip,&sa->sin6_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false; if (inet_pton(AF_INET6, ip, &sa->sin6_addr) != 1 || sscanf(p, "%u", &u) != 1 || !u || u > 0xFFFF)
return false;
sa->sin6_port = htons((uint16_t)u); sa->sin6_port = htons((uint16_t)u);
sa->sin6_flowinfo = 0; sa->sin6_flowinfo = 0;
sa->sin6_scope_id = 0; sa->sin6_scope_id = 0;
@ -180,7 +195,6 @@ bool pton6_port(const char *s, struct sockaddr_in6 *sa)
return true; return true;
} }
void dbgprint_socket_buffers(int fd) void dbgprint_socket_buffers(int fd)
{ {
if (params.debug) if (params.debug)
@ -216,14 +230,14 @@ bool set_socket_buffers(int fd, int rcvbuf, int sndbuf)
uint64_t pntoh64(const void *p) uint64_t pntoh64(const void *p)
{ {
return (uint64_t)*((const uint8_t *)(p)+0) << 56 | return (uint64_t) * ((const uint8_t *)(p) + 0) << 56 |
(uint64_t)*((const uint8_t *)(p)+1) << 48 | (uint64_t) * ((const uint8_t *)(p) + 1) << 48 |
(uint64_t)*((const uint8_t *)(p)+2) << 40 | (uint64_t) * ((const uint8_t *)(p) + 2) << 40 |
(uint64_t)*((const uint8_t *)(p)+3) << 32 | (uint64_t) * ((const uint8_t *)(p) + 3) << 32 |
(uint64_t)*((const uint8_t *)(p)+4) << 24 | (uint64_t) * ((const uint8_t *)(p) + 4) << 24 |
(uint64_t)*((const uint8_t *)(p)+5) << 16 | (uint64_t) * ((const uint8_t *)(p) + 5) << 16 |
(uint64_t)*((const uint8_t *)(p)+6) << 8 | (uint64_t) * ((const uint8_t *)(p) + 6) << 8 |
(uint64_t)*((const uint8_t *)(p)+7) << 0; (uint64_t) * ((const uint8_t *)(p) + 7) << 0;
} }
void phton64(uint8_t *p, uint64_t v) 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) 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) bool ipv6_addr_is_zero(const struct in6_addr *a)
{ {
return !memcmp(a,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",16); return !memcmp(a, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
} }
#define INVALID_HEX_DIGIT ((uint8_t) - 1)
#define INVALID_HEX_DIGIT ((uint8_t)-1)
static inline uint8_t parse_hex_digit(char c) static inline uint8_t parse_hex_digit(char c)
{ {
return (c>='0' && c<='9') ? c-'0' : (c>='a' && c<='f') ? c-'a'+0xA : (c>='A' && c<='F') ? c-'A'+0xA : INVALID_HEX_DIGIT; return (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 0xA
: (c >= 'A' && c <= 'F') ? c - 'A' + 0xA
: INVALID_HEX_DIGIT;
} }
static inline bool parse_hex_byte(const char *s, uint8_t *pbyte) static inline bool parse_hex_byte(const char *s, uint8_t *pbyte)
{ {
uint8_t u,l; uint8_t u, l;
u = parse_hex_digit(s[0]); u = parse_hex_digit(s[0]);
l = parse_hex_digit(s[1]); 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; return false;
} }
else else
{ {
*pbyte=(u<<4) | l; *pbyte = (u << 4) | l;
return true; return true;
} }
} }
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size) bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size)
{ {
uint8_t *pe = pbuf+*size; uint8_t *pe = pbuf + *size;
*size=0; *size = 0;
while(pbuf<pe && *s) while (pbuf < pe && *s)
{ {
if (!parse_hex_byte(s,pbuf)) if (!parse_hex_byte(s, pbuf))
return false; return false;
pbuf++; s+=2; (*size)++; pbuf++;
s += 2;
(*size)++;
} }
return true; return true;
} }
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; size_t size;
while (bufsize) while (bufsize)
{ {
size = bufsize>patsize ? patsize : bufsize; size = bufsize > patsize ? patsize : bufsize;
memcpy(buf,pattern,size); memcpy(buf, pattern, size);
buf += size; buf += size;
bufsize -= size; bufsize -= size;
} }
@ -301,66 +318,72 @@ int fprint_localtime(FILE *F)
time_t now; time_t now;
time(&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); 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) time_t file_mod_time(const char *filename)
{ {
struct stat st; 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) 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) 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++; s++;
} }
else else
pf->neg=false; pf->neg = false;
if (sscanf(s,"%u-%u",&v1,&v2)==2) if (sscanf(s, "%u-%u", &v1, &v2) == 2)
{ {
if (!v1 || v1>65535 || v2>65535 || v1>v2) return false; if (!v1 || v1 > 65535 || v2 > 65535 || v1 > v2)
pf->from=(uint16_t)v1; return false;
pf->to=(uint16_t)v2; 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; if (!v1 || v1 > 65535)
pf->to=pf->from=(uint16_t)v1; return false;
pf->to = pf->from = (uint16_t)v1;
} }
else else
return false; return false;
return true; 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; size_t k, sz16 = sz >> 1;
for(k=0;k<sz16;k++) ((uint16_t*)p)[k]=(uint16_t)random(); for (k = 0; k < sz16; k++)
if (sz & 1) p[sz-1]=(uint8_t)random(); ((uint16_t *)p)[k] = (uint16_t)random();
if (sz & 1)
p[sz - 1] = (uint8_t)random();
} }
void fill_random_az(uint8_t *p,size_t sz) void fill_random_az(uint8_t *p, size_t sz)
{ {
size_t k; size_t k;
for(k=0;k<sz;k++) p[k] = 'a'+(random() % ('z'-'a')); for (k = 0; k < sz; k++)
p[k] = 'a' + (random() % ('z' - 'a'));
} }
void fill_random_az09(uint8_t *p,size_t sz) void fill_random_az09(uint8_t *p, size_t sz)
{ {
size_t k; size_t k;
uint8_t rnd; uint8_t rnd;
for(k=0;k<sz;k++) for (k = 0; k < sz; k++)
{ {
rnd = random() % (10 + 'z'-'a'+1); rnd = random() % (10 + 'z' - 'a' + 1);
p[k] = rnd<10 ? rnd+'0' : 'a'+rnd-10; p[k] = rnd < 10 ? rnd + '0' : 'a' + rnd - 10;
} }
} }

View File

@ -10,9 +10,9 @@
#include <time.h> #include <time.h>
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit); void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit);
char *strncasestr(const char *s,const char *find, size_t slen); 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(const char *filename, void *buffer, size_t *buffer_size);
bool load_file_nonempty(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 save_file(const char *filename, const void *buffer, size_t buffer_size);
bool append_to_list_file(const char *filename, const char *s); bool append_to_list_file(const char *filename, const char *s);
@ -32,19 +32,22 @@ void phton64(uint8_t *p, uint64_t v);
bool ipv6_addr_is_zero(const struct in6_addr *a); bool ipv6_addr_is_zero(const struct in6_addr *a);
static inline uint16_t pntoh16(const uint8_t *p) { static inline uint16_t pntoh16(const uint8_t *p)
{
return ((uint16_t)p[0] << 8) | (uint16_t)p[1]; return ((uint16_t)p[0] << 8) | (uint16_t)p[1];
} }
static inline void phton16(uint8_t *p, uint16_t v) { static inline void phton16(uint8_t *p, uint16_t v)
{
p[0] = (uint8_t)(v >> 8); p[0] = (uint8_t)(v >> 8);
p[1] = v & 0xFF; p[1] = v & 0xFF;
} }
static inline uint32_t pntoh32(const uint8_t *p) { static inline uint32_t pntoh32(const uint8_t *p)
{
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3]; return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
} }
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size); 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); int fprint_localtime(FILE *F);
@ -52,12 +55,12 @@ time_t file_mod_time(const char *filename);
typedef struct typedef struct
{ {
uint16_t from,to; uint16_t from, to;
bool neg; bool neg;
} port_filter; } port_filter;
bool pf_in_range(uint16_t port, const port_filter *pf); bool pf_in_range(uint16_t port, const port_filter *pf);
bool pf_parse(const char *s, port_filter *pf); bool pf_parse(const char *s, port_filter *pf);
void fill_random_bytes(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_az(uint8_t *p, size_t sz);
void fill_random_az09(uint8_t *p,size_t sz); void fill_random_az09(uint8_t *p, size_t sz);

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -9,26 +9,30 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q)
} }
void rawpacket_free(struct rawpacket *rp) void rawpacket_free(struct rawpacket *rp)
{ {
if (rp) free(rp->packet); if (rp)
free(rp->packet);
free(rp); free(rp);
} }
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q) struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q)
{ {
struct rawpacket *rp; struct rawpacket *rp;
rp = TAILQ_FIRST(q); rp = TAILQ_FIRST(q);
if (rp) TAILQ_REMOVE(q, rp, next); if (rp)
TAILQ_REMOVE(q, rp, next);
return rp; return rp;
} }
void rawpacket_queue_destroy(struct rawpacket_tailhead *q) void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
{ {
struct rawpacket *rp; struct rawpacket *rp;
while((rp = rawpacket_dequeue(q))) rawpacket_free(rp); while ((rp = rawpacket_dequeue(q)))
rawpacket_free(rp);
} }
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len,size_t len_payload) struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q, const struct sockaddr_storage *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len, size_t len_payload)
{ {
struct rawpacket *rp = malloc(sizeof(struct rawpacket)); struct rawpacket *rp = malloc(sizeof(struct rawpacket));
if (!rp) return NULL; if (!rp)
return NULL;
rp->packet = malloc(len); rp->packet = malloc(len);
if (!rp->packet) if (!rp->packet)
@ -41,14 +45,14 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
rp->fwmark = fwmark; rp->fwmark = fwmark;
if (ifout) if (ifout)
{ {
strncpy(rp->ifout,ifout,sizeof(rp->ifout)); strncpy(rp->ifout, ifout, sizeof(rp->ifout));
rp->ifout[sizeof(rp->ifout)-1]=0; rp->ifout[sizeof(rp->ifout) - 1] = 0;
} }
else else
rp->ifout[0]=0; rp->ifout[0] = 0;
memcpy(rp->packet,data,len); memcpy(rp->packet, data, len);
rp->len=len; rp->len = len;
rp->len_payload=len_payload; rp->len_payload = len_payload;
TAILQ_INSERT_TAIL(q, rp, next); TAILQ_INSERT_TAIL(q, rp, next);
@ -58,8 +62,9 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q) unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q)
{ {
const struct rawpacket *rp; const struct rawpacket *rp;
unsigned int ct=0; unsigned int ct = 0;
TAILQ_FOREACH(rp, q, next) ct++; TAILQ_FOREACH(rp, q, next)
ct++;
return ct; return ct;
} }
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q) bool rawpacket_queue_empty(const struct rawpacket_tailhead *q)

View File

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

View File

@ -13,40 +13,39 @@ const char *progname = "nfqws";
#error UNKNOWN_SYSTEM_TIME #error UNKNOWN_SYSTEM_TIME
#endif #endif
int DLOG_FILE(FILE *F, const char *format, va_list args) int DLOG_FILE(FILE *F, const char *format, va_list args)
{ {
return vfprintf(F, format, args); return vfprintf(F, format, args);
} }
int DLOG_CON(const char *format, int syslog_priority, 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 DLOG_FILENAME(const char *filename, const char *format, va_list args)
{ {
int r; int r;
FILE *F = fopen(filename,"at"); FILE *F = fopen(filename, "at");
if (F) if (F)
{ {
r = DLOG_FILE(F, format, args); r = DLOG_FILE(F, format, args);
fclose(F); fclose(F);
} }
else else
r=-1; r = -1;
return r; return r;
} }
static char syslog_buf[1024]; 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) 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 // 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; syslog_buf_sz = 0;
} }
} }
@ -54,27 +53,27 @@ 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) static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list args)
{ {
int r=0; int r = 0;
va_list args2; 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); va_copy(args2, args);
DLOG_CON(format,syslog_priority,args2); DLOG_CON(format, syslog_priority, args2);
} }
if (params.debug) if (params.debug)
{ {
switch(params.debug_target) switch (params.debug_target)
{ {
case LOG_TARGET_CONSOLE: case LOG_TARGET_CONSOLE:
r = DLOG_CON(format,syslog_priority,args); r = DLOG_CON(format, syslog_priority, args);
break; break;
case LOG_TARGET_FILE: case LOG_TARGET_FILE:
r = DLOG_FILENAME(params.debug_logfile,format,args); r = DLOG_FILENAME(params.debug_logfile, format, args);
break; break;
case LOG_TARGET_SYSLOG: case LOG_TARGET_SYSLOG:
// skip newlines // skip newlines
syslog_buffered(syslog_priority,format,args); syslog_buffered(syslog_priority, format, args);
r = 1; r = 1;
break; break;
default: default:
@ -116,11 +115,10 @@ int DLOG_PERROR(const char *s)
return DLOG_ERR("%s: %s\n", s, strerror(errno)); return DLOG_ERR("%s: %s\n", s, strerror(errno));
} }
int LOG_APPEND(const char *filename, const char *format, va_list args) int LOG_APPEND(const char *filename, const char *format, va_list args)
{ {
int r; int r;
FILE *F = fopen(filename,"at"); FILE *F = fopen(filename, "at");
if (F) if (F)
{ {
fprint_localtime(F); fprint_localtime(F);
@ -130,7 +128,7 @@ int LOG_APPEND(const char *filename, const char *format, va_list args)
fclose(F); fclose(F);
} }
else else
r=-1; r = -1;
return r; return r;
} }

View File

@ -15,9 +15,9 @@
#define TLS_PARTIALS_ENABLE true #define TLS_PARTIALS_ENABLE true
#define Q_RCVBUF (128*1024) // in bytes #define Q_RCVBUF (128 * 1024) // in bytes
#define Q_SNDBUF (64*1024) // in bytes #define Q_SNDBUF (64 * 1024) // in bytes
#define RAW_SNDBUF (64*1024) // in bytes #define RAW_SNDBUF (64 * 1024) // in bytes
#define Q_MAXLEN 1024 // in packets #define Q_MAXLEN 1024 // in packets
@ -33,7 +33,12 @@
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 #define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3 #define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; enum log_target
{
LOG_TARGET_CONSOLE = 0,
LOG_TARGET_FILE,
LOG_TARGET_SYSLOG
};
struct params_s struct params_s
{ {
@ -41,8 +46,8 @@ struct params_s
char debug_logfile[PATH_MAX]; char debug_logfile[PATH_MAX];
bool debug; bool debug;
uint16_t wsize,wssize; uint16_t wsize, wssize;
uint8_t wscale,wsscale; uint8_t wscale, wsscale;
char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int wssize_cutoff; unsigned int wssize_cutoff;
#ifdef __linux__ #ifdef __linux__
@ -50,12 +55,12 @@ struct params_s
#elif defined(BSD) #elif defined(BSD)
uint16_t port; // divert port uint16_t port; // divert port
#endif #endif
char bind_fix4,bind_fix6; char bind_fix4, bind_fix6;
bool hostcase, hostnospace, domcase; bool hostcase, hostnospace, domcase;
char hostspell[4]; char hostspell[4];
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2; enum dpi_desync_mode desync_mode0, desync_mode, desync_mode2;
bool desync_retrans,desync_skip_nosni,desync_any_proto; 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; unsigned int desync_repeats, desync_split_pos, desync_seqovl, desync_ipfrag_pos_tcp, desync_ipfrag_pos_udp;
enum httpreqpos desync_split_http_req; enum httpreqpos desync_split_http_req;
enum tlspos desync_split_tls; enum tlspos desync_split_tls;
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence 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_fooling_mode;
uint32_t desync_fwmark; // unused in BSD uint32_t desync_fwmark; // unused in BSD
uint32_t desync_badseq_increment, desync_badseq_ack_increment; 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_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]; 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; 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; int udplen_increment;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
struct str_list_head ssid_filter,nlm_filter; struct str_list_head ssid_filter, nlm_filter;
#else #else
bool droproot; bool droproot;
uid_t uid; uid_t uid;

View File

@ -6,7 +6,8 @@
#define DESTROY_STR_POOL(etype, ppool) \ #define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \ etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) { \ HASH_ITER(hh, *ppool, elem, tmp) \
{ \
free(elem->str); \ free(elem->str); \
HASH_DEL(*ppool, elem); \ HASH_DEL(*ppool, elem); \
free(elem); \ free(elem); \
@ -14,7 +15,7 @@
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \ #define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \ etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \ if (!(elem = (etype *)malloc(sizeof(etype)))) \
return false; \ return false; \
if (!(elem->str = malloc(keystr_len + 1))) \ if (!(elem->str = malloc(keystr_len + 1))) \
{ \ { \
@ -32,7 +33,6 @@
return false; \ return false; \
} }
#undef uthash_nonfatal_oom #undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt) #define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
static bool oom = false; static bool oom = false;
@ -65,13 +65,8 @@ void StrPoolDestroy(strpool **pp)
DESTROY_STR_POOL(strpool, pp) DESTROY_STR_POOL(strpool, pp)
} }
void HostFailPoolDestroy(hostfail_pool **pp){
DESTROY_STR_POOL(hostfail_pool, pp)} hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time)
void HostFailPoolDestroy(hostfail_pool **pp)
{
DESTROY_STR_POOL(hostfail_pool, pp)
}
hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
{ {
size_t slen = strlen(s); size_t slen = strlen(s);
ADD_STR_POOL(hostfail_pool, pp, s, slen) ADD_STR_POOL(hostfail_pool, pp, s, slen)
@ -79,7 +74,7 @@ hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
elem->counter = 0; elem->counter = 0;
return elem; return elem;
} }
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s) hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s)
{ {
hostfail_pool *elem; hostfail_pool *elem;
HASH_FIND_STR(p, s, 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) void HostFailPoolPurgeRateLimited(hostfail_pool **pp)
{ {
time_t now = time(NULL); time_t now = time(NULL);
@ -120,14 +115,14 @@ void HostFailPoolDump(hostfail_pool *p)
hostfail_pool *elem, *tmp; hostfail_pool *elem, *tmp;
time_t now = time(NULL); time_t now = time(NULL);
HASH_ITER(hh, p, elem, tmp) 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) bool strlist_add(struct str_list_head *head, const char *filename)
{ {
struct str_list *entry = malloc(sizeof(struct str_list)); struct str_list *entry = malloc(sizeof(struct str_list));
if (!entry) return false; if (!entry)
return false;
entry->str = strdup(filename); entry->str = strdup(filename);
if (!entry->str) if (!entry->str)
{ {
@ -139,7 +134,8 @@ bool strlist_add(struct str_list_head *head, const char *filename)
} }
static void strlist_entry_destroy(struct str_list *entry) static void strlist_entry_destroy(struct str_list *entry)
{ {
if (entry->str) free(entry->str); if (entry->str)
free(entry->str);
free(entry); free(entry);
} }
void strlist_destroy(struct str_list_head *head) void strlist_destroy(struct str_list_head *head)

View File

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

View File

@ -7,7 +7,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <string.h> #include <string.h>
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL }; const char *http_methods[] = {"GET /", "POST /", "HEAD /", "OPTIONS /", "PUT /", "DELETE /", "CONNECT /", "TRACE /", NULL};
const char *HttpMethod(const uint8_t *data, size_t len) const char *HttpMethod(const uint8_t *data, size_t len)
{ {
const char **method; 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) bool IsHttp(const uint8_t *data, size_t len)
{ {
return !!HttpMethod(data,len); return !!HttpMethod(data, len);
} }
// pHost points to "Host: ..." // pHost points to "Host: ..."
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs) bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs)
{ {
if (!*pHost) if (!*pHost)
{ {
*pHost = memmem(buf, bs, "\nHost:", 6); *pHost = memmem(buf, bs, "\nHost:", 6);
if (*pHost) (*pHost)++; if (*pHost)
(*pHost)++;
} }
return !!*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) if (!*pHost)
{ {
*pHost = memmem(buf, bs, "\nHost:", 6); *pHost = memmem(buf, bs, "\nHost:", 6);
if (*pHost) (*pHost)++; if (*pHost)
(*pHost)++;
} }
return !!*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) bool IsHttpReply(const uint8_t *data, size_t len)
{ {
// HTTP/1.x 200\r\n // HTTP/1.x 200\r\n
return len>14 && !memcmp(data,"HTTP/1.",7) && (data[7]=='0' || data[7]=='1') && data[8]==' ' && return len > 14 && !memcmp(data, "HTTP/1.", 7) && (data[7] == '0' || data[7] == '1') && data[8] == ' ' &&
data[9]>='0' && data[9]<='9' && data[9] >= '0' && data[9] <= '9' &&
data[10]>='0' && data[10]<='9' && data[10] >= '0' && data[10] <= '9' &&
data[11]>='0' && data[11]<='9'; data[11] >= '0' && data[11] <= '9';
} }
int HttpReplyCode(const uint8_t *data, size_t len) 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) 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; const uint8_t *p, *s, *e = data + len;
p = (uint8_t*)strncasestr((char*)data, header, len); p = (uint8_t *)strncasestr((char *)data, header, len);
if (!p) return false; if (!p)
return false;
p += strlen(header); p += strlen(header);
while (p < e && (*p == ' ' || *p == '\t')) p++; while (p < e && (*p == ' ' || *p == '\t'))
p++;
s = p; s = p;
while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t')) s++; while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t'))
s++;
if (s > p) if (s > p)
{ {
size_t slen = s - p; size_t slen = s - p;
if (buf && len_buf) if (buf && len_buf)
{ {
if (slen >= len_buf) slen = len_buf - 1; if (slen >= len_buf)
for (size_t i = 0; i < slen; i++) buf[i] = tolower(p[i]); slen = len_buf - 1;
for (size_t i = 0; i < slen; i++)
buf[i] = tolower(p[i]);
buf[slen] = 0; buf[slen] = 0;
} }
return true; return true;
@ -85,41 +92,49 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
} }
const char *HttpFind2ndLevelDomain(const char *host) const char *HttpFind2ndLevelDomain(const char *host)
{ {
const char *p=NULL; const char *p = NULL;
if (*host) if (*host)
{ {
for (p = host + strlen(host)-1; p>host && *p!='.'; p--); for (p = host + strlen(host) - 1; p > host && *p != '.'; p--)
if (*p=='.') for (p--; p>host && *p!='.'; p--); ;
if (*p=='.') p++; if (*p == '.')
for (p--; p > host && *p != '.'; p--)
;
if (*p == '.')
p++;
} }
return p; return p;
} }
// DPI redirects are global redirects to another domain // DPI redirects are global redirects to another domain
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host) 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; int code;
if (!host || !*host) return false; if (!host || !*host)
return false;
code = HttpReplyCode(data,len); code = HttpReplyCode(data, len);
if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false; if ((code != 302 && code != 307) || !HttpExtractHeader(data, len, "\nLocation:", loc, sizeof(loc)))
return false;
// something like : https://censor.net/badpage.php?reason=denied&source=RKN // something like : https://censor.net/badpage.php?reason=denied&source=RKN
if (!strncmp(loc,"http://",7)) if (!strncmp(loc, "http://", 7))
redirect_host=loc+7; redirect_host = loc + 7;
else if (!strncmp(loc,"https://",8)) else if (!strncmp(loc, "https://", 8))
redirect_host=loc+8; redirect_host = loc + 8;
else else
return false; return false;
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN // somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
for(p=redirect_host; *p && *p!='/' ; p++); for (p = redirect_host; *p && *p != '/'; p++)
*p=0; ;
if (!*redirect_host) return false; *p = 0;
if (!*redirect_host)
return false;
// somethinkg like : censor.net // somethinkg like : censor.net
@ -128,30 +143,37 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
const char *dhost = HttpFind2ndLevelDomain(host); const char *dhost = HttpFind2ndLevelDomain(host);
const char *drhost = HttpFind2ndLevelDomain(redirect_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) size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
{ {
const uint8_t *method, *host; const uint8_t *method, *host;
int i; int i;
switch(tpos_type) switch (tpos_type)
{ {
case httpreqpos_method: case httpreqpos_method:
// recognize some tpws pre-applied hacks // recognize some tpws pre-applied hacks
method=http; method = http;
if (sz<10) break; if (sz < 10)
if (*method=='\n' || *method=='\r') method++; break;
if (*method=='\n' || *method=='\r') method++; if (*method == '\n' || *method == '\r')
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++; method++;
if (i<3 || *method!=' ') break; if (*method == '\n' || *method == '\r')
return method-http-1; 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: case httpreqpos_host:
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz) if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
{ {
host+=5; host += 5;
if (*host==' ') host++; if (*host == ' ')
return host-http; host++;
return host - http;
} }
break; break;
case httpreqpos_pos: case httpreqpos_pos:
@ -159,10 +181,9 @@ size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http,
default: default:
return 0; return 0;
} }
return hpos_pos<sz ? hpos_pos : 0; return hpos_pos < sz ? hpos_pos : 0;
} }
uint16_t TLSRecordDataLen(const uint8_t *data) uint16_t TLSRecordDataLen(const uint8_t *data)
{ {
return pntoh16(data + 3); return pntoh16(data + 3);
@ -173,7 +194,7 @@ size_t TLSRecordLen(const uint8_t *data)
} }
bool IsTLSRecordFull(const uint8_t *data, size_t len) 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) 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) 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) bool IsTLSHandshakeFull(const uint8_t *data, size_t len)
{ {
return (4+TLSHandshakeLen(data))<=len; return (4 + TLSHandshakeLen(data)) <= len;
} }
// bPartialIsOK=true - accept partial packets not containing the whole TLS message // bPartialIsOK=true - accept partial packets not containing the whole TLS message
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK) bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK)
{ {
@ -212,40 +232,51 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
size_t l; size_t l;
if (!bPartialIsOK && !IsTLSHandshakeFull(data,len)) return false; if (!bPartialIsOK && !IsTLSHandshakeFull(data, len))
return false;
l = 1 + 3 + 2 + 32; l = 1 + 3 + 2 + 32;
// SessionIDLength // SessionIDLength
if (len < (l + 1)) return false; if (len < (l + 1))
return false;
l += data[l] + 1; l += data[l] + 1;
// CipherSuitesLength // CipherSuitesLength
if (len < (l + 2)) return false; if (len < (l + 2))
return false;
l += pntoh16(data + l) + 2; l += pntoh16(data + l) + 2;
// CompressionMethodsLength // CompressionMethodsLength
if (len < (l + 1)) return false; if (len < (l + 1))
return false;
l += data[l] + 1; l += data[l] + 1;
// ExtensionsLength // ExtensionsLength
if (len < (l + 2)) return false; if (len < (l + 2))
return false;
data += l; len -= l; data += l;
len -= l;
l = pntoh16(data); l = pntoh16(data);
data += 2; len -= 2; data += 2;
len -= 2;
if (bPartialIsOK) if (bPartialIsOK)
{ {
if (len < l) l = len; if (len < l)
l = len;
} }
else else
{ {
if (len < l) return false; if (len < l)
return false;
} }
while (l >= 4) while (l >= 4)
{ {
uint16_t etype = pntoh16(data); uint16_t etype = pntoh16(data);
size_t elen = pntoh16(data + 2); size_t elen = pntoh16(data + 2);
data += 4; l -= 4; data += 4;
if (l < elen) break; l -= 4;
if (l < elen)
break;
if (etype == type) if (etype == type)
{ {
if (ext && len_ext) if (ext && len_ext)
@ -255,7 +286,8 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
} }
return true; return true;
} }
data += elen; l -= elen; data += elen;
l -= elen;
} }
return false; return false;
@ -267,9 +299,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
// u16 Version: TLS1.0 // u16 Version: TLS1.0
// u16 Length // u16 Length
size_t reclen; size_t reclen;
if (!IsTLSClientHello(data, len, bPartialIsOK)) return false; if (!IsTLSClientHello(data, len, bPartialIsOK))
reclen=TLSRecordLen(data); return false;
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has 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); return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
} }
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host) static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
@ -277,14 +311,19 @@ static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, s
// u16 data+0 - name list length // u16 data+0 - name list length
// u8 data+2 - server name type. 0=host_name // u8 data+2 - server name type. 0=host_name
// u16 data+3 - server name length // u16 data+3 - server name length
if (elen < 5 || ext[2] != 0) return false; if (elen < 5 || ext[2] != 0)
return false;
size_t slen = pntoh16(ext + 3); size_t slen = pntoh16(ext + 3);
ext += 5; elen -= 5; ext += 5;
if (slen < elen) return false; elen -= 5;
if (slen < elen)
return false;
if (host && len_host) if (host && len_host)
{ {
if (slen >= len_host) slen = len_host - 1; if (slen >= len_host)
for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]); slen = len_host - 1;
for (size_t i = 0; i < slen; i++)
host[i] = tolower(ext[i]);
host[slen] = 0; host[slen] = 0;
} }
return true; return true;
@ -294,7 +333,8 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len
const uint8_t *ext; const uint8_t *ext;
size_t elen; size_t elen;
if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK)) return false; if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK))
return false;
return TLSExtractHostFromExt(ext, elen, host, len_host); return TLSExtractHostFromExt(ext, elen, host, len_host);
} }
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK) bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK)
@ -302,48 +342,52 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
const uint8_t *ext; const uint8_t *ext;
size_t elen; size_t elen;
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false; if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK))
return false;
return TLSExtractHostFromExt(ext, elen, host, len_host); return TLSExtractHostFromExt(ext, elen, host, len_host);
} }
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type) size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
{ {
size_t elen; size_t elen;
const uint8_t *ext; const uint8_t *ext;
switch(tpos_type) switch (tpos_type)
{ {
case tlspos_sni: case tlspos_sni:
case tlspos_sniext: case tlspos_sniext:
if (TLSFindExt(tls,sz,0,&ext,&elen,false)) if (TLSFindExt(tls, sz, 0, &ext, &elen, false))
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1; return (tpos_type == tlspos_sni) ? ext - tls + 6 : ext - tls + 1;
// fall through // fall through
case tlspos_pos: case tlspos_pos:
return tpos_pos<sz ? tpos_pos : 0; return tpos_pos < sz ? tpos_pos : 0;
default: default:
return 0; return 0;
} }
} }
static uint8_t tvb_get_varint(const uint8_t *tvb, uint64_t *value) static uint8_t tvb_get_varint(const uint8_t *tvb, uint64_t *value)
{ {
switch (*tvb >> 6) switch (*tvb >> 6)
{ {
case 0: /* 0b00 => 1 byte length (6 bits Usable) */ case 0: /* 0b00 => 1 byte length (6 bits Usable) */
if (value) *value = *tvb & 0x3F; if (value)
*value = *tvb & 0x3F;
return 1; return 1;
case 1: /* 0b01 => 2 bytes length (14 bits Usable) */ case 1: /* 0b01 => 2 bytes length (14 bits Usable) */
if (value) *value = pntoh16(tvb) & 0x3FFF; if (value)
*value = pntoh16(tvb) & 0x3FFF;
return 2; return 2;
case 2: /* 0b10 => 4 bytes length (30 bits Usable) */ case 2: /* 0b10 => 4 bytes length (30 bits Usable) */
if (value) *value = pntoh32(tvb) & 0x3FFFFFFF; if (value)
*value = pntoh32(tvb) & 0x3FFFFFFF;
return 4; return 4;
case 3: /* 0b11 => 8 bytes length (62 bits Usable) */ case 3: /* 0b11 => 8 bytes length (62 bits Usable) */
if (value) *value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF; if (value)
*value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF;
return 8; return 8;
} }
// impossible case // impossible case
if (*value) *value = 0; if (*value)
*value = 0;
return 0; return 0;
} }
static uint8_t tvb_get_size(uint8_t tvb) static uint8_t tvb_get_size(uint8_t tvb)
@ -355,15 +399,21 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
{ {
size_t offset = 1; size_t offset = 1;
uint64_t coff, clen; uint64_t coff, clen;
if (len < 3 || *data != 6) return false; if (len < 3 || *data != 6)
if ((offset+tvb_get_size(data[offset])) >= len) return false; return false;
if ((offset + tvb_get_size(data[offset])) >= len)
return false;
offset += tvb_get_varint(data + offset, &coff); offset += tvb_get_varint(data + offset, &coff);
// offset must be 0 if it's a full segment, not just a chunk // offset must be 0 if it's a full segment, not just a chunk
if (coff || (offset+tvb_get_size(data[offset])) >= len) return false; if (coff || (offset + tvb_get_size(data[offset])) >= len)
return false;
offset += tvb_get_varint(data + offset, &clen); offset += tvb_get_varint(data + offset, &clen);
if ((offset + clen) > len || !IsTLSHandshakeClientHello(data+offset,clen)) return false; if ((offset + clen) > len || !IsTLSHandshakeClientHello(data + offset, clen))
if (hello_offset) *hello_offset = offset; return false;
if (hello_len) *hello_len = (size_t)clen; if (hello_offset)
*hello_offset = offset;
if (hello_len)
*hello_len = (size_t)clen;
return true; return true;
} }
@ -371,22 +421,26 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
uint8_t QUICDraftVersion(uint32_t version) uint8_t QUICDraftVersion(uint32_t version)
{ {
/* IETF Draft versions */ /* IETF Draft versions */
if ((version >> 8) == 0xff0000) { if ((version >> 8) == 0xff0000)
{
return (uint8_t)version; return (uint8_t)version;
} }
/* Facebook mvfst, based on draft -22. */ /* Facebook mvfst, based on draft -22. */
if (version == 0xfaceb001) { if (version == 0xfaceb001)
{
return 22; return 22;
} }
/* Facebook mvfst, based on draft -27. */ /* Facebook mvfst, based on draft -27. */
if (version == 0xfaceb002 || version == 0xfaceb00e) { if (version == 0xfaceb002 || version == 0xfaceb00e)
{
return 27; return 27;
} }
/* GQUIC Q050, T050 and T051: they are not really based on any drafts, /* GQUIC Q050, T050 and T051: they are not really based on any drafts,
* but we must return a sensible value */ * but we must return a sensible value */
if (version == 0x51303530 || if (version == 0x51303530 ||
version == 0x54303530 || version == 0x54303530 ||
version == 0x54303531) { version == 0x54303531)
{
return 27; return 27;
} }
/* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15 /* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15
@ -396,17 +450,20 @@ uint8_t QUICDraftVersion(uint32_t version)
used to select a proper salt (which depends on the version itself), but used to select a proper salt (which depends on the version itself), but
we don't have a real version here! Let's hope that we need to handle we don't have a real version here! Let's hope that we need to handle
only latest drafts... */ only latest drafts... */
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) { if ((version & 0x0F0F0F0F) == 0x0a0a0a0a)
{
return 29; return 29;
} }
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the /* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
final draft version */ final draft version */
if (version == 0x00000001) { if (version == 0x00000001)
{
return 34; return 34;
} }
/* QUIC Version 2 */ /* QUIC Version 2 */
/* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */ /* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */
if (version == 0x709A50C4) { if (version == 0x709A50C4)
{
return 100; return 100;
} }
return 0; return 0;
@ -426,9 +483,11 @@ static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, co
uint8_t hkdflabel[64]; uint8_t hkdflabel[64];
size_t label_size = strlen(label); size_t label_size = strlen(label);
if (label_size > 255) return false; if (label_size > 255)
return false;
size_t hkdflabel_size = 2 + 1 + label_size + 1; size_t hkdflabel_size = 2 + 1 + label_size + 1;
if (hkdflabel_size > sizeof(hkdflabel)) return false; if (hkdflabel_size > sizeof(hkdflabel))
return false;
phton16(hkdflabel, out_len); phton16(hkdflabel, out_len);
hkdflabel[2] = (uint8_t)label_size; hkdflabel[2] = (uint8_t)label_size;
@ -454,69 +513,89 @@ static bool quic_derive_initial_secret(const quic_cid_t *cid, uint8_t *client_in
*/ */
static const uint8_t handshake_salt_draft_22[20] = { static const uint8_t handshake_salt_draft_22[20] = {
0x7f, 0xbc, 0xdb, 0x0e, 0x7c, 0x66, 0xbb, 0xe9, 0x19, 0x3a, 0x7f, 0xbc, 0xdb, 0x0e, 0x7c, 0x66, 0xbb, 0xe9, 0x19, 0x3a,
0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a 0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a};
};
static const uint8_t handshake_salt_draft_23[20] = { static const uint8_t handshake_salt_draft_23[20] = {
0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xc3,
0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02, 0xee,
0xf7,
0x12,
0xc7,
0x2e,
0xbb,
0x5a,
0x11,
0xa7,
0xd2,
0x43,
0x2b,
0xb4,
0x63,
0x65,
0xbe,
0xf9,
0xf5,
0x02,
}; };
static const uint8_t handshake_salt_draft_29[20] = { static const uint8_t handshake_salt_draft_29[20] = {
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97,
0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99};
};
static const uint8_t handshake_salt_v1[20] = { static const uint8_t handshake_salt_v1[20] = {
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17,
0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a};
};
static const uint8_t hanshake_salt_draft_q50[20] = { static const uint8_t hanshake_salt_draft_q50[20] = {
0x50, 0x45, 0x74, 0xEF, 0xD0, 0x66, 0xFE, 0x2F, 0x9D, 0x94, 0x50, 0x45, 0x74, 0xEF, 0xD0, 0x66, 0xFE, 0x2F, 0x9D, 0x94,
0x5C, 0xFC, 0xDB, 0xD3, 0xA7, 0xF0, 0xD3, 0xB5, 0x6B, 0x45 0x5C, 0xFC, 0xDB, 0xD3, 0xA7, 0xF0, 0xD3, 0xB5, 0x6B, 0x45};
};
static const uint8_t hanshake_salt_draft_t50[20] = { static const uint8_t hanshake_salt_draft_t50[20] = {
0x7f, 0xf5, 0x79, 0xe5, 0xac, 0xd0, 0x72, 0x91, 0x55, 0x80, 0x7f, 0xf5, 0x79, 0xe5, 0xac, 0xd0, 0x72, 0x91, 0x55, 0x80,
0x30, 0x4c, 0x43, 0xa2, 0x36, 0x7c, 0x60, 0x48, 0x83, 0x10 0x30, 0x4c, 0x43, 0xa2, 0x36, 0x7c, 0x60, 0x48, 0x83, 0x10};
};
static const uint8_t hanshake_salt_draft_t51[20] = { static const uint8_t hanshake_salt_draft_t51[20] = {
0x7a, 0x4e, 0xde, 0xf4, 0xe7, 0xcc, 0xee, 0x5f, 0xa4, 0x50, 0x7a, 0x4e, 0xde, 0xf4, 0xe7, 0xcc, 0xee, 0x5f, 0xa4, 0x50,
0x6c, 0x19, 0x12, 0x4f, 0xc8, 0xcc, 0xda, 0x6e, 0x03, 0x3d 0x6c, 0x19, 0x12, 0x4f, 0xc8, 0xcc, 0xda, 0x6e, 0x03, 0x3d};
};
static const uint8_t handshake_salt_v2[20] = { static const uint8_t handshake_salt_v2[20] = {
0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93,
0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9};
};
int err; int err;
const uint8_t *salt; const uint8_t *salt;
uint8_t secret[USHAMaxHashSize]; uint8_t secret[USHAMaxHashSize];
uint8_t draft_version = QUICDraftVersion(version); uint8_t draft_version = QUICDraftVersion(version);
if (version == 0x51303530) { if (version == 0x51303530)
{
salt = hanshake_salt_draft_q50; salt = hanshake_salt_draft_q50;
} }
else if (version == 0x54303530) { else if (version == 0x54303530)
{
salt = hanshake_salt_draft_t50; salt = hanshake_salt_draft_t50;
} }
else if (version == 0x54303531) { else if (version == 0x54303531)
{
salt = hanshake_salt_draft_t51; salt = hanshake_salt_draft_t51;
} }
else if (is_quic_draft_max(draft_version, 22)) { else if (is_quic_draft_max(draft_version, 22))
{
salt = handshake_salt_draft_22; salt = handshake_salt_draft_22;
} }
else if (is_quic_draft_max(draft_version, 28)) { else if (is_quic_draft_max(draft_version, 28))
{
salt = handshake_salt_draft_23; salt = handshake_salt_draft_23;
} }
else if (is_quic_draft_max(draft_version, 32)) { else if (is_quic_draft_max(draft_version, 32))
{
salt = handshake_salt_draft_29; salt = handshake_salt_draft_29;
} }
else if (is_quic_draft_max(draft_version, 34)) { else if (is_quic_draft_max(draft_version, 34))
{
salt = handshake_salt_v1; salt = handshake_salt_v1;
} }
else { else
{
salt = handshake_salt_v2; salt = handshake_salt_v2;
} }
err = hkdfExtract(SHA256, salt, 20, cid->cid, cid->len, secret); err = hkdfExtract(SHA256, salt, 20, cid->cid, cid->len, secret);
if (err) return false; if (err)
return false;
if (client_initial_secret && !quic_hkdf_expand_label(secret, SHA256HashSize, "tls13 client in", client_initial_secret, SHA256HashSize)) if (client_initial_secret && !quic_hkdf_expand_label(secret, SHA256HashSize, "tls13 client in", client_initial_secret, SHA256HashSize))
return false; return false;
@ -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) 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) uint32_t QUICExtractVersion(const uint8_t *data, size_t len)
{ {
// long header, fixed bit, type=initial // 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) bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid)
{ {
if (!QUICIsLongHeader(data,len) || !data[5] || data[5] > QUIC_MAX_CID_LENGTH || (6+data[5])>len) return false; if (!QUICIsLongHeader(data, len) || !data[5] || data[5] > QUIC_MAX_CID_LENGTH || (6 + data[5]) > len)
return false;
cid->len = data[5]; cid->len = data[5];
memcpy(&cid->cid, data + 6, data[5]); memcpy(&cid->cid, data + 6, data[5]);
return true; return true;
@ -542,13 +622,16 @@ bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid)
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len) bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len)
{ {
uint32_t ver = QUICExtractVersion(data, data_len); uint32_t ver = QUICExtractVersion(data, data_len);
if (!ver) return false; if (!ver)
return false;
quic_cid_t dcid; quic_cid_t dcid;
if (!QUICExtractDCID(data, data_len, &dcid)) return false; if (!QUICExtractDCID(data, data_len, &dcid))
return false;
uint8_t client_initial_secret[SHA256HashSize]; uint8_t client_initial_secret[SHA256HashSize];
if (!quic_derive_initial_secret(&dcid, client_initial_secret, ver)) return false; if (!quic_derive_initial_secret(&dcid, client_initial_secret, ver))
return false;
uint8_t aeskey[16], aesiv[12], aeshp[16]; uint8_t aeskey[16], aesiv[12], aeshp[16];
bool v1_label = !is_quic_v2(ver); bool v1_label = !is_quic_v2(ver);
@ -559,23 +642,28 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
return false; return false;
} }
uint64_t payload_len,token_len; uint64_t payload_len, token_len;
size_t pn_offset; size_t pn_offset;
pn_offset = 1 + 4 + 1 + data[5]; pn_offset = 1 + 4 + 1 + data[5];
if (pn_offset >= data_len) return false; if (pn_offset >= data_len)
return false;
pn_offset += 1 + data[pn_offset]; pn_offset += 1 + data[pn_offset];
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false; if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len)
return false;
pn_offset += tvb_get_varint(data + pn_offset, &token_len); pn_offset += tvb_get_varint(data + pn_offset, &token_len);
pn_offset += token_len; pn_offset += token_len;
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false; if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len)
return false;
pn_offset += tvb_get_varint(data + pn_offset, &payload_len); pn_offset += tvb_get_varint(data + pn_offset, &payload_len);
if (payload_len<20 || (pn_offset + payload_len)>data_len) return false; if (payload_len < 20 || (pn_offset + payload_len) > data_len)
return false;
aes_init_keygen_tables(); aes_init_keygen_tables();
uint8_t sample_enc[16]; uint8_t sample_enc[16];
aes_context ctx; aes_context ctx;
if (aes_setkey(&ctx, 1, aeshp, sizeof(aeshp)) || aes_cipher(&ctx, data + pn_offset + 4, sample_enc)) return false; if (aes_setkey(&ctx, 1, aeshp, sizeof(aeshp)) || aes_cipher(&ctx, data + pn_offset + 4, sample_enc))
return false;
uint8_t mask[5]; uint8_t mask[5];
memcpy(mask, sample_enc, sizeof(mask)); memcpy(mask, sample_enc, sizeof(mask));
@ -586,21 +674,25 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
uint8_t pkn_bytes[4]; uint8_t pkn_bytes[4];
memcpy(pkn_bytes, data + pn_offset, pkn_len); memcpy(pkn_bytes, data + pn_offset, pkn_len);
uint32_t pkn = 0; uint32_t pkn = 0;
for (uint8_t i = 0; i < pkn_len; i++) pkn |= (uint32_t)(pkn_bytes[i] ^ mask[1 + i]) << (8 * (pkn_len - 1 - i)); for (uint8_t i = 0; i < pkn_len; i++)
pkn |= (uint32_t)(pkn_bytes[i] ^ mask[1 + i]) << (8 * (pkn_len - 1 - i));
phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn); phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn);
size_t cryptlen = payload_len - pkn_len - 16; size_t cryptlen = payload_len - pkn_len - 16;
if (cryptlen > *clean_len) return false; if (cryptlen > *clean_len)
return false;
*clean_len = cryptlen; *clean_len = cryptlen;
const uint8_t *decrypt_begin = data + pn_offset + pkn_len; const uint8_t *decrypt_begin = data + pn_offset + pkn_len;
uint8_t atag[16],header[256]; uint8_t atag[16], header[256];
size_t header_len = pn_offset + pkn_len; size_t header_len = pn_offset + pkn_len;
if (header_len > sizeof(header)) return false; // not likely header will be so large if (header_len > sizeof(header))
return false; // not likely header will be so large
memcpy(header, data, header_len); memcpy(header, data, header_len);
header[0] = packet0; header[0] = packet0;
for(uint8_t i = 0; i < pkn_len; i++) header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i)); for (uint8_t i = 0; i < pkn_len; i++)
header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i));
if (aes_gcm_crypt(AES_DECRYPT, clean, decrypt_begin, cryptlen, aeskey, sizeof(aeskey), aesiv, sizeof(aesiv), header, header_len, atag, sizeof(atag))) if (aes_gcm_crypt(AES_DECRYPT, clean, decrypt_begin, cryptlen, aeskey, sizeof(aeskey), aesiv, sizeof(aesiv), header, header_len, atag, sizeof(atag)))
return false; return false;
@ -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); 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 // Crypto frame can be split into multiple chunks
// chromium randomly splits it and pads with zero/one bytes to force support the standard // chromium randomly splits it and pads with zero/one bytes to force support the standard
// mozilla does not split // mozilla does not split
if (*defrag_len<10) return false; if (*defrag_len < 10)
uint8_t *defrag_data = defrag+10; return false;
size_t defrag_data_len = *defrag_len-10; uint8_t *defrag_data = defrag + 10;
size_t defrag_data_len = *defrag_len - 10;
uint8_t ft; uint8_t ft;
uint64_t offset,sz,szmax=0,zeropos=0,pos=0; uint64_t offset, sz, szmax = 0, zeropos = 0, pos = 0;
bool found=false; bool found = false;
while(pos<clean_len) while (pos < clean_len)
{ {
ft = clean[pos]; ft = clean[pos];
pos++; pos++;
if (ft>1) // 00 - padding, 01 - ping if (ft > 1) // 00 - padding, 01 - ping
{ {
if (ft!=6) return false; // dont want to know all possible frame type formats if (ft != 6)
return false; // don't want to know all possible frame type formats
if (pos>=clean_len) return false; if (pos >= clean_len)
return false;
if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false; if ((pos + tvb_get_size(clean[pos]) >= clean_len))
pos += tvb_get_varint(clean+pos, &offset); return false;
pos += tvb_get_varint(clean + pos, &offset);
if ((pos+tvb_get_size(clean[pos])>clean_len)) return false; if ((pos + tvb_get_size(clean[pos]) > clean_len))
pos += tvb_get_varint(clean+pos, &sz); return false;
if ((pos+sz)>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) if (zeropos < offset)
// make sure no uninitialized gaps exist in case of not full fragment coverage // make sure no uninitialized gaps exist in case of not full fragment coverage
memset(defrag_data+zeropos,0,offset-zeropos); memset(defrag_data + zeropos, 0, offset - zeropos);
if ((offset+sz) > zeropos) if ((offset + sz) > zeropos)
zeropos=offset+sz; zeropos = offset + sz;
memcpy(defrag_data+offset,clean+pos,sz); memcpy(defrag_data + offset, clean + pos, sz);
if ((offset+sz) > szmax) szmax = offset+sz; if ((offset + sz) > szmax)
szmax = offset + sz;
found=true; found = true;
pos+=sz; pos += sz;
} }
} }
if (found) if (found)
@ -659,31 +759,38 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
defrag[1] = 0; // offset defrag[1] = 0; // offset
// 2..9 - length 64 bit // 2..9 - length 64 bit
// +10 - data start // +10 - data start
phton64(defrag+2,szmax); phton64(defrag + 2, szmax);
defrag[2] |= 0xC0; // 64 bit value defrag[2] |= 0xC0; // 64 bit value
*defrag_len = (size_t)(szmax+10); *defrag_len = (size_t)(szmax + 10);
} }
return found; return found;
} }
bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello) bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello)
{ {
if (bIsCryptoHello) *bIsCryptoHello=false; if (bIsCryptoHello)
if (bDecryptOK) *bDecryptOK=false; *bIsCryptoHello = false;
if (bDecryptOK)
*bDecryptOK = false;
uint8_t clean[1500]; uint8_t clean[1500];
size_t clean_len = sizeof(clean); size_t clean_len = sizeof(clean);
if (!QUICDecryptInitial(data,data_len,clean,&clean_len)) return false; if (!QUICDecryptInitial(data, data_len, clean, &clean_len))
return false;
if (bDecryptOK) *bDecryptOK=true; if (bDecryptOK)
*bDecryptOK = true;
uint8_t defrag[1500]; uint8_t defrag[1500];
size_t defrag_len = sizeof(defrag); size_t defrag_len = sizeof(defrag);
if (!QUICDefragCrypto(clean,clean_len,defrag,&defrag_len)) return false; if (!QUICDefragCrypto(clean, clean_len, defrag, &defrag_len))
return false;
size_t hello_offset, hello_len; size_t hello_offset, hello_len;
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len)) return false; if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len))
if (bIsCryptoHello) *bIsCryptoHello=true; return false;
if (bIsCryptoHello)
*bIsCryptoHello = true;
return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, true); return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, true);
} }
@ -692,47 +799,53 @@ bool IsQUICInitial(const uint8_t *data, size_t len)
{ {
// too small packets are not likely to be initials with client hello // too small packets are not likely to be initials with client hello
// long header, fixed bit // long header, fixed bit
if (len < 256 || (data[0] & 0xC0)!=0xC0) return false; if (len < 256 || (data[0] & 0xC0) != 0xC0)
return false;
uint32_t ver = QUICExtractVersion(data,len); uint32_t ver = QUICExtractVersion(data, len);
if (QUICDraftVersion(ver) < 11) return false; if (QUICDraftVersion(ver) < 11)
return false;
// quic v1 : initial packets are 00b // QUIC v1 : initial packets are 00b
// quic v2 : initial packets are 01b // QUIC v2 : initial packets are 01b
if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00)) return false; if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00))
return false;
uint64_t offset=5, sz; uint64_t offset = 5, sz;
// DCID. must be present // DCID. must be present
if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH) return false; if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH)
return false;
offset += 1 + data[offset]; offset += 1 + data[offset];
// SCID // SCID
if (data[offset] > QUIC_MAX_CID_LENGTH) return false; if (data[offset] > QUIC_MAX_CID_LENGTH)
return false;
offset += 1 + data[offset]; offset += 1 + data[offset];
// token length // token length
offset += tvb_get_varint(data + offset, &sz); offset += tvb_get_varint(data + offset, &sz);
offset += sz; offset += sz;
if (offset >= len) return false; if (offset >= len)
return false;
// payload length // payload length
if ((offset + tvb_get_size(data[offset])) > len) return false; if ((offset + tvb_get_size(data[offset])) > len)
return false;
tvb_get_varint(data + offset, &sz); tvb_get_varint(data + offset, &sz);
offset += sz; offset += sz;
if (offset > len) return false; if (offset > len)
return false;
// client hello cannot be too small. likely ACK // ClientHello cannot be too small. likely ACK
return sz>=96; return sz >= 96;
} }
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len) bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len)
{ {
return len==148 && data[0]==1 && data[1]==0 && data[2]==0 && data[3]==0; return len == 148 && data[0] == 1 && data[1] == 0 && data[2] == 0 && data[3] == 0;
} }
bool IsDhtD1(const uint8_t *data, size_t len) bool IsDhtD1(const uint8_t *data, size_t len)
{ {
return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e'; return len >= 7 && data[0] == 'd' && data[1] == '1' && data[len - 1] == 'e';
} }

View File

@ -10,8 +10,8 @@
extern const char *http_methods[9]; extern const char *http_methods[9];
const char *HttpMethod(const uint8_t *data, size_t len); const char *HttpMethod(const uint8_t *data, size_t len);
bool IsHttp(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 HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs);
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);
// header must be passed like this : "\nHost:" // 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 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); 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); int HttpReplyCode(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply // must be pre-checked by IsHttpReply
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host); bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
enum httpreqpos { httpreqpos_none = 0, httpreqpos_method, httpreqpos_host, httpreqpos_pos }; enum httpreqpos
{
httpreqpos_none = 0,
httpreqpos_method,
httpreqpos_host,
httpreqpos_pos
};
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz); size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz);
uint16_t TLSRecordDataLen(const uint8_t *data); uint16_t TLSRecordDataLen(const uint8_t *data);
@ -35,14 +41,21 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK); bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK); bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK); bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_pos }; enum tlspos
{
tlspos_none = 0,
tlspos_sni,
tlspos_sniext,
tlspos_pos
};
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type); size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len); bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
bool IsDhtD1(const uint8_t *data, size_t len); bool IsDhtD1(const uint8_t *data, size_t len);
#define QUIC_MAX_CID_LENGTH 20 #define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid { typedef struct quic_cid
{
uint8_t len; uint8_t len;
uint8_t cid[QUIC_MAX_CID_LENGTH]; uint8_t cid[QUIC_MAX_CID_LENGTH];
} quic_cid_t; } quic_cid_t;
@ -55,5 +68,5 @@ uint8_t QUICDraftVersion(uint32_t version);
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid); bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid);
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len); bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len);
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); bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);

162
nfq/sec.c
View File

@ -25,128 +25,127 @@
// block most of the undesired syscalls to harden against code execution // block most of the undesired syscalls to harden against code execution
static long blocked_syscalls[] = { static long blocked_syscalls[] = {
#ifdef SYS_execv #ifdef SYS_execv
SYS_execv, SYS_execv,
#endif #endif
SYS_execve, SYS_execve,
#ifdef SYS_execveat #ifdef SYS_execveat
SYS_execveat, SYS_execveat,
#endif #endif
#ifdef SYS_exec_with_loader #ifdef SYS_exec_with_loader
SYS_exec_with_loader, SYS_exec_with_loader,
#endif #endif
#ifdef SYS_clone #ifdef SYS_clone
SYS_clone, SYS_clone,
#endif #endif
#ifdef SYS_clone2 #ifdef SYS_clone2
SYS_clone2, SYS_clone2,
#endif #endif
#ifdef SYS_clone3 #ifdef SYS_clone3
SYS_clone3, SYS_clone3,
#endif #endif
#ifdef SYS_osf_execve #ifdef SYS_osf_execve
SYS_osf_execve, SYS_osf_execve,
#endif #endif
#ifdef SYS_fork #ifdef SYS_fork
SYS_fork, SYS_fork,
#endif #endif
#ifdef SYS_vfork #ifdef SYS_vfork
SYS_vfork, SYS_vfork,
#endif #endif
#ifdef SYS_uselib #ifdef SYS_uselib
SYS_uselib, SYS_uselib,
#endif #endif
#ifdef SYS_unlink #ifdef SYS_unlink
SYS_unlink, SYS_unlink,
#endif #endif
SYS_unlinkat, SYS_unlinkat,
#ifdef SYS_chmod #ifdef SYS_chmod
SYS_chmod, SYS_chmod,
#endif #endif
SYS_fchmod,SYS_fchmodat, SYS_fchmod, SYS_fchmodat,
#ifdef SYS_chown #ifdef SYS_chown
SYS_chown, SYS_chown,
#endif #endif
#ifdef SYS_chown32 #ifdef SYS_chown32
SYS_chown32, SYS_chown32,
#endif #endif
SYS_fchown, SYS_fchown,
#ifdef SYS_fchown32 #ifdef SYS_fchown32
SYS_fchown32, SYS_fchown32,
#endif #endif
#ifdef SYS_lchown #ifdef SYS_lchown
SYS_lchown, SYS_lchown,
#endif #endif
#ifdef SYS_lchown32 #ifdef SYS_lchown32
SYS_lchown32, SYS_lchown32,
#endif #endif
SYS_fchownat, SYS_fchownat,
#ifdef SYS_symlink #ifdef SYS_symlink
SYS_symlink, SYS_symlink,
#endif #endif
SYS_symlinkat, SYS_symlinkat,
#ifdef SYS_link #ifdef SYS_link
SYS_link, SYS_link,
#endif #endif
SYS_linkat, SYS_linkat,
#ifdef SYS_pkey_mprotect #ifdef SYS_pkey_mprotect
SYS_pkey_mprotect, SYS_pkey_mprotect,
#endif #endif
SYS_mprotect, SYS_mprotect,
SYS_truncate, SYS_truncate,
#ifdef SYS_truncate64 #ifdef SYS_truncate64
SYS_truncate64, SYS_truncate64,
#endif #endif
SYS_ftruncate, SYS_ftruncate,
#ifdef SYS_ftruncate64 #ifdef SYS_ftruncate64
SYS_ftruncate64, SYS_ftruncate64,
#endif #endif
#ifdef SYS_mknod #ifdef SYS_mknod
SYS_mknod, SYS_mknod,
#endif #endif
SYS_mknodat, SYS_mknodat,
#ifdef SYS_mkdir #ifdef SYS_mkdir
SYS_mkdir, SYS_mkdir,
#endif #endif
SYS_mkdirat, SYS_mkdirat,
#ifdef SYS_rmdir #ifdef SYS_rmdir
SYS_rmdir, SYS_rmdir,
#endif #endif
#ifdef SYS_rename #ifdef SYS_rename
SYS_rename, SYS_rename,
#endif #endif
#ifdef SYS_renameat2 #ifdef SYS_renameat2
SYS_renameat2, SYS_renameat2,
#endif #endif
#ifdef SYS_renameat #ifdef SYS_renameat
SYS_renameat, SYS_renameat,
#endif #endif
#ifdef SYS_readdir #ifdef SYS_readdir
SYS_readdir, SYS_readdir,
#endif #endif
#ifdef SYS_getdents #ifdef SYS_getdents
SYS_getdents, SYS_getdents,
#endif #endif
#ifdef SYS_getdents64 #ifdef SYS_getdents64
SYS_getdents64, SYS_getdents64,
#endif #endif
#ifdef SYS_process_vm_readv #ifdef SYS_process_vm_readv
SYS_process_vm_readv, SYS_process_vm_readv,
#endif #endif
#ifdef SYS_process_vm_writev #ifdef SYS_process_vm_writev
SYS_process_vm_writev, SYS_process_vm_writev,
#endif #endif
#ifdef SYS_process_madvise #ifdef SYS_process_madvise
SYS_process_madvise, SYS_process_madvise,
#endif #endif
#ifdef SYS_tkill #ifdef SYS_tkill
SYS_tkill, SYS_tkill,
#endif #endif
#ifdef SYS_tgkill #ifdef SYS_tgkill
SYS_tgkill, SYS_tgkill,
#endif #endif
SYS_kill, SYS_ptrace SYS_kill, SYS_ptrace};
}; #define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls))
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls))
static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k) static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k)
{ {
@ -159,13 +158,13 @@ static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf,
static bool set_seccomp(void) static bool set_seccomp(void)
{ {
#ifdef __X32_SYSCALL_BIT #ifdef __X32_SYSCALL_BIT
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT) #define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
#else #else
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT) #define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
#endif #endif
struct sock_filter sockf[SECCOMP_PROG_SIZE]; struct sock_filter sockf[SECCOMP_PROG_SIZE];
struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE, .filter = sockf }; struct sock_fprog prog = {.len = SECCOMP_PROG_SIZE, .filter = sockf};
int i,idx=0; int i, idx = 0;
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr); set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr);
#ifdef __X32_SYSCALL_BIT #ifdef __X32_SYSCALL_BIT
@ -178,16 +177,16 @@ static bool set_seccomp(void)
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr);
#endif #endif
/* /*
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr // ! 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_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_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_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 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++) 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_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
@ -201,30 +200,29 @@ bool sec_harden(void)
DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)"); DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)");
return false; return false;
} }
#if ARCH_NR!=0 #if ARCH_NR != 0
if (!set_seccomp()) if (!set_seccomp())
{ {
DLOG_PERROR("seccomp"); DLOG_PERROR("seccomp");
if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n"); if (errno == EINVAL)
DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
return false; return false;
} }
#endif #endif
return true; return true;
} }
bool checkpcap(uint64_t caps) bool checkpcap(uint64_t caps)
{ {
if (!caps) return true; // no special caps reqd if (!caps)
return true; // no special caps reqd
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()}; struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
struct __user_cap_data_struct cd[2]; struct __user_cap_data_struct cd[2];
uint32_t c0 = (uint32_t)caps; 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) bool setpcap(uint64_t caps)
{ {
@ -233,10 +231,10 @@ bool setpcap(uint64_t caps)
cd[0].effective = cd[0].permitted = (uint32_t)caps; cd[0].effective = cd[0].permitted = (uint32_t)caps;
cd[0].inheritable = 0; 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; cd[1].inheritable = 0;
return !capset(&ch,cd); return !capset(&ch, cd);
} }
int getmaxcap(void) int getmaxcap(void)
{ {
@ -248,18 +246,17 @@ int getmaxcap(void)
fclose(F); fclose(F);
} }
return maxcap; return maxcap;
} }
bool dropcaps(void) 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(); int maxcap = getmaxcap();
if (setpcap(caps|(1<<CAP_SETPCAP))) if (setpcap(caps | (1 << CAP_SETPCAP)))
{ {
for (int cap = 0; cap <= maxcap; cap++) 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_ERR("could not drop bound cap %d\n", cap);
DLOG_PERROR("cap_drop_bound"); DLOG_PERROR("cap_drop_bound");
@ -291,7 +288,7 @@ bool can_drop_root(void)
{ {
#ifdef __linux__ #ifdef __linux__
// has some caps // 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 #else
// effective root // effective root
return !geteuid(); return !geteuid();
@ -308,7 +305,7 @@ bool droproot(uid_t uid, gid_t gid)
} }
#endif #endif
// drop all SGIDs // drop all SGIDs
if (setgroups(0,NULL)) if (setgroups(0, NULL))
{ {
DLOG_PERROR("setgroups"); DLOG_PERROR("setgroups");
return false; return false;
@ -332,24 +329,23 @@ bool droproot(uid_t uid, gid_t gid)
void print_id(void) void print_id(void)
{ {
int i,N; int i, N;
gid_t g[128]; gid_t g[128];
DLOG_CONDUP("Running as UID=%u GID=",getuid()); DLOG_CONDUP("Running as UID=%u GID=", getuid());
N=getgroups(sizeof(g)/sizeof(*g),g); N = getgroups(sizeof(g) / sizeof(*g), g);
if (N>0) if (N > 0)
{ {
for(i=0;i<N;i++) for (i = 0; i < N; i++)
DLOG_CONDUP(i==(N-1) ? "%u" : "%u,", g[i]); DLOG_CONDUP(i == (N - 1) ? "%u" : "%u,", g[i]);
DLOG_CONDUP("\n"); DLOG_CONDUP("\n");
} }
else else
DLOG_CONDUP("%u\n",getgid()); DLOG_CONDUP("%u\n", getgid());
} }
#endif #endif
void daemonize(void) void daemonize(void)
{ {
int pid; int pid;

View File

@ -20,67 +20,66 @@ bool dropcaps(void);
#if defined(__aarch64__) #if defined(__aarch64__)
# define ARCH_NR AUDIT_ARCH_AARCH64 #define ARCH_NR AUDIT_ARCH_AARCH64
#elif defined(__amd64__) #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__)) #elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__))
# if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_ARM #define ARCH_NR AUDIT_ARCH_ARM
# else #else
# define ARCH_NR AUDIT_ARCH_ARMEB #define ARCH_NR AUDIT_ARCH_ARMEB
# endif #endif
#elif defined(__i386__) #elif defined(__i386__)
# define ARCH_NR AUDIT_ARCH_I386 #define ARCH_NR AUDIT_ARCH_I386
#elif defined(__mips__) #elif defined(__mips__)
#if _MIPS_SIM == _MIPS_SIM_ABI32 #if _MIPS_SIM == _MIPS_SIM_ABI32
# if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_MIPSEL #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
#else #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 #endif
#elif defined(__PPC64__) #elif defined(__PPC64__)
# if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_PPC64LE #define ARCH_NR AUDIT_ARCH_PPC64LE
# else #else
# define ARCH_NR AUDIT_ARCH_PPC64 #define ARCH_NR AUDIT_ARCH_PPC64
# endif #endif
#elif defined(__PPC__) #elif defined(__PPC__)
# define ARCH_NR AUDIT_ARCH_PPC #define ARCH_NR AUDIT_ARCH_PPC
#elif __riscv && __riscv_xlen == 64 #elif __riscv && __riscv_xlen == 64
# define ARCH_NR AUDIT_ARCH_RISCV64 #define ARCH_NR AUDIT_ARCH_RISCV64
#else #else
# error "Platform does not support seccomp filter yet" #error "Platform does not support seccomp filter yet"
#endif #endif
#endif #endif
#ifndef __CYGWIN__ #ifndef __CYGWIN__
bool sec_harden(void); bool sec_harden(void);
bool can_drop_root(void); bool can_drop_root(void);

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,7 @@ bool service_run(int argc, char *argv[])
{ {
SERVICE_TABLE_ENTRY ServiceTable[] = { SERVICE_TABLE_ENTRY ServiceTable[] = {
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main}, {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main},
{NULL, NULL} {NULL, NULL}};
};
service_argc = argc; service_argc = argc;
service_argv = argv; service_argv = argv;
@ -76,5 +75,4 @@ void service_main(int argc __attribute__((unused)), char *argv[] __attribute__((
return; return;
} }
#endif #endif

View File

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

View File

@ -62,39 +62,41 @@
#endif /* __MINGW32__ */ #endif /* __MINGW32__ */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
/****************************************************************************/ /****************************************************************************/
/* WINDIVERT API */ /* WINDIVERT API */
/****************************************************************************/ /****************************************************************************/
/* /*
* WinDivert layers. * WinDivert layers.
*/ */
typedef enum typedef enum
{ {
WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */ WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */
WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */ WINDIVERT_LAYER_NETWORK_FORWARD = 1, /* Network layer (forwarded packets) */
WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */ WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */ WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */
WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */ WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */
} WINDIVERT_LAYER, *PWINDIVERT_LAYER; } WINDIVERT_LAYER,
*PWINDIVERT_LAYER;
/* /*
* WinDivert NETWORK and NETWORK_FORWARD layer data. * WinDivert NETWORK and NETWORK_FORWARD layer data.
*/ */
typedef struct typedef struct
{ {
UINT32 IfIdx; /* Packet's interface index. */ UINT32 IfIdx; /* Packet's interface index. */
UINT32 SubIfIdx; /* Packet's sub-interface index. */ UINT32 SubIfIdx; /* Packet's sub-interface index. */
} WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK; } WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK;
/* /*
* WinDivert FLOW layer data. * WinDivert FLOW layer data.
*/ */
typedef struct typedef struct
{ {
UINT64 EndpointId; /* Endpoint ID. */ UINT64 EndpointId; /* Endpoint ID. */
UINT64 ParentEndpointId; /* Parent endpoint ID. */ UINT64 ParentEndpointId; /* Parent endpoint ID. */
UINT32 ProcessId; /* Process ID. */ UINT32 ProcessId; /* Process ID. */
@ -103,13 +105,13 @@ typedef struct
UINT16 LocalPort; /* Local port. */ UINT16 LocalPort; /* Local port. */
UINT16 RemotePort; /* Remote port. */ UINT16 RemotePort; /* Remote port. */
UINT8 Protocol; /* Protocol. */ UINT8 Protocol; /* Protocol. */
} WINDIVERT_DATA_FLOW, *PWINDIVERT_DATA_FLOW; } WINDIVERT_DATA_FLOW, *PWINDIVERT_DATA_FLOW;
/* /*
* WinDivert SOCKET layer data. * WinDivert SOCKET layer data.
*/ */
typedef struct typedef struct
{ {
UINT64 EndpointId; /* Endpoint ID. */ UINT64 EndpointId; /* Endpoint ID. */
UINT64 ParentEndpointId; /* Parent Endpoint ID. */ UINT64 ParentEndpointId; /* Parent Endpoint ID. */
UINT32 ProcessId; /* Process ID. */ UINT32 ProcessId; /* Process ID. */
@ -118,41 +120,41 @@ typedef struct
UINT16 LocalPort; /* Local port. */ UINT16 LocalPort; /* Local port. */
UINT16 RemotePort; /* Remote port. */ UINT16 RemotePort; /* Remote port. */
UINT8 Protocol; /* Protocol. */ UINT8 Protocol; /* Protocol. */
} WINDIVERT_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET; } WINDIVERT_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET;
/* /*
* WinDivert REFLECTION layer data. * WinDivert REFLECTION layer data.
*/ */
typedef struct typedef struct
{ {
INT64 Timestamp; /* Handle open time. */ INT64 Timestamp; /* Handle open time. */
UINT32 ProcessId; /* Handle process ID. */ UINT32 ProcessId; /* Handle process ID. */
WINDIVERT_LAYER Layer; /* Handle layer. */ WINDIVERT_LAYER Layer; /* Handle layer. */
UINT64 Flags; /* Handle flags. */ UINT64 Flags; /* Handle flags. */
INT16 Priority; /* Handle priority. */ INT16 Priority; /* Handle priority. */
} WINDIVERT_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT; } WINDIVERT_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT;
/* /*
* WinDivert address. * WinDivert address.
*/ */
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4201) #pragma warning(disable : 4201)
#endif #endif
typedef struct typedef struct
{ {
INT64 Timestamp; /* Packet's timestamp. */ INT64 Timestamp; /* Packet's timestamp. */
UINT32 Layer:8; /* Packet's layer. */ UINT32 Layer : 8; /* Packet's layer. */
UINT32 Event:8; /* Packet event. */ UINT32 Event : 8; /* Packet event. */
UINT32 Sniffed:1; /* Packet was sniffed? */ UINT32 Sniffed : 1; /* Packet was sniffed? */
UINT32 Outbound:1; /* Packet is outound? */ UINT32 Outbound : 1; /* Packet is outound? */
UINT32 Loopback:1; /* Packet is loopback? */ UINT32 Loopback : 1; /* Packet is loopback? */
UINT32 Impostor:1; /* Packet is impostor? */ UINT32 Impostor : 1; /* Packet is impostor? */
UINT32 IPv6:1; /* Packet is IPv6? */ UINT32 IPv6 : 1; /* Packet is IPv6? */
UINT32 IPChecksum:1; /* Packet has valid IPv4 checksum? */ UINT32 IPChecksum : 1; /* Packet has valid IPv4 checksum? */
UINT32 TCPChecksum:1; /* Packet has valid TCP checksum? */ UINT32 TCPChecksum : 1; /* Packet has valid TCP checksum? */
UINT32 UDPChecksum:1; /* Packet has valid UDP checksum? */ UINT32 UDPChecksum : 1; /* Packet has valid UDP checksum? */
UINT32 Reserved1:8; UINT32 Reserved1 : 8;
UINT32 Reserved2; UINT32 Reserved2;
union union
{ {
@ -162,16 +164,16 @@ typedef struct
WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */ WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */
UINT8 Reserved3[64]; UINT8 Reserved3[64];
}; };
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS; } WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif #endif
/* /*
* WinDivert events. * WinDivert events.
*/ */
typedef enum typedef enum
{ {
WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */ WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */
WINDIVERT_EVENT_FLOW_ESTABLISHED = 1, WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
/* Flow established. */ /* Flow established. */
@ -183,7 +185,8 @@ typedef enum
WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */ WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */
WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */ WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */
WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */ WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT; } WINDIVERT_EVENT,
*PWINDIVERT_EVENT;
/* /*
* WinDivert flags. * WinDivert flags.
@ -197,55 +200,57 @@ typedef enum
#define WINDIVERT_FLAG_NO_INSTALL 0x0010 #define WINDIVERT_FLAG_NO_INSTALL 0x0010
#define WINDIVERT_FLAG_FRAGMENTS 0x0020 #define WINDIVERT_FLAG_FRAGMENTS 0x0020
/* /*
* WinDivert parameters. * WinDivert parameters.
*/ */
typedef enum typedef enum
{ {
WINDIVERT_PARAM_QUEUE_LENGTH = 0, /* Packet queue length. */ WINDIVERT_PARAM_QUEUE_LENGTH = 0, /* Packet queue length. */
WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */ WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */
WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */ WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */
WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */ WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */
WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */ WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */
} WINDIVERT_PARAM, *PWINDIVERT_PARAM; } WINDIVERT_PARAM,
*PWINDIVERT_PARAM;
#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR #define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR
/* /*
* WinDivert shutdown parameter. * WinDivert shutdown parameter.
*/ */
typedef enum typedef enum
{ {
WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */ WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */
WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */ WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */
WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */ WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */
} WINDIVERT_SHUTDOWN, *PWINDIVERT_SHUTDOWN; } WINDIVERT_SHUTDOWN,
*PWINDIVERT_SHUTDOWN;
#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH #define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH
#ifndef WINDIVERT_KERNEL #ifndef WINDIVERT_KERNEL
/* /*
* Open a WinDivert handle. * Open a WinDivert handle.
*/ */
WINDIVERTEXPORT HANDLE WinDivertOpen( WINDIVERTEXPORT HANDLE WinDivertOpen(
__in const char *filter, __in const char *filter,
__in WINDIVERT_LAYER layer, __in WINDIVERT_LAYER layer,
__in INT16 priority, __in INT16 priority,
__in UINT64 flags); __in UINT64 flags);
/* /*
* Receive (read) a packet from a WinDivert handle. * Receive (read) a packet from a WinDivert handle.
*/ */
WINDIVERTEXPORT BOOL WinDivertRecv( WINDIVERTEXPORT BOOL WinDivertRecv(
__in HANDLE handle, __in HANDLE handle,
__out_opt VOID *pPacket, __out_opt VOID *pPacket,
__in UINT packetLen, __in UINT packetLen,
__out_opt UINT *pRecvLen, __out_opt UINT *pRecvLen,
__out_opt WINDIVERT_ADDRESS *pAddr); __out_opt WINDIVERT_ADDRESS *pAddr);
/* /*
* Receive (read) a packet from a WinDivert handle. * Receive (read) a packet from a WinDivert handle.
*/ */
WINDIVERTEXPORT BOOL WinDivertRecvEx( WINDIVERTEXPORT BOOL WinDivertRecvEx(
__in HANDLE handle, __in HANDLE handle,
__out_opt VOID *pPacket, __out_opt VOID *pPacket,
__in UINT packetLen, __in UINT packetLen,
@ -255,20 +260,20 @@ WINDIVERTEXPORT BOOL WinDivertRecvEx(
__inout_opt UINT *pAddrLen, __inout_opt UINT *pAddrLen,
__inout_opt LPOVERLAPPED lpOverlapped); __inout_opt LPOVERLAPPED lpOverlapped);
/* /*
* Send (write/inject) a packet to a WinDivert handle. * Send (write/inject) a packet to a WinDivert handle.
*/ */
WINDIVERTEXPORT BOOL WinDivertSend( WINDIVERTEXPORT BOOL WinDivertSend(
__in HANDLE handle, __in HANDLE handle,
__in const VOID *pPacket, __in const VOID *pPacket,
__in UINT packetLen, __in UINT packetLen,
__out_opt UINT *pSendLen, __out_opt UINT *pSendLen,
__in const WINDIVERT_ADDRESS *pAddr); __in const WINDIVERT_ADDRESS *pAddr);
/* /*
* Send (write/inject) a packet to a WinDivert handle. * Send (write/inject) a packet to a WinDivert handle.
*/ */
WINDIVERTEXPORT BOOL WinDivertSendEx( WINDIVERTEXPORT BOOL WinDivertSendEx(
__in HANDLE handle, __in HANDLE handle,
__in const VOID *pPacket, __in const VOID *pPacket,
__in UINT packetLen, __in UINT packetLen,
@ -278,31 +283,31 @@ WINDIVERTEXPORT BOOL WinDivertSendEx(
__in UINT addrLen, __in UINT addrLen,
__inout_opt LPOVERLAPPED lpOverlapped); __inout_opt LPOVERLAPPED lpOverlapped);
/* /*
* Shutdown a WinDivert handle. * Shutdown a WinDivert handle.
*/ */
WINDIVERTEXPORT BOOL WinDivertShutdown( WINDIVERTEXPORT BOOL WinDivertShutdown(
__in HANDLE handle, __in HANDLE handle,
__in WINDIVERT_SHUTDOWN how); __in WINDIVERT_SHUTDOWN how);
/* /*
* Close a WinDivert handle. * Close a WinDivert handle.
*/ */
WINDIVERTEXPORT BOOL WinDivertClose( WINDIVERTEXPORT BOOL WinDivertClose(
__in HANDLE handle); __in HANDLE handle);
/* /*
* Set a WinDivert handle parameter. * Set a WinDivert handle parameter.
*/ */
WINDIVERTEXPORT BOOL WinDivertSetParam( WINDIVERTEXPORT BOOL WinDivertSetParam(
__in HANDLE handle, __in HANDLE handle,
__in WINDIVERT_PARAM param, __in WINDIVERT_PARAM param,
__in UINT64 value); __in UINT64 value);
/* /*
* Get a WinDivert handle parameter. * Get a WinDivert handle parameter.
*/ */
WINDIVERTEXPORT BOOL WinDivertGetParam( WINDIVERTEXPORT BOOL WinDivertGetParam(
__in HANDLE handle, __in HANDLE handle,
__in WINDIVERT_PARAM param, __in WINDIVERT_PARAM param,
__out UINT64 *pValue); __out UINT64 *pValue);
@ -326,22 +331,22 @@ WINDIVERTEXPORT BOOL WinDivertGetParam(
#define WINDIVERT_BATCH_MAX 0xFF /* 255 */ #define WINDIVERT_BATCH_MAX 0xFF /* 255 */
#define WINDIVERT_MTU_MAX (40 + 0xFFFF) #define WINDIVERT_MTU_MAX (40 + 0xFFFF)
/****************************************************************************/ /****************************************************************************/
/* WINDIVERT HELPER API */ /* WINDIVERT HELPER API */
/****************************************************************************/ /****************************************************************************/
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4214) #pragma warning(disable : 4214)
#endif #endif
/* /*
* IPv4/IPv6/ICMP/ICMPv6/TCP/UDP header definitions. * IPv4/IPv6/ICMP/ICMPv6/TCP/UDP header definitions.
*/ */
typedef struct typedef struct
{ {
UINT8 HdrLength:4; UINT8 HdrLength : 4;
UINT8 Version:4; UINT8 Version : 4;
UINT8 TOS; UINT8 TOS;
UINT16 Length; UINT16 Length;
UINT16 Id; UINT16 Id;
@ -351,7 +356,7 @@ typedef struct
UINT16 Checksum; UINT16 Checksum;
UINT32 SrcAddr; UINT32 SrcAddr;
UINT32 DstAddr; UINT32 DstAddr;
} WINDIVERT_IPHDR, *PWINDIVERT_IPHDR; } WINDIVERT_IPHDR, *PWINDIVERT_IPHDR;
#define WINDIVERT_IPHDR_GET_FRAGOFF(hdr) \ #define WINDIVERT_IPHDR_GET_FRAGOFF(hdr) \
(((hdr)->FragOff0) & 0xFF1F) (((hdr)->FragOff0) & 0xFF1F)
@ -367,43 +372,39 @@ typedef struct
{ \ { \
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \ (hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \
((val) & 0xFF1F); \ ((val) & 0xFF1F); \
} \ } while (FALSE)
while (FALSE)
#define WINDIVERT_IPHDR_SET_MF(hdr, val) \ #define WINDIVERT_IPHDR_SET_MF(hdr, val) \
do \ do \
{ \ { \
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \ (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \
(((val) & 0x0001) << 5); \ (((val) & 0x0001) << 5); \
} \ } while (FALSE)
while (FALSE)
#define WINDIVERT_IPHDR_SET_DF(hdr, val) \ #define WINDIVERT_IPHDR_SET_DF(hdr, val) \
do \ do \
{ \ { \
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \ (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \
(((val) & 0x0001) << 6); \ (((val) & 0x0001) << 6); \
} \ } while (FALSE)
while (FALSE)
#define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \ #define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \
do \ do \
{ \ { \
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \ (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \
(((val) & 0x0001) << 7); \ (((val) & 0x0001) << 7); \
} \ } while (FALSE)
while (FALSE)
typedef struct typedef struct
{ {
UINT8 TrafficClass0:4; UINT8 TrafficClass0 : 4;
UINT8 Version:4; UINT8 Version : 4;
UINT8 FlowLabel0:4; UINT8 FlowLabel0 : 4;
UINT8 TrafficClass1:4; UINT8 TrafficClass1 : 4;
UINT16 FlowLabel1; UINT16 FlowLabel1;
UINT16 Length; UINT16 Length;
UINT8 NextHdr; UINT8 NextHdr;
UINT8 HopLimit; UINT8 HopLimit;
UINT32 SrcAddr[4]; UINT32 SrcAddr[4];
UINT32 DstAddr[4]; UINT32 DstAddr[4];
} WINDIVERT_IPV6HDR, *PWINDIVERT_IPV6HDR; } WINDIVERT_IPV6HDR, *PWINDIVERT_IPV6HDR;
#define WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(hdr) \ #define WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(hdr) \
((((hdr)->TrafficClass0) << 4) | ((hdr)->TrafficClass1)) ((((hdr)->TrafficClass0) << 4) | ((hdr)->TrafficClass1))
@ -415,59 +416,57 @@ typedef struct
{ \ { \
(hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \ (hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \
(hdr)->TrafficClass1 = (UINT8)(val); \ (hdr)->TrafficClass1 = (UINT8)(val); \
} \ } while (FALSE)
while (FALSE)
#define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \ #define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \
do \ do \
{ \ { \
(hdr)->FlowLabel0 = (UINT8)((val) >> 16); \ (hdr)->FlowLabel0 = (UINT8)((val) >> 16); \
(hdr)->FlowLabel1 = (UINT16)(val); \ (hdr)->FlowLabel1 = (UINT16)(val); \
} \ } while (FALSE)
while (FALSE)
typedef struct typedef struct
{ {
UINT8 Type; UINT8 Type;
UINT8 Code; UINT8 Code;
UINT16 Checksum; UINT16 Checksum;
UINT32 Body; UINT32 Body;
} WINDIVERT_ICMPHDR, *PWINDIVERT_ICMPHDR; } WINDIVERT_ICMPHDR, *PWINDIVERT_ICMPHDR;
typedef struct typedef struct
{ {
UINT8 Type; UINT8 Type;
UINT8 Code; UINT8 Code;
UINT16 Checksum; UINT16 Checksum;
UINT32 Body; UINT32 Body;
} WINDIVERT_ICMPV6HDR, *PWINDIVERT_ICMPV6HDR; } WINDIVERT_ICMPV6HDR, *PWINDIVERT_ICMPV6HDR;
typedef struct typedef struct
{ {
UINT16 SrcPort; UINT16 SrcPort;
UINT16 DstPort; UINT16 DstPort;
UINT32 SeqNum; UINT32 SeqNum;
UINT32 AckNum; UINT32 AckNum;
UINT16 Reserved1:4; UINT16 Reserved1 : 4;
UINT16 HdrLength:4; UINT16 HdrLength : 4;
UINT16 Fin:1; UINT16 Fin : 1;
UINT16 Syn:1; UINT16 Syn : 1;
UINT16 Rst:1; UINT16 Rst : 1;
UINT16 Psh:1; UINT16 Psh : 1;
UINT16 Ack:1; UINT16 Ack : 1;
UINT16 Urg:1; UINT16 Urg : 1;
UINT16 Reserved2:2; UINT16 Reserved2 : 2;
UINT16 Window; UINT16 Window;
UINT16 Checksum; UINT16 Checksum;
UINT16 UrgPtr; UINT16 UrgPtr;
} WINDIVERT_TCPHDR, *PWINDIVERT_TCPHDR; } WINDIVERT_TCPHDR, *PWINDIVERT_TCPHDR;
typedef struct typedef struct
{ {
UINT16 SrcPort; UINT16 SrcPort;
UINT16 DstPort; UINT16 DstPort;
UINT16 Length; UINT16 Length;
UINT16 Checksum; UINT16 Checksum;
} WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR; } WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@ -484,22 +483,22 @@ typedef struct
#ifndef WINDIVERT_KERNEL #ifndef WINDIVERT_KERNEL
/* /*
* Hash a packet. * Hash a packet.
*/ */
WINDIVERTEXPORT UINT64 WinDivertHelperHashPacket( WINDIVERTEXPORT UINT64 WinDivertHelperHashPacket(
__in const VOID *pPacket, __in const VOID *pPacket,
__in UINT packetLen, __in UINT packetLen,
__in UINT64 seed __in UINT64 seed
#ifdef __cplusplus #ifdef __cplusplus
= 0 = 0
#endif #endif
); );
/* /*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet. * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperParsePacket( WINDIVERTEXPORT BOOL WinDivertHelperParsePacket(
__in const VOID *pPacket, __in const VOID *pPacket,
__in UINT packetLen, __in UINT packetLen,
__out_opt PWINDIVERT_IPHDR *ppIpHdr, __out_opt PWINDIVERT_IPHDR *ppIpHdr,
@ -514,56 +513,56 @@ WINDIVERTEXPORT BOOL WinDivertHelperParsePacket(
__out_opt PVOID *ppNext, __out_opt PVOID *ppNext,
__out_opt UINT *pNextLen); __out_opt UINT *pNextLen);
/* /*
* Parse an IPv4 address. * Parse an IPv4 address.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperParseIPv4Address( WINDIVERTEXPORT BOOL WinDivertHelperParseIPv4Address(
__in const char *addrStr, __in const char *addrStr,
__out_opt UINT32 *pAddr); __out_opt UINT32 *pAddr);
/* /*
* Parse an IPv6 address. * Parse an IPv6 address.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address( WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address(
__in const char *addrStr, __in const char *addrStr,
__out_opt UINT32 *pAddr); __out_opt UINT32 *pAddr);
/* /*
* Format an IPv4 address. * Format an IPv4 address.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address( WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address(
__in UINT32 addr, __in UINT32 addr,
__out char *buffer, __out char *buffer,
__in UINT bufLen); __in UINT bufLen);
/* /*
* Format an IPv6 address. * Format an IPv6 address.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address( WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address(
__in const UINT32 *pAddr, __in const UINT32 *pAddr,
__out char *buffer, __out char *buffer,
__in UINT bufLen); __in UINT bufLen);
/* /*
* Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums. * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperCalcChecksums( WINDIVERTEXPORT BOOL WinDivertHelperCalcChecksums(
__inout VOID *pPacket, __inout VOID *pPacket,
__in UINT packetLen, __in UINT packetLen,
__out_opt WINDIVERT_ADDRESS *pAddr, __out_opt WINDIVERT_ADDRESS *pAddr,
__in UINT64 flags); __in UINT64 flags);
/* /*
* Decrement the TTL/HopLimit. * Decrement the TTL/HopLimit.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperDecrementTTL( WINDIVERTEXPORT BOOL WinDivertHelperDecrementTTL(
__inout VOID *pPacket, __inout VOID *pPacket,
__in UINT packetLen); __in UINT packetLen);
/* /*
* Compile the given filter string. * Compile the given filter string.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter( WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter(
__in const char *filter, __in const char *filter,
__in WINDIVERT_LAYER layer, __in WINDIVERT_LAYER layer,
__out_opt char *object, __out_opt char *object,
@ -571,53 +570,53 @@ WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter(
__out_opt const char **errorStr, __out_opt const char **errorStr,
__out_opt UINT *errorPos); __out_opt UINT *errorPos);
/* /*
* Evaluate the given filter string. * Evaluate the given filter string.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter( WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter(
__in const char *filter, __in const char *filter,
__in const VOID *pPacket, __in const VOID *pPacket,
__in UINT packetLen, __in UINT packetLen,
__in const WINDIVERT_ADDRESS *pAddr); __in const WINDIVERT_ADDRESS *pAddr);
/* /*
* Format the given filter string. * Format the given filter string.
*/ */
WINDIVERTEXPORT BOOL WinDivertHelperFormatFilter( WINDIVERTEXPORT BOOL WinDivertHelperFormatFilter(
__in const char *filter, __in const char *filter,
__in WINDIVERT_LAYER layer, __in WINDIVERT_LAYER layer,
__out char *buffer, __out char *buffer,
__in UINT bufLen); __in UINT bufLen);
/* /*
* Byte ordering. * Byte ordering.
*/ */
WINDIVERTEXPORT UINT16 WinDivertHelperNtohs( WINDIVERTEXPORT UINT16 WinDivertHelperNtohs(
__in UINT16 x); __in UINT16 x);
WINDIVERTEXPORT UINT16 WinDivertHelperHtons( WINDIVERTEXPORT UINT16 WinDivertHelperHtons(
__in UINT16 x); __in UINT16 x);
WINDIVERTEXPORT UINT32 WinDivertHelperNtohl( WINDIVERTEXPORT UINT32 WinDivertHelperNtohl(
__in UINT32 x); __in UINT32 x);
WINDIVERTEXPORT UINT32 WinDivertHelperHtonl( WINDIVERTEXPORT UINT32 WinDivertHelperHtonl(
__in UINT32 x); __in UINT32 x);
WINDIVERTEXPORT UINT64 WinDivertHelperNtohll( WINDIVERTEXPORT UINT64 WinDivertHelperNtohll(
__in UINT64 x); __in UINT64 x);
WINDIVERTEXPORT UINT64 WinDivertHelperHtonll( WINDIVERTEXPORT UINT64 WinDivertHelperHtonll(
__in UINT64 x); __in UINT64 x);
WINDIVERTEXPORT void WinDivertHelperNtohIPv6Address( WINDIVERTEXPORT void WinDivertHelperNtohIPv6Address(
__in const UINT *inAddr, __in const UINT *inAddr,
__out UINT *outAddr); __out UINT *outAddr);
WINDIVERTEXPORT void WinDivertHelperHtonIPv6Address( WINDIVERTEXPORT void WinDivertHelperHtonIPv6Address(
__in const UINT *inAddr, __in const UINT *inAddr,
__out UINT *outAddr); __out UINT *outAddr);
/* /*
* Old names to be removed in the next version. * Old names to be removed in the next version.
*/ */
WINDIVERTEXPORT void WinDivertHelperNtohIpv6Address( WINDIVERTEXPORT void WinDivertHelperNtohIpv6Address(
__in const UINT *inAddr, __in const UINT *inAddr,
__out UINT *outAddr); __out UINT *outAddr);
WINDIVERTEXPORT void WinDivertHelperHtonIpv6Address( WINDIVERTEXPORT void WinDivertHelperHtonIpv6Address(
__in const UINT *inAddr, __in const UINT *inAddr,
__out UINT *outAddr); __out UINT *outAddr);

View File

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

View File

@ -22,10 +22,12 @@
// all supported FreeBSD versions. // all supported FreeBSD versions.
#ifndef timespecsub #ifndef timespecsub
#define timespecsub(tsp, usp, vsp) \ #define timespecsub(tsp, usp, vsp) \
do { \ do \
{ \
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
if ((vsp)->tv_nsec < 0) { \ if ((vsp)->tv_nsec < 0) \
{ \
(vsp)->tv_sec--; \ (vsp)->tv_sec--; \
(vsp)->tv_nsec += 1000000000L; \ (vsp)->tv_nsec += 1000000000L; \
} \ } \
@ -50,14 +52,16 @@ epoll_create_impl(errno_t *ec)
FDContextMapNode *node; FDContextMapNode *node;
node = epoll_shim_ctx_create_node(&epoll_shim_ctx, ec); node = epoll_shim_ctx_create_node(&epoll_shim_ctx, ec);
if (!node) { if (!node)
{
return NULL; return NULL;
} }
node->flags = 0; node->flags = 0;
if ((*ec = epollfd_ctx_init(&node->ctx.epollfd, /**/ if ((*ec = epollfd_ctx_init(&node->ctx.epollfd, /**/
node->fd)) != 0) { node->fd)) != 0)
{
goto fail; goto fail;
} }
@ -77,7 +81,8 @@ epoll_create_common(void)
errno_t ec; errno_t ec;
node = epoll_create_impl(&ec); node = epoll_create_impl(&ec);
if (!node) { if (!node)
{
errno = ec; errno = ec;
return -1; return -1;
} }
@ -85,10 +90,10 @@ epoll_create_common(void)
return node->fd; return node->fd;
} }
int int epoll_create(int size)
epoll_create(int size)
{ {
if (size <= 0) { if (size <= 0)
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -96,10 +101,10 @@ epoll_create(int size)
return epoll_create_common(); return epoll_create_common();
} }
int int epoll_create1(int flags)
epoll_create1(int flags)
{ {
if (flags & ~EPOLL_CLOEXEC) { if (flags & ~EPOLL_CLOEXEC)
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -110,12 +115,14 @@ epoll_create1(int flags)
static errno_t static errno_t
epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev) epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev)
{ {
if (!ev && op != EPOLL_CTL_DEL) { if (!ev && op != EPOLL_CTL_DEL)
{
return EFAULT; return EFAULT;
} }
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd); FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node || node->vtable != &epollfd_vtable) { if (!node || node->vtable != &epollfd_vtable)
{
struct stat sb; struct stat sb;
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL; return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
} }
@ -123,11 +130,11 @@ epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev)
return epollfd_ctx_ctl(&node->ctx.epollfd, op, fd2, ev); return epollfd_ctx_ctl(&node->ctx.epollfd, op, fd2, ev);
} }
int int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
{ {
errno_t ec = epoll_ctl_impl(fd, op, fd2, ev); errno_t ec = epoll_ctl_impl(fd, op, fd2, ev);
if (ec != 0) { if (ec != 0)
{
errno = ec; errno = ec;
return -1; return -1;
} }
@ -147,29 +154,35 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
{ {
errno_t ec; errno_t ec;
for (;;) { for (;;)
{
if ((ec = epollfd_ctx_wait(epollfd, /**/ if ((ec = epollfd_ctx_wait(epollfd, /**/
ev, cnt, actual_cnt)) != 0) { ev, cnt, actual_cnt)) != 0)
{
return ec; return ec;
} }
if (*actual_cnt || is_no_wait_deadline(deadline)) { if (*actual_cnt || is_no_wait_deadline(deadline))
{
return 0; return 0;
} }
struct timespec timeout; struct timespec timeout;
if (deadline) { if (deadline)
{
struct timespec current_time; struct timespec current_time;
if (clock_gettime(CLOCK_MONOTONIC, /**/ if (clock_gettime(CLOCK_MONOTONIC, /**/
&current_time) < 0) { &current_time) < 0)
{
return errno; return errno;
} }
timespecsub(deadline, &current_time, &timeout); timespecsub(deadline, &current_time, &timeout);
if (timeout.tv_sec < 0 || if (timeout.tv_sec < 0 ||
is_no_wait_deadline(&timeout)) { is_no_wait_deadline(&timeout))
{
return 0; return 0;
} }
} }
@ -180,14 +193,16 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
size_t size; size_t size;
if (__builtin_mul_overflow(nfds, sizeof(struct pollfd), if (__builtin_mul_overflow(nfds, sizeof(struct pollfd),
&size)) { &size))
{
ec = ENOMEM; ec = ENOMEM;
(void)pthread_mutex_unlock(&epollfd->mutex); (void)pthread_mutex_unlock(&epollfd->mutex);
return ec; return ec;
} }
struct pollfd *pfds = malloc(size); struct pollfd *pfds = malloc(size);
if (!pfds) { if (!pfds)
{
ec = errno; ec = errno;
(void)pthread_mutex_unlock(&epollfd->mutex); (void)pthread_mutex_unlock(&epollfd->mutex);
return ec; return ec;
@ -211,7 +226,8 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
#endif #endif
int n = ppoll(pfds, nfds, deadline ? &timeout : NULL, sigs); int n = ppoll(pfds, nfds, deadline ? &timeout : NULL, sigs);
if (n < 0) { if (n < 0)
{
ec = errno; ec = errno;
} }
@ -219,13 +235,15 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
(void)pthread_mutex_lock(&epollfd->nr_polling_threads_mutex); (void)pthread_mutex_lock(&epollfd->nr_polling_threads_mutex);
--epollfd->nr_polling_threads; --epollfd->nr_polling_threads;
if (epollfd->nr_polling_threads == 0) { if (epollfd->nr_polling_threads == 0)
{
(void)pthread_cond_signal( (void)pthread_cond_signal(
&epollfd->nr_polling_threads_cond); &epollfd->nr_polling_threads_cond);
} }
(void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex); (void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex);
if (n < 0) { if (n < 0)
{
return ec; return ec;
} }
} }
@ -236,21 +254,27 @@ timeout_to_deadline(struct timespec *deadline, int to)
{ {
assert(to >= 0); assert(to >= 0);
if (to == 0) { if (to == 0)
{
*deadline = (struct timespec){0, 0}; *deadline = (struct timespec){0, 0};
} else if (to > 0) { }
if (clock_gettime(CLOCK_MONOTONIC, deadline) < 0) { else if (to > 0)
{
if (clock_gettime(CLOCK_MONOTONIC, deadline) < 0)
{
return errno; return errno;
} }
if (__builtin_add_overflow(deadline->tv_sec, to / 1000 + 1, if (__builtin_add_overflow(deadline->tv_sec, to / 1000 + 1,
&deadline->tv_sec)) { &deadline->tv_sec))
{
return EINVAL; return EINVAL;
} }
deadline->tv_sec -= 1; deadline->tv_sec -= 1;
deadline->tv_nsec += (to % 1000) * 1000000L; deadline->tv_nsec += (to % 1000) * 1000000L;
if (deadline->tv_nsec >= 1000000000) { if (deadline->tv_nsec >= 1000000000)
{
deadline->tv_nsec -= 1000000000; deadline->tv_nsec -= 1000000000;
deadline->tv_sec += 1; deadline->tv_sec += 1;
} }
@ -263,19 +287,22 @@ static errno_t
epoll_pwait_impl(int fd, struct epoll_event *ev, int cnt, int to, epoll_pwait_impl(int fd, struct epoll_event *ev, int cnt, int to,
sigset_t const *sigs, int *actual_cnt) sigset_t const *sigs, int *actual_cnt)
{ {
if (cnt < 1 || cnt > (int)(INT_MAX / sizeof(struct epoll_event))) { if (cnt < 1 || cnt > (int)(INT_MAX / sizeof(struct epoll_event)))
{
return EINVAL; return EINVAL;
} }
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd); FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node || node->vtable != &epollfd_vtable) { if (!node || node->vtable != &epollfd_vtable)
{
struct stat sb; struct stat sb;
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL; return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
} }
struct timespec deadline; struct timespec deadline;
errno_t ec; errno_t ec;
if (to >= 0 && (ec = timeout_to_deadline(&deadline, to)) != 0) { if (to >= 0 && (ec = timeout_to_deadline(&deadline, to)) != 0)
{
return ec; return ec;
} }
@ -283,14 +310,14 @@ epoll_pwait_impl(int fd, struct epoll_event *ev, int cnt, int to,
actual_cnt, (to >= 0) ? &deadline : NULL, sigs); actual_cnt, (to >= 0) ? &deadline : NULL, sigs);
} }
int int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
sigset_t const *sigs) sigset_t const *sigs)
{ {
int actual_cnt; int actual_cnt;
errno_t ec = epoll_pwait_impl(fd, ev, cnt, to, sigs, &actual_cnt); errno_t ec = epoll_pwait_impl(fd, ev, cnt, to, sigs, &actual_cnt);
if (ec != 0) { if (ec != 0)
{
errno = ec; errno = ec;
return -1; return -1;
} }
@ -298,8 +325,7 @@ epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
return actual_cnt; return actual_cnt;
} }
int int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
{ {
return epoll_pwait(fd, ev, cnt, to, NULL); return epoll_pwait(fd, ev, cnt, to, NULL);
} }

View File

@ -20,7 +20,8 @@ fd_context_map_node_create(int kq, errno_t *ec)
FDContextMapNode *node; FDContextMapNode *node;
node = malloc(sizeof(FDContextMapNode)); node = malloc(sizeof(FDContextMapNode));
if (!node) { if (!node)
{
*ec = errno; *ec = errno;
return NULL; return NULL;
} }
@ -34,7 +35,8 @@ fd_context_map_node_terminate(FDContextMapNode *node, bool close_fd)
{ {
errno_t ec = node->vtable ? node->vtable->close_fun(node) : 0; errno_t ec = node->vtable ? node->vtable->close_fun(node) : 0;
if (close_fd && close(node->fd) < 0) { if (close_fd && close(node->fd) < 0)
{
ec = ec ? ec : errno; ec = ec ? ec : errno;
} }
@ -107,7 +109,8 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
&epoll_shim_ctx->fd_context_map, &find); &epoll_shim_ctx->fd_context_map, &find);
} }
if (node) { if (node)
{
/* /*
* If we get here, someone must have already closed the old fd * If we get here, someone must have already closed the old fd
* with a normal 'close()' call, i.e. not with our * with a normal 'close()' call, i.e. not with our
@ -118,9 +121,12 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
*/ */
(void)fd_context_map_node_terminate(node, false); (void)fd_context_map_node_terminate(node, false);
fd_context_map_node_init(node, kq); fd_context_map_node_init(node, kq);
} else { }
else
{
node = fd_context_map_node_create(kq, ec); node = fd_context_map_node_create(kq, ec);
if (!node) { if (!node)
{
return NULL; return NULL;
} }
@ -139,7 +145,8 @@ epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec)
FDContextMapNode *node; FDContextMapNode *node;
int kq = kqueue(); int kq = kqueue();
if (kq < 0) { if (kq < 0)
{
*ec = errno; *ec = errno;
return NULL; return NULL;
} }
@ -148,7 +155,8 @@ epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec)
node = epoll_shim_ctx_create_node_impl(epoll_shim_ctx, kq, ec); node = epoll_shim_ctx_create_node_impl(epoll_shim_ctx, kq, ec);
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex); (void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
if (!node) { if (!node)
{
close(kq); close(kq);
} }
@ -188,7 +196,8 @@ epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, int fd)
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex); (void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
node = epoll_shim_ctx_find_node_impl(epoll_shim_ctx, fd); node = epoll_shim_ctx_find_node_impl(epoll_shim_ctx, fd);
if (node) { if (node)
{
RB_REMOVE(fd_context_map_, /**/ RB_REMOVE(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, node); &epoll_shim_ctx->fd_context_map, node);
} }
@ -197,8 +206,7 @@ epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, int fd)
return node; return node;
} }
void void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
FDContextMapNode *node) FDContextMapNode *node)
{ {
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex); (void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
@ -209,18 +217,19 @@ epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
/**/ /**/
int int epoll_shim_close(int fd)
epoll_shim_close(int fd)
{ {
FDContextMapNode *node; FDContextMapNode *node;
node = epoll_shim_ctx_remove_node(&epoll_shim_ctx, fd); node = epoll_shim_ctx_remove_node(&epoll_shim_ctx, fd);
if (!node) { if (!node)
{
return close(fd); return close(fd);
} }
errno_t ec = fd_context_map_node_destroy(node); errno_t ec = fd_context_map_node_destroy(node);
if (ec != 0) { if (ec != 0)
{
errno = ec; errno = ec;
return -1; return -1;
} }
@ -234,11 +243,13 @@ epoll_shim_read(int fd, void *buf, size_t nbytes)
FDContextMapNode *node; FDContextMapNode *node;
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd); node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node) { if (!node)
{
return read(fd, buf, nbytes); return read(fd, buf, nbytes);
} }
if (nbytes > SSIZE_MAX) { if (nbytes > SSIZE_MAX)
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -246,7 +257,8 @@ epoll_shim_read(int fd, void *buf, size_t nbytes)
size_t bytes_transferred; size_t bytes_transferred;
errno_t ec = node->vtable->read_fun(node, /**/ errno_t ec = node->vtable->read_fun(node, /**/
buf, nbytes, &bytes_transferred); buf, nbytes, &bytes_transferred);
if (ec != 0) { if (ec != 0)
{
errno = ec; errno = ec;
return -1; return -1;
} }
@ -260,11 +272,13 @@ epoll_shim_write(int fd, void const *buf, size_t nbytes)
FDContextMapNode *node; FDContextMapNode *node;
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd); node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node) { if (!node)
{
return write(fd, buf, nbytes); return write(fd, buf, nbytes);
} }
if (nbytes > SSIZE_MAX) { if (nbytes > SSIZE_MAX)
{
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -272,7 +286,8 @@ epoll_shim_write(int fd, void const *buf, size_t nbytes)
size_t bytes_transferred; size_t bytes_transferred;
errno_t ec = node->vtable->write_fun(node, /**/ errno_t ec = node->vtable->write_fun(node, /**/
buf, nbytes, &bytes_transferred); buf, nbytes, &bytes_transferred);
if (ec != 0) { if (ec != 0)
{
errno = ec; errno = ec;
return -1; return -1;
} }

View File

@ -21,7 +21,8 @@ typedef errno_t (*fd_context_write_fun)(FDContextMapNode *node, /**/
const void *buf, size_t nbytes, size_t *bytes_transferred); const void *buf, size_t nbytes, size_t *bytes_transferred);
typedef errno_t (*fd_context_close_fun)(FDContextMapNode *node); typedef errno_t (*fd_context_close_fun)(FDContextMapNode *node);
typedef struct { typedef struct
{
fd_context_read_fun read_fun; fd_context_read_fun read_fun;
fd_context_write_fun write_fun; fd_context_write_fun write_fun;
fd_context_close_fun close_fun; fd_context_close_fun close_fun;
@ -32,11 +33,14 @@ errno_t fd_context_default_read(FDContextMapNode *node, /**/
errno_t fd_context_default_write(FDContextMapNode *node, /**/ errno_t fd_context_default_write(FDContextMapNode *node, /**/
void const *buf, size_t nbytes, size_t *bytes_transferred); void const *buf, size_t nbytes, size_t *bytes_transferred);
struct fd_context_map_node_ { struct fd_context_map_node_
RB_ENTRY(fd_context_map_node_) entry; {
RB_ENTRY(fd_context_map_node_)
entry;
int fd; int fd;
int flags; int flags;
union { union
{
EpollFDCtx epollfd; EpollFDCtx epollfd;
EventFDCtx eventfd; EventFDCtx eventfd;
TimerFDCtx timerfd; TimerFDCtx timerfd;
@ -51,7 +55,8 @@ errno_t fd_context_map_node_destroy(FDContextMapNode *node);
typedef RB_HEAD(fd_context_map_, fd_context_map_node_) FDContextMap; typedef RB_HEAD(fd_context_map_, fd_context_map_node_) FDContextMap;
typedef struct { typedef struct
{
FDContextMap fd_context_map; FDContextMap fd_context_map;
pthread_mutex_t mutex; pthread_mutex_t mutex;
} EpollShimCtx; } EpollShimCtx;

File diff suppressed because it is too large Load Diff

View File

@ -19,12 +19,14 @@
struct registered_fds_node_; struct registered_fds_node_;
typedef struct registered_fds_node_ RegisteredFDsNode; typedef struct registered_fds_node_ RegisteredFDsNode;
typedef enum { typedef enum
{
EOF_STATE_READ_EOF = 0x01, EOF_STATE_READ_EOF = 0x01,
EOF_STATE_WRITE_EOF = 0x02, EOF_STATE_WRITE_EOF = 0x02,
} EOFState; } EOFState;
typedef enum { typedef enum
{
NODE_TYPE_FIFO = 1, NODE_TYPE_FIFO = 1,
NODE_TYPE_SOCKET = 2, NODE_TYPE_SOCKET = 2,
NODE_TYPE_KQUEUE = 3, NODE_TYPE_KQUEUE = 3,
@ -32,9 +34,12 @@ typedef enum {
NODE_TYPE_POLL = 5, NODE_TYPE_POLL = 5,
} NodeType; } NodeType;
struct registered_fds_node_ { struct registered_fds_node_
RB_ENTRY(registered_fds_node_) entry; {
TAILQ_ENTRY(registered_fds_node_) pollfd_list_entry; RB_ENTRY(registered_fds_node_)
entry;
TAILQ_ENTRY(registered_fds_node_)
pollfd_list_entry;
int fd; int fd;
epoll_data_t data; epoll_data_t data;
@ -50,8 +55,10 @@ struct registered_fds_node_ {
bool got_evfilt_except; bool got_evfilt_except;
NodeType node_type; NodeType node_type;
union { union
struct { {
struct
{
bool readable; bool readable;
bool writable; bool writable;
} fifo; } fifo;
@ -72,7 +79,8 @@ struct registered_fds_node_ {
typedef TAILQ_HEAD(pollfds_list_, registered_fds_node_) PollFDList; typedef TAILQ_HEAD(pollfds_list_, registered_fds_node_) PollFDList;
typedef RB_HEAD(registered_fds_set_, registered_fds_node_) RegisteredFDsSet; typedef RB_HEAD(registered_fds_set_, registered_fds_node_) RegisteredFDsSet;
typedef struct { typedef struct
{
int kq; // non owning int kq; // non owning
pthread_mutex_t mutex; pthread_mutex_t mutex;

View File

@ -11,7 +11,8 @@
#define EVENTFD_CTX_FLAG_SEMAPHORE (1 << 0) #define EVENTFD_CTX_FLAG_SEMAPHORE (1 << 0)
typedef struct { typedef struct
{
int kq_; // non owning int kq_; // non owning
int flags_; int flags_;
pthread_mutex_t mutex_; pthread_mutex_t mutex_;

View File

@ -4,7 +4,7 @@
#include <errno.h> #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 // macos does not implement ppoll
// this is a hacky ppoll shim. only for tpws which does not require sigmask // 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; errno = EINVAL;
return -1; 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 #endif

View File

@ -11,10 +11,11 @@ typedef int errno_t;
#include <signal.h> #include <signal.h>
#include <poll.h> #include <poll.h>
struct itimerspec { struct itimerspec
{
struct timespec it_interval; struct timespec it_interval;
struct timespec it_value; struct timespec it_value;
}; };
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 #endif

View File

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

View File

@ -11,7 +11,8 @@
#include <pthread.h> #include <pthread.h>
#include <time.h> #include <time.h>
typedef struct { typedef struct
{
int kq; // non owning int kq; // non owning
int flags; int flags;
pthread_mutex_t mutex; pthread_mutex_t mutex;

View File

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

View File

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

View File

@ -11,7 +11,7 @@
#include <time.h> #include <time.h>
#include <sys/stat.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; char c, sc;
size_t len; size_t len;
@ -23,9 +23,11 @@ char *strncasestr(const char *s,const char *find, size_t slen)
{ {
do do
{ {
if (slen-- < 1 || (sc = *s++) == '\0') return NULL; if (slen-- < 1 || (sc = *s++) == '\0')
return NULL;
} while (toupper(c) != toupper(sc)); } while (toupper(c) != toupper(sc));
if (len > slen) return NULL; if (len > slen)
return NULL;
} while (strncasecmp(s, find, len) != 0); } while (strncasecmp(s, find, len) != 0);
s--; s--;
} }
@ -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) bool append_to_list_file(const char *filename, const char *s)
{ {
FILE *F = fopen(filename,"at"); FILE *F = fopen(filename, "at");
if (!F) return false; if (!F)
bool bOK = fprintf(F,"%s\n",s)>0; return false;
bool bOK = fprintf(F, "%s\n", s) > 0;
fclose(F); fclose(F);
return bOK; return bOK;
} }
void ntop46(const struct sockaddr *sa, char *str, size_t len) void ntop46(const struct sockaddr *sa, char *str, size_t len)
{ {
if (!len) return; if (!len)
*str=0; return;
*str = 0;
switch (sa->sa_family) switch (sa->sa_family)
{ {
case AF_INET: 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; break;
case AF_INET6: 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; break;
default: 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) void ntop46_port(const struct sockaddr *sa, char *str, size_t len)
{ {
char ip[40]; char ip[40];
ntop46(sa,ip,sizeof(ip)); ntop46(sa, ip, sizeof(ip));
switch (sa->sa_family) switch (sa->sa_family)
{ {
case AF_INET: 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; break;
case AF_INET6: 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; break;
default: default:
snprintf(str,len,"%s",ip); snprintf(str, len, "%s", ip);
} }
} }
void print_sockaddr(const struct sockaddr *sa) void print_sockaddr(const struct sockaddr *sa)
{ {
char ip_port[48]; char ip_port[48];
ntop46_port(sa,ip_port,sizeof(ip_port)); ntop46_port(sa, ip_port, sizeof(ip_port));
printf("%s",ip_port); printf("%s", ip_port);
} }
// -1 = error, 0 = not local, 1 = local // -1 = error, 0 = not local, 1 = local
bool check_local_ip(const struct sockaddr *saddr) bool check_local_ip(const struct sockaddr *saddr)
{ {
struct ifaddrs *addrs,*a; struct ifaddrs *addrs, *a;
if (is_localnet(saddr)) if (is_localnet(saddr))
return true; return true;
if (getifaddrs(&addrs)<0) return false; if (getifaddrs(&addrs) < 0)
return false;
a = addrs; a = addrs;
bool bres=false; bool bres = false;
while (a) 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; break;
} }
a = a->ifa_next; a = a->ifa_next;
@ -115,50 +119,48 @@ void print_addrinfo(const struct addrinfo *ai)
switch (ai->ai_family) switch (ai->ai_family)
{ {
case AF_INET: 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); printf("%s\n", str);
break; break;
case AF_INET6: 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)))
printf( "%s\n", str); printf("%s\n", str);
break; break;
} }
ai = ai->ai_next; ai = ai->ai_next;
} }
} }
bool saismapped(const struct sockaddr_in6 *sa) bool saismapped(const struct sockaddr_in6 *sa)
{ {
// ::ffff:1.2.3.4 // ::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))) || 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_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_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)); (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) uint16_t saport(const struct sockaddr *sa)
{ {
return htons(sa->sa_family==AF_INET ? ((struct sockaddr_in*)sa)->sin_port : return htons(sa->sa_family == AF_INET ? ((struct sockaddr_in *)sa)->sin_port : sa->sa_family == AF_INET6 ? ((struct sockaddr_in6 *)sa)->sin6_port
sa->sa_family==AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0); : 0);
} }
bool saconvmapped(struct sockaddr_storage *a) bool saconvmapped(struct sockaddr_storage *a)
{ {
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); uint32_t ip4 = IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr);
uint16_t port = ((struct sockaddr_in6*)a)->sin6_port; uint16_t port = ((struct sockaddr_in6 *)a)->sin6_port;
a->ss_family = AF_INET; a->ss_family = AF_INET;
((struct sockaddr_in*)a)->sin_addr.s_addr = ip4; ((struct sockaddr_in *)a)->sin_addr.s_addr = ip4;
((struct sockaddr_in*)a)->sin_port = port; ((struct sockaddr_in *)a)->sin_port = port;
return true; return true;
} }
return false; return false;
@ -167,45 +169,43 @@ bool saconvmapped(struct sockaddr_storage *a)
bool is_localnet(const struct sockaddr *a) bool is_localnet(const struct sockaddr *a)
{ {
// match 127.0.0.0/8, 0.0.0.0, ::1, ::0, :ffff:127.0.0.0/104, :ffff:0.0.0.0 // match 127.0.0.0/8, 0.0.0.0, ::1, ::0, :ffff:127.0.0.0/104, :ffff:0.0.0.0
return (a->sa_family==AF_INET && (IN_LOOPBACK(ntohl(((struct sockaddr_in *)a)->sin_addr.s_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)))) || 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) || (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_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))) || (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)))))); INADDR_ANY == ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr))))));
} }
bool is_linklocal(const struct sockaddr_in6 *a) bool is_linklocal(const struct sockaddr_in6 *a)
{ {
// fe80::/10 // 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 // fc00::/7
return (a->sin6_addr.s6_addr[0] & 0xFE) == 0xFC; return (a->sin6_addr.s6_addr[0] & 0xFE) == 0xFC;
} }
bool set_keepalive(int fd) bool set_keepalive(int fd)
{ {
int yes=1; int yes = 1;
return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int))!=-1; return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int)) != -1;
} }
bool set_ttl(int fd, int ttl) 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) 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 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 // try to set both but one may fail if family is wrong
b1=set_ttl(fd, ttl); b1 = set_ttl(fd, ttl);
b2=set_hl(fd, ttl); b2 = set_hl(fd, ttl);
return b1 || b2; return b1 || b2;
} }
int get_so_error(int fd) int get_so_error(int fd)
@ -213,8 +213,8 @@ int get_so_error(int fd)
// getsockopt(SO_ERROR) clears error // getsockopt(SO_ERROR) clears error
int errn; int errn;
socklen_t optlen = sizeof(errn); socklen_t optlen = sizeof(errn);
if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1) if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1)
errn=errno; errn = errno;
return errn; return errn;
} }
@ -224,42 +224,45 @@ int fprint_localtime(FILE *F)
time_t now; time_t now;
time(&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); 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) time_t file_mod_time(const char *filename)
{ {
struct stat st; 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) 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) 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++; s++;
} }
else else
pf->neg=false; pf->neg = false;
if (sscanf(s,"%u-%u",&v1,&v2)==2) if (sscanf(s, "%u-%u", &v1, &v2) == 2)
{ {
if (!v1 || v1>65535 || v2>65535 || v1>v2) return false; if (!v1 || v1 > 65535 || v2 > 65535 || v1 > v2)
pf->from=(uint16_t)v1; return false;
pf->to=(uint16_t)v2; 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; if (!v1 || v1 > 65535)
pf->to=pf->from=(uint16_t)v1; return false;
pf->to = pf->from = (uint16_t)v1;
} }
else else
return false; return false;

View File

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

View File

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

View File

@ -8,10 +8,18 @@
#define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook) #define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook)
enum { PF_INOUT, PF_IN, PF_OUT, PF_FWD }; enum
{
PF_INOUT,
PF_IN,
PF_OUT,
PF_FWD
};
struct pf_addr { struct pf_addr
union { {
union
{
struct in_addr v4; struct in_addr v4;
struct in6_addr v6; struct in6_addr v6;
u_int8_t addr8[16]; u_int8_t addr8[16];
@ -25,13 +33,15 @@ struct pf_addr {
#define addr32 pfa.addr32 #define addr32 pfa.addr32
}; };
union pf_state_xport { union pf_state_xport
{
u_int16_t port; u_int16_t port;
u_int16_t call_id; u_int16_t call_id;
u_int32_t spi; u_int32_t spi;
}; };
struct pfioc_natlook { struct pfioc_natlook
{
struct pf_addr saddr; struct pf_addr saddr;
struct pf_addr daddr; struct pf_addr daddr;
struct pf_addr rsaddr; struct pf_addr rsaddr;

View File

@ -62,22 +62,26 @@
*/ */
#define SPLAY_HEAD(name, type) \ #define SPLAY_HEAD(name, type) \
struct name { \ struct name \
{ \
struct type *sph_root; /* root of the tree */ \ struct type *sph_root; /* root of the tree */ \
} }
#define SPLAY_INITIALIZER(root) \ #define SPLAY_INITIALIZER(root) \
{ NULL } {NULL}
#define SPLAY_INIT(root) do { \ #define SPLAY_INIT(root) \
do \
{ \
(root)->sph_root = NULL; \ (root)->sph_root = NULL; \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
#define SPLAY_ENTRY(type) \ #define SPLAY_ENTRY(type) \
struct { \ struct \
{ \
struct type *spe_left; /* left element */ \ struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \ struct type *spe_right; /* right element */ \
} }
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left #define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
@ -85,197 +89,233 @@ struct { \
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ #define SPLAY_ROTATE_RIGHT(head, tmp, field) \
do \
{ \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \ (head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ #define SPLAY_ROTATE_LEFT(head, tmp, field) \
do \
{ \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \ (head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \ #define SPLAY_LINKLEFT(head, tmp, field) \
do \
{ \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \ tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \ #define SPLAY_LINKRIGHT(head, tmp, field) \
do \
{ \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \ tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ #define SPLAY_ASSEMBLE(head, node, left, right, field) \
do \
{ \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */ /* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \ #define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \ void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \ void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\ \
/* Finds the node with the same key as elm */ \ /* Finds the node with the same key as elm */ \
static __inline struct type * \ static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \ name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \ { \
if (SPLAY_EMPTY(head)) \ if (SPLAY_EMPTY(head)) \
return(NULL); \ return (NULL); \
name##_SPLAY(head, elm); \ name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \ if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \ return (head->sph_root); \
return (NULL); \ return (NULL); \
} \ } \
\ \
static __inline struct type * \ static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \ name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \ { \
name##_SPLAY(head, elm); \ name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \ if (SPLAY_RIGHT(elm, field) != NULL) \
{ \
elm = SPLAY_RIGHT(elm, field); \ elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \ while (SPLAY_LEFT(elm, field) != NULL) \
{ \
elm = SPLAY_LEFT(elm, field); \ elm = SPLAY_LEFT(elm, field); \
} \ } \
} else \ } \
else \
elm = NULL; \ elm = NULL; \
return (elm); \ return (elm); \
} \ } \
\ \
static __inline struct type * \ static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \ name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \ { \
name##_SPLAY_MINMAX(head, val); \ name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \ return (SPLAY_ROOT(head)); \
} }
/* Main splay operation. /* Main splay operation.
* Moves node close to the key of elm to top * Moves node close to the key of elm to top
*/ */
#define SPLAY_GENERATE(name, type, field, cmp) \ #define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \ struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \ name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \ { \
if (SPLAY_EMPTY(head)) { \ if (SPLAY_EMPTY(head)) \
{ \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \ } \
else \
{ \
int __comp; \ int __comp; \
name##_SPLAY(head, elm); \ name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \ __comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \ if (__comp < 0) \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_RIGHT(elm, field) = (head)->sph_root; \ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \ SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \ } \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ else if (__comp > 0) \
{ \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
SPLAY_LEFT(elm, field) = (head)->sph_root; \ SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \ } \
else \
return ((head)->sph_root); \ return ((head)->sph_root); \
} \ } \
(head)->sph_root = (elm); \ (head)->sph_root = (elm); \
return (NULL); \ return (NULL); \
} \ } \
\ \
struct type * \ struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \ { \
struct type *__tmp; \ struct type *__tmp; \
if (SPLAY_EMPTY(head)) \ if (SPLAY_EMPTY(head)) \
return (NULL); \ return (NULL); \
name##_SPLAY(head, elm); \ name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \ if ((cmp)(elm, (head)->sph_root) == 0) \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
} else { \ { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} \
else \
{ \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
name##_SPLAY(head, elm); \ name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \ } \
return (elm); \ return (elm); \
} \ } \
return (NULL); \ return (NULL); \
} \ } \
\ \
void \ void \
name##_SPLAY(struct name *head, struct type *elm) \ name##_SPLAY(struct name *head, struct type *elm) \
{ \ { \
struct type __node, *__left, *__right, *__tmp; \ struct type __node, *__left, *__right, *__tmp; \
int __comp; \ int __comp; \
\ \
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
__left = __right = &__node; \ __left = __right = &__node; \
\ \
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) \
if (__comp < 0) { \ { \
if (__comp < 0) \
{ \
__tmp = SPLAY_LEFT((head)->sph_root, field); \ __tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \ if (__tmp == NULL) \
break; \ break; \
if ((cmp)(elm, __tmp) < 0){ \ if ((cmp)(elm, __tmp) < 0) \
{ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
break; \ break; \
} \ } \
SPLAY_LINKLEFT(head, __right, field); \ SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \ } \
else if (__comp > 0) \
{ \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \ if (__tmp == NULL) \
break; \ break; \
if ((cmp)(elm, __tmp) > 0){ \ if ((cmp)(elm, __tmp) > 0) \
{ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \ SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
break; \ break; \
} \ } \
SPLAY_LINKRIGHT(head, __left, field); \ SPLAY_LINKRIGHT(head, __left, field); \
} \ } \
} \ } \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \ } \
\ \
/* Splay with either the minimum or the maximum element \ /* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \ * Used to find minimum or maximum element in tree. \
*/ \ */ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \ void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \ { \
struct type __node, *__left, *__right, *__tmp; \ struct type __node, *__left, *__right, *__tmp; \
\ \
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
__left = __right = &__node; \ __left = __right = &__node; \
\ \
while (1) { \ while (1) \
if (__comp < 0) { \ { \
if (__comp < 0) \
{ \
__tmp = SPLAY_LEFT((head)->sph_root, field); \ __tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \ if (__tmp == NULL) \
break; \ break; \
if (__comp < 0){ \ if (__comp < 0) \
{ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
break; \ break; \
} \ } \
SPLAY_LINKLEFT(head, __right, field); \ SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \ } \
else if (__comp > 0) \
{ \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \ if (__tmp == NULL) \
break; \ break; \
if (__comp > 0) { \ if (__comp > 0) \
{ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \ SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
break; \ break; \
} \ } \
SPLAY_LINKRIGHT(head, __left, field); \ SPLAY_LINKRIGHT(head, __left, field); \
} \ } \
} \ } \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} }
#define SPLAY_NEGINF -1 #define SPLAY_NEGINF -1
#define SPLAY_INF 1 #define SPLAY_INF 1
@ -296,26 +336,30 @@ void name##_SPLAY_MINMAX(struct name *head, int __comp) \
/* Macros that define a red-black tree */ /* Macros that define a red-black tree */
#define RB_HEAD(name, type) \ #define RB_HEAD(name, type) \
struct name { \ struct name \
{ \
struct type *rbh_root; /* root of the tree */ \ struct type *rbh_root; /* root of the tree */ \
} }
#define RB_INITIALIZER(root) \ #define RB_INITIALIZER(root) \
{ NULL } {NULL}
#define RB_INIT(root) do { \ #define RB_INIT(root) \
do \
{ \
(root)->rbh_root = NULL; \ (root)->rbh_root = NULL; \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
#define RB_BLACK 0 #define RB_BLACK 0
#define RB_RED 1 #define RB_RED 1
#define RB_ENTRY(type) \ #define RB_ENTRY(type) \
struct { \ struct \
{ \
struct type *rbe_left; /* left element */ \ struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \ struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \ struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \ int rbe_color; /* node color */ \
} }
#define RB_LEFT(elm, field) (elm)->field.rbe_left #define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right #define RB_RIGHT(elm, field) (elm)->field.rbe_right
@ -324,64 +368,81 @@ struct { \
#define RB_ROOT(head) (head)->rbh_root #define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL) #define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(elm, parent, field) do { \ #define RB_SET(elm, parent, field) \
do \
{ \
RB_PARENT(elm, field) = parent; \ RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \ RB_COLOR(elm, field) = RB_RED; \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
#define RB_SET_BLACKRED(black, red, field) do { \ #define RB_SET_BLACKRED(black, red, field) \
do \
{ \
RB_COLOR(black, field) = RB_BLACK; \ RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \ RB_COLOR(red, field) = RB_RED; \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
#ifndef RB_AUGMENT #ifndef RB_AUGMENT
#define RB_AUGMENT(x) do {} while (0) #define RB_AUGMENT(x) \
do \
{ \
} while (0)
#endif #endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ #define RB_ROTATE_LEFT(head, elm, tmp, field) \
do \
{ \
(tmp) = RB_RIGHT(elm, field); \ (tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) \
{ \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \ } \
RB_AUGMENT(elm); \ RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) \
{ \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \ else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \ } \
else \
(head)->rbh_root = (tmp); \ (head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \ RB_LEFT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \ RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \ RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \ if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \ RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ #define RB_ROTATE_RIGHT(head, elm, tmp, field) \
do \
{ \
(tmp) = RB_LEFT(elm, field); \ (tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) \
{ \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \ } \
RB_AUGMENT(elm); \ RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) \
{ \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \ else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \ } \
else \
(head)->rbh_root = (tmp); \ (head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \ RB_RIGHT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \ RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \ RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \ if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \ RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0) } while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */ /* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \ #define RB_PROTOTYPE(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) RB_PROTOTYPE_INTERNAL(name, type, field, cmp, )
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
@ -417,7 +478,7 @@ struct { \
* Moves node close to the key of elm to top * Moves node close to the key of elm to top
*/ */
#define RB_GENERATE(name, type, field, cmp) \ #define RB_GENERATE(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp,) RB_GENERATE_INTERNAL(name, type, field, cmp, )
#define RB_GENERATE_STATIC(name, type, field, cmp) \ #define RB_GENERATE_STATIC(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
@ -432,39 +493,47 @@ struct { \
RB_GENERATE_MINMAX(name, type, field, attr) RB_GENERATE_MINMAX(name, type, field, attr)
#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ #define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \
attr void \ attr void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \ { \
struct type *parent, *gparent, *tmp; \ struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) != NULL && \ while ((parent = RB_PARENT(elm, field)) != NULL && \
RB_COLOR(parent, field) == RB_RED) { \ RB_COLOR(parent, field) == RB_RED) \
{ \
gparent = RB_PARENT(parent, field); \ gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \ if (parent == RB_LEFT(gparent, field)) \
{ \
tmp = RB_RIGHT(gparent, field); \ tmp = RB_RIGHT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ if (tmp && RB_COLOR(tmp, field) == RB_RED) \
{ \
RB_COLOR(tmp, field) = RB_BLACK; \ RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\ RB_SET_BLACKRED(parent, gparent, field); \
elm = gparent; \ elm = gparent; \
continue; \ continue; \
} \ } \
if (RB_RIGHT(parent, field) == elm) { \ if (RB_RIGHT(parent, field) == elm) \
RB_ROTATE_LEFT(head, parent, tmp, field);\ { \
RB_ROTATE_LEFT(head, parent, tmp, field); \
tmp = parent; \ tmp = parent; \
parent = elm; \ parent = elm; \
elm = tmp; \ elm = tmp; \
} \ } \
RB_SET_BLACKRED(parent, gparent, field); \ RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} else { \ } \
else \
{ \
tmp = RB_LEFT(gparent, field); \ tmp = RB_LEFT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ if (tmp && RB_COLOR(tmp, field) == RB_RED) \
{ \
RB_COLOR(tmp, field) = RB_BLACK; \ RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\ RB_SET_BLACKRED(parent, gparent, field); \
elm = gparent; \ elm = gparent; \
continue; \ continue; \
} \ } \
if (RB_LEFT(parent, field) == elm) { \ if (RB_LEFT(parent, field) == elm) \
RB_ROTATE_RIGHT(head, parent, tmp, field);\ { \
RB_ROTATE_RIGHT(head, parent, tmp, field); \
tmp = parent; \ tmp = parent; \
parent = elm; \ parent = elm; \
elm = tmp; \ elm = tmp; \
@ -474,78 +543,90 @@ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
} \ } \
} \ } \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
} }
#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ #define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \
attr void \ attr void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \ { \
struct type *tmp; \ struct type *tmp; \
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
elm != RB_ROOT(head)) { \ elm != RB_ROOT(head)) \
if (RB_LEFT(parent, field) == elm) { \ { \
if (RB_LEFT(parent, field) == elm) \
{ \
tmp = RB_RIGHT(parent, field); \ tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \ if (RB_COLOR(tmp, field) == RB_RED) \
{ \
RB_SET_BLACKRED(tmp, parent, field); \ RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field);\ RB_ROTATE_LEFT(head, parent, tmp, field); \
tmp = RB_RIGHT(parent, field); \ tmp = RB_RIGHT(parent, field); \
} \ } \
if ((RB_LEFT(tmp, field) == NULL || \ if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
(RB_RIGHT(tmp, field) == NULL || \ (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) \
{ \
RB_COLOR(tmp, field) = RB_RED; \ RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \ elm = parent; \
parent = RB_PARENT(elm, field); \ parent = RB_PARENT(elm, field); \
} else { \ } \
else \
{ \
if (RB_RIGHT(tmp, field) == NULL || \ if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) \
{ \
struct type *oleft; \ struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)) \ if ((oleft = RB_LEFT(tmp, field)) != NULL) \
!= NULL) \ RB_COLOR(oleft, field) = RB_BLACK; \
RB_COLOR(oleft, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \ RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field);\ RB_ROTATE_RIGHT(head, tmp, oleft, field); \
tmp = RB_RIGHT(parent, field); \ tmp = RB_RIGHT(parent, field); \
} \ } \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
RB_COLOR(parent, field) = RB_BLACK; \ RB_COLOR(parent, field) = RB_BLACK; \
if (RB_RIGHT(tmp, field)) \ if (RB_RIGHT(tmp, field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
RB_ROTATE_LEFT(head, parent, tmp, field);\ RB_ROTATE_LEFT(head, parent, tmp, field); \
elm = RB_ROOT(head); \ elm = RB_ROOT(head); \
break; \ break; \
} \ } \
} else { \ } \
else \
{ \
tmp = RB_LEFT(parent, field); \ tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \ if (RB_COLOR(tmp, field) == RB_RED) \
{ \
RB_SET_BLACKRED(tmp, parent, field); \ RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field);\ RB_ROTATE_RIGHT(head, parent, tmp, field); \
tmp = RB_LEFT(parent, field); \ tmp = RB_LEFT(parent, field); \
} \ } \
if ((RB_LEFT(tmp, field) == NULL || \ if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
(RB_RIGHT(tmp, field) == NULL || \ (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) \
{ \
RB_COLOR(tmp, field) = RB_RED; \ RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \ elm = parent; \
parent = RB_PARENT(elm, field); \ parent = RB_PARENT(elm, field); \
} else { \ } \
else \
{ \
if (RB_LEFT(tmp, field) == NULL || \ if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) \
{ \
struct type *oright; \ struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)) \ if ((oright = RB_RIGHT(tmp, field)) != NULL) \
!= NULL) \ RB_COLOR(oright, field) = RB_BLACK; \
RB_COLOR(oright, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \ RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field);\ RB_ROTATE_LEFT(head, tmp, oright, field); \
tmp = RB_LEFT(parent, field); \ tmp = RB_LEFT(parent, field); \
} \ } \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
RB_COLOR(parent, field) = RB_BLACK; \ RB_COLOR(parent, field) = RB_BLACK; \
if (RB_LEFT(tmp, field)) \ if (RB_LEFT(tmp, field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
RB_ROTATE_RIGHT(head, parent, tmp, field);\ RB_ROTATE_RIGHT(head, parent, tmp, field); \
elm = RB_ROOT(head); \ elm = RB_ROOT(head); \
break; \ break; \
} \ } \
@ -553,19 +634,20 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm)
} \ } \
if (elm) \ if (elm) \
RB_COLOR(elm, field) = RB_BLACK; \ RB_COLOR(elm, field) = RB_BLACK; \
} }
#define RB_GENERATE_REMOVE(name, type, field, attr) \ #define RB_GENERATE_REMOVE(name, type, field, attr) \
attr struct type * \ attr struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \ name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \ { \
struct type *child, *parent, *old = elm; \ struct type *child, *parent, *old = elm; \
int color; \ int color; \
if (RB_LEFT(elm, field) == NULL) \ if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \ child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \ else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \ child = RB_LEFT(elm, field); \
else { \ else \
{ \
struct type *left; \ struct type *left; \
elm = RB_RIGHT(elm, field); \ elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field)) != NULL) \ while ((left = RB_LEFT(elm, field)) != NULL) \
@ -575,31 +657,37 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \
color = RB_COLOR(elm, field); \ color = RB_COLOR(elm, field); \
if (child) \ if (child) \
RB_PARENT(child, field) = parent; \ RB_PARENT(child, field) = parent; \
if (parent) { \ if (parent) \
{ \
if (RB_LEFT(parent, field) == elm) \ if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \ RB_LEFT(parent, field) = child; \
else \ else \
RB_RIGHT(parent, field) = child; \ RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \ RB_AUGMENT(parent); \
} else \ } \
else \
RB_ROOT(head) = child; \ RB_ROOT(head) = child; \
if (RB_PARENT(elm, field) == old) \ if (RB_PARENT(elm, field) == old) \
parent = elm; \ parent = elm; \
(elm)->field = (old)->field; \ (elm)->field = (old)->field; \
if (RB_PARENT(old, field)) { \ if (RB_PARENT(old, field)) \
if (RB_LEFT(RB_PARENT(old, field), field) == old)\ { \
RB_LEFT(RB_PARENT(old, field), field) = elm;\ if (RB_LEFT(RB_PARENT(old, field), field) == old) \
RB_LEFT(RB_PARENT(old, field), field) = elm; \
else \ else \
RB_RIGHT(RB_PARENT(old, field), field) = elm;\ RB_RIGHT(RB_PARENT(old, field), field) = elm; \
RB_AUGMENT(RB_PARENT(old, field)); \ RB_AUGMENT(RB_PARENT(old, field)); \
} else \ } \
else \
RB_ROOT(head) = elm; \ RB_ROOT(head) = elm; \
RB_PARENT(RB_LEFT(old, field), field) = elm; \ RB_PARENT(RB_LEFT(old, field), field) = elm; \
if (RB_RIGHT(old, field)) \ if (RB_RIGHT(old, field)) \
RB_PARENT(RB_RIGHT(old, field), field) = elm; \ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
if (parent) { \ if (parent) \
{ \
left = parent; \ left = parent; \
do { \ do \
{ \
RB_AUGMENT(left); \ RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field)) != NULL); \ } while ((left = RB_PARENT(left, field)) != NULL); \
} \ } \
@ -609,30 +697,33 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \
color = RB_COLOR(elm, field); \ color = RB_COLOR(elm, field); \
if (child) \ if (child) \
RB_PARENT(child, field) = parent; \ RB_PARENT(child, field) = parent; \
if (parent) { \ if (parent) \
{ \
if (RB_LEFT(parent, field) == elm) \ if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \ RB_LEFT(parent, field) = child; \
else \ else \
RB_RIGHT(parent, field) = child; \ RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \ RB_AUGMENT(parent); \
} else \ } \
else \
RB_ROOT(head) = child; \ RB_ROOT(head) = child; \
color: \ color: \
if (color == RB_BLACK) \ if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \ name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \ return (old); \
} \ }
#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ #define RB_GENERATE_INSERT(name, type, field, cmp, attr) \
/* Inserts a node into the RB tree */ \ /* Inserts a node into the RB tree */ \
attr struct type * \ attr struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \ name##_RB_INSERT(struct name *head, struct type *elm) \
{ \ { \
struct type *tmp; \ struct type *tmp; \
struct type *parent = NULL; \ struct type *parent = NULL; \
int comp = 0; \ int comp = 0; \
tmp = RB_ROOT(head); \ tmp = RB_ROOT(head); \
while (tmp) { \ while (tmp) \
{ \
parent = tmp; \ parent = tmp; \
comp = (cmp)(elm, parent); \ comp = (cmp)(elm, parent); \
if (comp < 0) \ if (comp < 0) \
@ -643,26 +734,29 @@ name##_RB_INSERT(struct name *head, struct type *elm) \
return (tmp); \ return (tmp); \
} \ } \
RB_SET(elm, parent, field); \ RB_SET(elm, parent, field); \
if (parent != NULL) { \ if (parent != NULL) \
{ \
if (comp < 0) \ if (comp < 0) \
RB_LEFT(parent, field) = elm; \ RB_LEFT(parent, field) = elm; \
else \ else \
RB_RIGHT(parent, field) = elm; \ RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \ RB_AUGMENT(parent); \
} else \ } \
else \
RB_ROOT(head) = elm; \ RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \ name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \ return (NULL); \
} }
#define RB_GENERATE_FIND(name, type, field, cmp, attr) \ #define RB_GENERATE_FIND(name, type, field, cmp, attr) \
/* Finds the node with the same key as elm */ \ /* Finds the node with the same key as elm */ \
attr struct type * \ attr struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \ name##_RB_FIND(struct name *head, struct type *elm) \
{ \ { \
struct type *tmp = RB_ROOT(head); \ struct type *tmp = RB_ROOT(head); \
int comp; \ int comp; \
while (tmp) { \ while (tmp) \
{ \
comp = cmp(elm, tmp); \ comp = cmp(elm, tmp); \
if (comp < 0) \ if (comp < 0) \
tmp = RB_LEFT(tmp, field); \ tmp = RB_LEFT(tmp, field); \
@ -672,19 +766,21 @@ name##_RB_FIND(struct name *head, struct type *elm) \
return (tmp); \ return (tmp); \
} \ } \
return (NULL); \ return (NULL); \
} }
#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \ #define RB_GENERATE_NFIND(name, type, field, cmp, attr) \
/* Finds the first node greater than or equal to the search key */ \ /* Finds the first node greater than or equal to the search key */ \
attr struct type * \ attr struct type * \
name##_RB_NFIND(struct name *head, struct type *elm) \ name##_RB_NFIND(struct name *head, struct type *elm) \
{ \ { \
struct type *tmp = RB_ROOT(head); \ struct type *tmp = RB_ROOT(head); \
struct type *res = NULL; \ struct type *res = NULL; \
int comp; \ int comp; \
while (tmp) { \ while (tmp) \
{ \
comp = cmp(elm, tmp); \ comp = cmp(elm, tmp); \
if (comp < 0) { \ if (comp < 0) \
{ \
res = tmp; \ res = tmp; \
tmp = RB_LEFT(tmp, field); \ tmp = RB_LEFT(tmp, field); \
} \ } \
@ -694,61 +790,70 @@ name##_RB_NFIND(struct name *head, struct type *elm) \
return (tmp); \ return (tmp); \
} \ } \
return (res); \ return (res); \
} }
#define RB_GENERATE_NEXT(name, type, field, attr) \ #define RB_GENERATE_NEXT(name, type, field, attr) \
/* ARGSUSED */ \ /* ARGSUSED */ \
attr struct type * \ attr struct type * \
name##_RB_NEXT(struct type *elm) \ name##_RB_NEXT(struct type *elm) \
{ \ { \
if (RB_RIGHT(elm, field)) { \ if (RB_RIGHT(elm, field)) \
{ \
elm = RB_RIGHT(elm, field); \ elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \ while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \ elm = RB_LEFT(elm, field); \
} else { \ } \
else \
{ \
if (RB_PARENT(elm, field) && \ if (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \
else { \ else \
{ \
while (RB_PARENT(elm, field) && \ while (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \
} \ } \
} \ } \
return (elm); \ return (elm); \
} }
#define RB_GENERATE_PREV(name, type, field, attr) \ #define RB_GENERATE_PREV(name, type, field, attr) \
/* ARGSUSED */ \ /* ARGSUSED */ \
attr struct type * \ attr struct type * \
name##_RB_PREV(struct type *elm) \ name##_RB_PREV(struct type *elm) \
{ \ { \
if (RB_LEFT(elm, field)) { \ if (RB_LEFT(elm, field)) \
{ \
elm = RB_LEFT(elm, field); \ elm = RB_LEFT(elm, field); \
while (RB_RIGHT(elm, field)) \ while (RB_RIGHT(elm, field)) \
elm = RB_RIGHT(elm, field); \ elm = RB_RIGHT(elm, field); \
} else { \ } \
else \
{ \
if (RB_PARENT(elm, field) && \ if (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \
else { \ else \
{ \
while (RB_PARENT(elm, field) && \ while (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field)))\ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \
} \ } \
} \ } \
return (elm); \ return (elm); \
} }
#define RB_GENERATE_MINMAX(name, type, field, attr) \ #define RB_GENERATE_MINMAX(name, type, field, attr) \
attr struct type * \ attr struct type * \
name##_RB_MINMAX(struct name *head, int val) \ name##_RB_MINMAX(struct name *head, int val) \
{ \ { \
struct type *tmp = RB_ROOT(head); \ struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \ struct type *parent = NULL; \
while (tmp) { \ while (tmp) \
{ \
parent = tmp; \ parent = tmp; \
if (val < 0) \ if (val < 0) \
tmp = RB_LEFT(tmp, field); \ tmp = RB_LEFT(tmp, field); \
@ -756,7 +861,7 @@ name##_RB_MINMAX(struct name *head, int val) \
tmp = RB_RIGHT(tmp, field); \ tmp = RB_RIGHT(tmp, field); \
} \ } \
return (parent); \ return (parent); \
} }
#define RB_NEGINF -1 #define RB_NEGINF -1
#define RB_INF 1 #define RB_INF 1

View File

@ -9,33 +9,33 @@ int DLOG_FILE(FILE *F, const char *format, va_list args)
} }
int DLOG_CON(const char *format, int syslog_priority, va_list args) 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 DLOG_FILENAME(const char *filename, const char *format, va_list args)
{ {
int r; int r;
FILE *F = fopen(filename,"at"); FILE *F = fopen(filename, "at");
if (F) if (F)
{ {
r = DLOG_FILE(F, format, args); r = DLOG_FILE(F, format, args);
fclose(F); fclose(F);
} }
else else
r=-1; r = -1;
return r; return r;
} }
static char syslog_buf[1024]; 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) 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 // 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; syslog_buf_sz = 0;
} }
} }
@ -43,27 +43,27 @@ 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) 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; 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); va_copy(args2, args);
DLOG_CON(format,syslog_priority,args2); 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: case LOG_TARGET_CONSOLE:
r = DLOG_CON(format,syslog_priority,args); r = DLOG_CON(format, syslog_priority, args);
break; break;
case LOG_TARGET_FILE: case LOG_TARGET_FILE:
r = DLOG_FILENAME(params.debug_logfile,format,args); r = DLOG_FILENAME(params.debug_logfile, format, args);
break; break;
case LOG_TARGET_SYSLOG: case LOG_TARGET_SYSLOG:
// skip newlines // skip newlines
syslog_buffered(syslog_priority,format,args); syslog_buffered(syslog_priority, format, args);
r = 1; r = 1;
break; break;
default: default:
@ -105,11 +105,10 @@ int DLOG_PERROR(const char *s)
return DLOG_ERR("%s: %s\n", s, strerror(errno)); return DLOG_ERR("%s: %s\n", s, strerror(errno));
} }
int LOG_APPEND(const char *filename, const char *format, va_list args) int LOG_APPEND(const char *filename, const char *format, va_list args)
{ {
int r; int r;
FILE *F = fopen(filename,"at"); FILE *F = fopen(filename, "at");
if (F) if (F)
{ {
fprint_localtime(F); fprint_localtime(F);
@ -119,7 +118,7 @@ int LOG_APPEND(const char *filename, const char *format, va_list args)
fclose(F); fclose(F);
} }
else else
r=-1; r = -1;
return r; return r;
} }

View File

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

View File

@ -6,7 +6,8 @@
#define DESTROY_STR_POOL(etype, ppool) \ #define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \ etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) { \ HASH_ITER(hh, *ppool, elem, tmp) \
{ \
free(elem->str); \ free(elem->str); \
HASH_DEL(*ppool, elem); \ HASH_DEL(*ppool, elem); \
free(elem); \ free(elem); \
@ -14,7 +15,7 @@
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \ #define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \ etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \ if (!(elem = (etype *)malloc(sizeof(etype)))) \
return false; \ return false; \
if (!(elem->str = malloc(keystr_len + 1))) \ if (!(elem->str = malloc(keystr_len + 1))) \
{ \ { \
@ -32,7 +33,6 @@
return false; \ return false; \
} }
#undef uthash_nonfatal_oom #undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt) #define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
static bool oom = false; static bool oom = false;
@ -65,13 +65,8 @@ void StrPoolDestroy(strpool **pp)
DESTROY_STR_POOL(strpool, pp) DESTROY_STR_POOL(strpool, pp)
} }
void HostFailPoolDestroy(hostfail_pool **pp){
DESTROY_STR_POOL(hostfail_pool, pp)} hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time)
void HostFailPoolDestroy(hostfail_pool **pp)
{
DESTROY_STR_POOL(hostfail_pool, pp)
}
hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
{ {
size_t slen = strlen(s); size_t slen = strlen(s);
ADD_STR_POOL(hostfail_pool, pp, s, slen) ADD_STR_POOL(hostfail_pool, pp, s, slen)
@ -79,7 +74,7 @@ hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
elem->counter = 0; elem->counter = 0;
return elem; return elem;
} }
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s) hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s)
{ {
hostfail_pool *elem; hostfail_pool *elem;
HASH_FIND_STR(p, s, 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) void HostFailPoolPurgeRateLimited(hostfail_pool **pp)
{ {
time_t now = time(NULL); time_t now = time(NULL);
@ -120,14 +115,14 @@ void HostFailPoolDump(hostfail_pool *p)
hostfail_pool *elem, *tmp; hostfail_pool *elem, *tmp;
time_t now = time(NULL); time_t now = time(NULL);
HASH_ITER(hh, p, elem, tmp) 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) bool strlist_add(struct str_list_head *head, const char *filename)
{ {
struct str_list *entry = malloc(sizeof(struct str_list)); struct str_list *entry = malloc(sizeof(struct str_list));
if (!entry) return false; if (!entry)
return false;
entry->str = strdup(filename); entry->str = strdup(filename);
if (!entry->str) if (!entry->str)
{ {
@ -139,7 +134,8 @@ bool strlist_add(struct str_list_head *head, const char *filename)
} }
static void strlist_entry_destroy(struct str_list *entry) static void strlist_entry_destroy(struct str_list *entry)
{ {
if (entry->str) free(entry->str); if (entry->str)
free(entry->str);
free(entry); free(entry);
} }
void strlist_destroy(struct str_list_head *head) void strlist_destroy(struct str_list_head *head)

View File

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

View File

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

View File

@ -7,8 +7,8 @@
extern const char *http_methods[9]; extern const char *http_methods[9];
const char *HttpMethod(const uint8_t *data, size_t len); const char *HttpMethod(const uint8_t *data, size_t len);
bool IsHttp(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 HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs);
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);
// header must be passed like this : "\nHost:" // 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 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); 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); int HttpReplyCode(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply // must be pre-checked by IsHttpReply
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host); bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
enum httpreqpos { httpreqpos_none = 0, httpreqpos_method, httpreqpos_host, httpreqpos_pos }; enum httpreqpos
{
httpreqpos_none = 0,
httpreqpos_method,
httpreqpos_host,
httpreqpos_pos
};
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz); size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz);
uint16_t TLSRecordDataLen(const uint8_t *data); uint16_t TLSRecordDataLen(const uint8_t *data);
@ -29,5 +35,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK); bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK); bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK); bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_pos }; enum tlspos
{
tlspos_none = 0,
tlspos_sni,
tlspos_sniext,
tlspos_pos
};
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type); size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);

View File

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

View File

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

View File

@ -13,7 +13,8 @@ struct resolve_item
int ga_res; // getaddrinfo result code int ga_res; // getaddrinfo result code
uint16_t port; // request port uint16_t port; // request port
void *ptr; void *ptr;
TAILQ_ENTRY(resolve_item) next; TAILQ_ENTRY(resolve_item)
next;
}; };
struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr); struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr);

View File

@ -23,103 +23,102 @@
// block most of the undesired syscalls to harden against code execution // block most of the undesired syscalls to harden against code execution
static long blocked_syscalls[] = { static long blocked_syscalls[] = {
#ifdef SYS_execv #ifdef SYS_execv
SYS_execv, SYS_execv,
#endif #endif
SYS_execve, SYS_execve,
#ifdef SYS_execveat #ifdef SYS_execveat
SYS_execveat, SYS_execveat,
#endif #endif
#ifdef SYS_exec_with_loader #ifdef SYS_exec_with_loader
SYS_exec_with_loader, SYS_exec_with_loader,
#endif #endif
#ifdef SYS_osf_execve #ifdef SYS_osf_execve
SYS_osf_execve, SYS_osf_execve,
#endif #endif
#ifdef SYS_uselib #ifdef SYS_uselib
SYS_uselib, SYS_uselib,
#endif #endif
#ifdef SYS_unlink #ifdef SYS_unlink
SYS_unlink, SYS_unlink,
#endif #endif
SYS_unlinkat, SYS_unlinkat,
#ifdef SYS_chmod #ifdef SYS_chmod
SYS_chmod, SYS_chmod,
#endif #endif
SYS_fchmod,SYS_fchmodat, SYS_fchmod, SYS_fchmodat,
#ifdef SYS_chown #ifdef SYS_chown
SYS_chown, SYS_chown,
#endif #endif
#ifdef SYS_chown32 #ifdef SYS_chown32
SYS_chown32, SYS_chown32,
#endif #endif
SYS_fchown, SYS_fchown,
#ifdef SYS_fchown32 #ifdef SYS_fchown32
SYS_fchown32, SYS_fchown32,
#endif #endif
#ifdef SYS_lchown #ifdef SYS_lchown
SYS_lchown, SYS_lchown,
#endif #endif
#ifdef SYS_lchown32 #ifdef SYS_lchown32
SYS_lchown32, SYS_lchown32,
#endif #endif
SYS_fchownat, SYS_fchownat,
#ifdef SYS_symlink #ifdef SYS_symlink
SYS_symlink, SYS_symlink,
#endif #endif
SYS_symlinkat, SYS_symlinkat,
#ifdef SYS_link #ifdef SYS_link
SYS_link, SYS_link,
#endif #endif
SYS_linkat, SYS_linkat,
SYS_truncate, SYS_truncate,
#ifdef SYS_truncate64 #ifdef SYS_truncate64
SYS_truncate64, SYS_truncate64,
#endif #endif
SYS_ftruncate, SYS_ftruncate,
#ifdef SYS_ftruncate64 #ifdef SYS_ftruncate64
SYS_ftruncate64, SYS_ftruncate64,
#endif #endif
#ifdef SYS_mknod #ifdef SYS_mknod
SYS_mknod, SYS_mknod,
#endif #endif
SYS_mknodat, SYS_mknodat,
#ifdef SYS_mkdir #ifdef SYS_mkdir
SYS_mkdir, SYS_mkdir,
#endif #endif
SYS_mkdirat, SYS_mkdirat,
#ifdef SYS_rmdir #ifdef SYS_rmdir
SYS_rmdir, SYS_rmdir,
#endif #endif
#ifdef SYS_rename #ifdef SYS_rename
SYS_rename, SYS_rename,
#endif #endif
#ifdef SYS_renameat2 #ifdef SYS_renameat2
SYS_renameat2, SYS_renameat2,
#endif #endif
#ifdef SYS_renameat #ifdef SYS_renameat
SYS_renameat, SYS_renameat,
#endif #endif
#ifdef SYS_readdir #ifdef SYS_readdir
SYS_readdir, SYS_readdir,
#endif #endif
#ifdef SYS_getdents #ifdef SYS_getdents
SYS_getdents, SYS_getdents,
#endif #endif
#ifdef SYS_getdents64 #ifdef SYS_getdents64
SYS_getdents64, SYS_getdents64,
#endif #endif
#ifdef SYS_process_vm_readv #ifdef SYS_process_vm_readv
SYS_process_vm_readv, SYS_process_vm_readv,
#endif #endif
#ifdef SYS_process_vm_writev #ifdef SYS_process_vm_writev
SYS_process_vm_writev, SYS_process_vm_writev,
#endif #endif
#ifdef SYS_process_madvise #ifdef SYS_process_madvise
SYS_process_madvise, SYS_process_madvise,
#endif #endif
SYS_kill, SYS_ptrace SYS_kill, SYS_ptrace};
}; #define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls))
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls))
static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k) static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k)
{ {
@ -132,13 +131,13 @@ static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf,
static bool set_seccomp(void) static bool set_seccomp(void)
{ {
#ifdef __X32_SYSCALL_BIT #ifdef __X32_SYSCALL_BIT
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT) #define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
#else #else
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT) #define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
#endif #endif
struct sock_filter sockf[SECCOMP_PROG_SIZE]; struct sock_filter sockf[SECCOMP_PROG_SIZE];
struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE, .filter = sockf }; struct sock_fprog prog = {.len = SECCOMP_PROG_SIZE, .filter = sockf};
int i,idx=0; int i, idx = 0;
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr); set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr);
#ifdef __X32_SYSCALL_BIT #ifdef __X32_SYSCALL_BIT
@ -151,16 +150,16 @@ static bool set_seccomp(void)
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr);
#endif #endif
/* /*
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr // ! 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_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_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_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 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++) 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_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
@ -174,30 +173,29 @@ bool sec_harden(void)
DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)"); DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)");
return false; return false;
} }
#if ARCH_NR!=0 #if ARCH_NR != 0
if (!set_seccomp()) if (!set_seccomp())
{ {
DLOG_PERROR("seccomp"); DLOG_PERROR("seccomp");
if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n"); if (errno == EINVAL)
DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
return false; return false;
} }
#endif #endif
return true; return true;
} }
bool checkpcap(uint64_t caps) bool checkpcap(uint64_t caps)
{ {
if (!caps) return true; // no special caps reqd if (!caps)
return true; // no special caps reqd
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()}; struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
struct __user_cap_data_struct cd[2]; struct __user_cap_data_struct cd[2];
uint32_t c0 = (uint32_t)caps; 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) bool setpcap(uint64_t caps)
{ {
@ -206,10 +204,10 @@ bool setpcap(uint64_t caps)
cd[0].effective = cd[0].permitted = (uint32_t)caps; cd[0].effective = cd[0].permitted = (uint32_t)caps;
cd[0].inheritable = 0; 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; cd[1].inheritable = 0;
return !capset(&ch,cd); return !capset(&ch, cd);
} }
int getmaxcap(void) int getmaxcap(void)
{ {
@ -221,18 +219,17 @@ int getmaxcap(void)
fclose(F); fclose(F);
} }
return maxcap; return maxcap;
} }
bool dropcaps(void) bool dropcaps(void)
{ {
uint64_t caps = 0; uint64_t caps = 0;
int maxcap = getmaxcap(); int maxcap = getmaxcap();
if (setpcap(caps|(1<<CAP_SETPCAP))) if (setpcap(caps | (1 << CAP_SETPCAP)))
{ {
for (int cap = 0; cap <= maxcap; cap++) 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_ERR("could not drop bound cap %d\n", cap);
DLOG_PERROR("cap_drop_bound"); DLOG_PERROR("cap_drop_bound");
@ -257,13 +254,11 @@ bool sec_harden(void)
#endif // __linux__ #endif // __linux__
bool can_drop_root(void) bool can_drop_root(void)
{ {
#ifdef __linux__ #ifdef __linux__
// has some caps // 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 #else
// effective root // effective root
return !geteuid(); return !geteuid();
@ -280,7 +275,7 @@ bool droproot(uid_t uid, gid_t gid)
} }
#endif #endif
// drop all SGIDs // drop all SGIDs
if (setgroups(0,NULL)) if (setgroups(0, NULL))
{ {
DLOG_PERROR("setgroups"); DLOG_PERROR("setgroups");
return false; return false;
@ -304,19 +299,19 @@ bool droproot(uid_t uid, gid_t gid)
void print_id(void) void print_id(void)
{ {
int i,N; int i, N;
gid_t g[128]; gid_t g[128];
DLOG_CONDUP("Running as UID=%u GID=",getuid()); DLOG_CONDUP("Running as UID=%u GID=", getuid());
N=getgroups(sizeof(g)/sizeof(*g),g); N = getgroups(sizeof(g) / sizeof(*g), g);
if (N>0) if (N > 0)
{ {
for(i=0;i<N;i++) for (i = 0; i < N; i++)
DLOG_CONDUP(i==(N-1) ? "%u" : "%u,", g[i]); DLOG_CONDUP(i == (N - 1) ? "%u" : "%u,", g[i]);
DLOG_CONDUP("\n"); DLOG_CONDUP("\n");
} }
else else
DLOG_CONDUP("%u\n",getgid()); DLOG_CONDUP("%u\n", getgid());
} }
void daemonize(void) void daemonize(void)

View File

@ -22,61 +22,61 @@ bool dropcaps(void);
#if defined(__aarch64__) #if defined(__aarch64__)
# define ARCH_NR AUDIT_ARCH_AARCH64 #define ARCH_NR AUDIT_ARCH_AARCH64
#elif defined(__amd64__) #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__)) #elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__))
# if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_ARM #define ARCH_NR AUDIT_ARCH_ARM
# else #else
# define ARCH_NR AUDIT_ARCH_ARMEB #define ARCH_NR AUDIT_ARCH_ARMEB
# endif #endif
#elif defined(__i386__) #elif defined(__i386__)
# define ARCH_NR AUDIT_ARCH_I386 #define ARCH_NR AUDIT_ARCH_I386
#elif defined(__mips__) #elif defined(__mips__)
#if _MIPS_SIM == _MIPS_SIM_ABI32 #if _MIPS_SIM == _MIPS_SIM_ABI32
# if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_MIPSEL #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
#else #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 #endif
#elif defined(__PPC64__) #elif defined(__PPC64__)
# if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_PPC64LE #define ARCH_NR AUDIT_ARCH_PPC64LE
# else #else
# define ARCH_NR AUDIT_ARCH_PPC64 #define ARCH_NR AUDIT_ARCH_PPC64
# endif #endif
#elif defined(__PPC__) #elif defined(__PPC__)
# define ARCH_NR AUDIT_ARCH_PPC #define ARCH_NR AUDIT_ARCH_PPC
#elif __riscv && __riscv_xlen == 64 #elif __riscv && __riscv_xlen == 64
# define ARCH_NR AUDIT_ARCH_RISCV64 #define ARCH_NR AUDIT_ARCH_RISCV64
#else #else
# error "Platform does not support seccomp filter yet" #error "Platform does not support seccomp filter yet"
#endif #endif

View File

@ -3,42 +3,40 @@
#include <stdint.h> #include <stdint.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#pragma pack(push,1) #pragma pack(push, 1)
#define S4_CMD_CONNECT 1 #define S4_CMD_CONNECT 1
#define S4_CMD_BIND 2 #define S4_CMD_BIND 2
typedef struct typedef struct
{ {
uint8_t ver,cmd; uint8_t ver, cmd;
uint16_t port; uint16_t port;
uint32_t ip; uint32_t ip;
} s4_req; } s4_req;
#define S4_REQ_HEADER_VALID(r,l) (l>=sizeof(s4_req) && r->ver==4) #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_CONNECT_VALID(r, l) (S4_REQ_HEADER_VALID(r, l) && r->cmd == S4_CMD_CONNECT)
#define S4_REP_OK 90 #define S4_REP_OK 90
#define S4_REP_FAILED 91 #define S4_REP_FAILED 91
typedef struct typedef struct
{ {
uint8_t zero,rep; uint8_t zero, rep;
uint16_t port; uint16_t port;
uint32_t ip; uint32_t ip;
} s4_rep; } s4_rep;
#define S5_AUTH_NONE 0 #define S5_AUTH_NONE 0
#define S5_AUTH_GSSAPI 1 #define S5_AUTH_GSSAPI 1
#define S5_AUTH_USERPASS 2 #define S5_AUTH_USERPASS 2
#define S5_AUTH_UNACCEPTABLE 0xFF #define S5_AUTH_UNACCEPTABLE 0xFF
typedef struct typedef struct
{ {
uint8_t ver,nmethods,methods[255]; uint8_t ver, nmethods, methods[255];
} s5_handshake; } 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 typedef struct
{ {
uint8_t ver,method; uint8_t ver, method;
} s5_handshake_ack; } s5_handshake_ack;
#define S5_CMD_CONNECT 1 #define S5_CMD_CONNECT 1
@ -49,26 +47,30 @@ typedef struct
#define S5_ATYP_IP6 4 #define S5_ATYP_IP6 4
typedef struct typedef struct
{ {
uint8_t ver,cmd,rsv,atyp; uint8_t ver, cmd, rsv, atyp;
union { union
struct { {
struct
{
struct in_addr addr; struct in_addr addr;
uint16_t port; uint16_t port;
} d4; } d4;
struct { struct
{
struct in6_addr addr; struct in6_addr addr;
uint16_t port; uint16_t port;
} d6; } d6;
struct { struct
{
uint8_t len; uint8_t len;
char domport[255+2]; // max hostname + binary port char domport[255 + 2]; // max hostname + binary port
} dd; } dd;
}; };
} s5_req; } s5_req;
#define S5_REQ_HEADER_VALID(r,l) (l>=4 && r->ver==5) #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_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_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_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_OK 0
#define S5_REP_GENERAL_FAILURE 1 #define S5_REP_GENERAL_FAILURE 1
@ -81,9 +83,11 @@ typedef struct
#define S5_REP_ADDR_TYPE_NOT_SUPPORTED 8 #define S5_REP_ADDR_TYPE_NOT_SUPPORTED 8
typedef struct typedef struct
{ {
uint8_t ver,rep,rsv,atyp; uint8_t ver, rep, rsv, atyp;
union { union
struct { {
struct
{
struct in_addr addr; struct in_addr addr;
uint16_t port; uint16_t port;
} d4; } d4;

View File

@ -9,7 +9,7 @@
#include <stdio.h> #include <stdio.h>
// segment buffer has at least 5 extra bytes to extend data block // segment buffer has at least 5 extra bytes to extend data block
void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags) void tamper_out(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size, size_t *split_pos, uint8_t *split_flags)
{ {
uint8_t *p, *pp, *pHost = NULL; uint8_t *p, *pp, *pHost = NULL;
size_t method_len = 0, pos; size_t method_len = 0, pos;
@ -19,26 +19,30 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
DBGPRINT("tamper_out\n"); DBGPRINT("tamper_out\n");
*split_pos=0; *split_pos = 0;
*split_flags=0; *split_flags = 0;
if ((method = HttpMethod(segment,*size))) if ((method = HttpMethod(segment, *size)))
{ {
method_len = strlen(method)-2; method_len = strlen(method) - 2;
VPRINT("Data block looks like http request start : %s\n", method); VPRINT("Data block looks like HTTP request start : %s\n", method);
if (!ctrack->l7proto) ctrack->l7proto=HTTP; if (!ctrack->l7proto)
ctrack->l7proto = HTTP;
// cpu saving : we search host only if and when required. we do not research host every time we need its position // cpu saving : we search host only if and when required. we do not research host every time we need its position
if ((params.hostlist || params.hostlist_exclude) && HttpFindHost(&pHost,segment,*size)) if ((params.hostlist || params.hostlist_exclude) && HttpFindHost(&pHost, segment, *size))
{ {
p = pHost + 5; p = pHost + 5;
while (p < (segment + *size) && (*p == ' ' || *p == '\t')) p++; while (p < (segment + *size) && (*p == ' ' || *p == '\t'))
p++;
pp = p; pp = p;
while (pp < (segment + *size) && (pp - p) < (sizeof(Host) - 1) && *pp != '\r' && *pp != '\n') pp++; while (pp < (segment + *size) && (pp - p) < (sizeof(Host) - 1) && *pp != '\r' && *pp != '\n')
pp++;
memcpy(Host, p, pp - p); memcpy(Host, p, pp - p);
Host[pp - p] = '\0'; Host[pp - p] = '\0';
bHaveHost = true; bHaveHost = true;
VPRINT("Requested Host is : %s\n", Host); VPRINT("Requested Host is : %s\n", Host);
for(pc = Host; *pc; pc++) *pc=tolower(*pc); for (pc = Host; *pc; pc++)
*pc = tolower(*pc);
bBypass = !HostlistCheck(Host, &bHostExcluded); bBypass = !HostlistCheck(Host, &bHostExcluded);
} }
if (!bBypass) if (!bBypass)
@ -48,7 +52,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
p = pp = segment; p = pp = segment;
while ((p = memmem(p, segment + *size - p, "\r\n", 2))) while ((p = memmem(p, segment + *size - p, "\r\n", 2)))
{ {
*p = '\n'; p++; *p = '\n';
p++;
memmove(p, p + 1, segment + *size - p - 1); memmove(p, p + 1, segment + *size - p - 1);
(*size)--; (*size)--;
if (pp == (p - 1)) if (pp == (p - 1))
@ -61,13 +66,14 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
} }
pHost = NULL; // invalidate pHost = NULL; // invalidate
} }
if (params.methodeol && (*size+1+!params.unixeol)<=segment_buffer_size) if (params.methodeol && (*size + 1 + !params.unixeol) <= segment_buffer_size)
{ {
VPRINT("Adding EOL before method\n"); VPRINT("Adding EOL before method\n");
if (params.unixeol) if (params.unixeol)
{ {
memmove(segment + 1, segment, *size); memmove(segment + 1, segment, *size);
(*size)++;; (*size)++;
;
segment[0] = '\n'; segment[0] = '\n';
} }
else else
@ -79,7 +85,7 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
} }
pHost = NULL; // invalidate pHost = NULL; // invalidate
} }
if (params.methodspace && *size<segment_buffer_size) if (params.methodspace && *size < segment_buffer_size)
{ {
// we only work with data blocks looking as HTTP query, so method is at the beginning // we only work with data blocks looking as HTTP query, so method is at the beginning
VPRINT("Adding extra space after method\n"); VPRINT("Adding extra space after method\n");
@ -88,12 +94,14 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
memmove(p + 1, p, *size - pos); memmove(p + 1, p, *size - pos);
*p = ' '; // insert extra space *p = ' '; // insert extra space
(*size)++; // block will grow by 1 byte (*size)++; // block will grow by 1 byte
if (pHost) pHost++; // Host: position will move by 1 byte if (pHost)
pHost++; // Host: position will move by 1 byte
} }
if ((params.hostdot || params.hosttab) && *size<segment_buffer_size && HttpFindHost(&pHost,segment,*size)) if ((params.hostdot || params.hosttab) && *size < segment_buffer_size && HttpFindHost(&pHost, segment, *size))
{ {
p = pHost + 5; p = pHost + 5;
while (p < (segment + *size) && *p != '\r' && *p != '\n') p++; while (p < (segment + *size) && *p != '\r' && *p != '\n')
p++;
if (p < (segment + *size)) if (p < (segment + *size))
{ {
pos = p - segment; pos = p - segment;
@ -103,15 +111,15 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
(*size)++; // block will grow by 1 byte (*size)++; // block will grow by 1 byte
} }
} }
if (params.domcase && HttpFindHost(&pHost,segment,*size)) if (params.domcase && HttpFindHost(&pHost, segment, *size))
{ {
p = pHost + 5; p = pHost + 5;
pos = p - segment; 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++) for (; p < (segment + *size) && *p != '\r' && *p != '\n'; p++)
*p = (((size_t)p) & 1) ? tolower(*p) : toupper(*p); *p = (((size_t)p) & 1) ? tolower(*p) : toupper(*p);
} }
if (params.hostnospace && HttpFindHost(&pHost,segment,*size) && (pHost+5)<(segment+*size) && pHost[5] == ' ') if (params.hostnospace && HttpFindHost(&pHost, segment, *size) && (pHost + 5) < (segment + *size) && pHost[5] == ' ')
{ {
p = pHost + 6; p = pHost + 6;
pos = p - segment; pos = p - segment;
@ -119,25 +127,25 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
memmove(p - 1, p, *size - pos); memmove(p - 1, p, *size - pos);
(*size)--; // block will shrink by 1 byte (*size)--; // block will shrink by 1 byte
} }
if (params.hostcase && HttpFindHost(&pHost,segment,*size)) if (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); 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); 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] // add : XXXXX: <padding?[\r\n|\n]
char s[8]; char s[8];
size_t hsize = params.unixeol ? 8 : 9; 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"); VPRINT("could not add host padding : buffer too small\n");
else 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); VPRINT("host padding reduced to %zu bytes : buffer too small\n", hostpad);
} }
else else
@ -147,50 +155,55 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
pos = p - segment; pos = p - segment;
memmove(p + hostpad, p, *size - pos); memmove(p + hostpad, p, *size - pos);
(*size) += hostpad; (*size) += hostpad;
while(hostpad) while (hostpad)
{ {
#define MAX_HDR_SIZE 2048 #define MAX_HDR_SIZE 2048
size_t padsize = hostpad > hsize ? hostpad-hsize : 0; size_t padsize = hostpad > hsize ? hostpad - hsize : 0;
if (padsize>MAX_HDR_SIZE) padsize=MAX_HDR_SIZE; if (padsize > MAX_HDR_SIZE)
padsize = MAX_HDR_SIZE;
// if next header would be too small then add extra padding to the current one // if next header would be too small then add extra padding to the current one
if ((hostpad-padsize-hsize)<hsize) padsize+=hostpad-padsize-hsize; if ((hostpad - padsize - hsize) < hsize)
snprintf(s,sizeof(s),"%c%04x: ", 'a'+rand()%('z'-'a'+1), rand() & 0xFFFF); padsize += hostpad - padsize - hsize;
memcpy(p,s,7); snprintf(s, sizeof(s), "%c%04x: ", 'a' + rand() % ('z' - 'a' + 1), rand() & 0xFFFF);
p+=7; memcpy(p, s, 7);
memset(p,'a'+rand()%('z'-'a'+1),padsize); p += 7;
p+=padsize; memset(p, 'a' + rand() % ('z' - 'a' + 1), padsize);
p += padsize;
if (params.unixeol) if (params.unixeol)
*p++='\n'; *p++ = '\n';
else else
{ {
*p++='\r'; *p++ = '\r';
*p++='\n'; *p++ = '\n';
} }
hostpad-=hsize+padsize; hostpad -= hsize + padsize;
} }
pHost = NULL; // invalidate pHost = NULL; // invalidate
} }
} }
*split_pos = HttpPos(params.split_http_req, params.split_pos, segment, *size); *split_pos = HttpPos(params.split_http_req, params.split_pos, segment, *size);
if (params.disorder_http) *split_flags |= SPLIT_FLAG_DISORDER; if (params.disorder_http)
if (params.oob_http) *split_flags |= SPLIT_FLAG_OOB; *split_flags |= SPLIT_FLAG_DISORDER;
if (params.oob_http)
*split_flags |= SPLIT_FLAG_OOB;
} }
else else
{ {
VPRINT("Not acting on this request\n"); 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; size_t tpos = 0, spos = 0;
if (!ctrack->l7proto) ctrack->l7proto=TLS; if (!ctrack->l7proto)
ctrack->l7proto = TLS;
VPRINT("packet contains TLS ClientHello\n"); VPRINT("packet contains TLS ClientHello\n");
// we need host only if hostlist is present // we need host only if hostlist is present
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; bHaveHost = true;
bBypass = !HostlistCheck(Host, &bHostExcluded); bBypass = !HostlistCheck(Host, &bHostExcluded);
} }
@ -202,39 +215,43 @@ 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); 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); tpos = TLSPos(params.tlsrec, params.tlsrec_pos + 5, segment, *size, 0);
if (tpos>5) if (tpos > 5)
{ {
// construct 2 TLS records from one // construct 2 TLS records from one
uint16_t l = pntoh16(segment+3); // length uint16_t l = pntoh16(segment + 3); // length
if (l>=2) if (l >= 2)
{ {
// length is checked in IsTLSClientHello and cannot exceed buffer size // length is checked in IsTLSClientHello and cannot exceed buffer size
if ((tpos-5)>=l) tpos=5+1; if ((tpos - 5) >= l)
VPRINT("making 2 TLS records at pos %zu\n",tpos); tpos = 5 + 1;
memmove(segment+tpos+5,segment+tpos,*size-tpos); VPRINT("making 2 TLS records at pos %zu\n", tpos);
memmove(segment + tpos + 5, segment + tpos, *size - tpos);
segment[tpos] = segment[0]; segment[tpos] = segment[0];
segment[tpos+1] = segment[1]; segment[tpos + 1] = segment[1];
segment[tpos+2] = segment[2]; segment[tpos + 2] = segment[2];
phton16(segment+tpos+3,l-(tpos-5)); phton16(segment + tpos + 3, l - (tpos - 5));
phton16(segment+3,tpos-5); phton16(segment + 3, tpos - 5);
*size += 5; *size += 5;
// split pos present and it is not before tlsrec split. increase split pos by tlsrec header size (5 bytes) // split pos present and it is not before tlsrec split. increase split pos by tlsrec header size (5 bytes)
if (spos && spos>=tpos) spos+=5; if (spos && spos >= tpos)
spos += 5;
} }
} }
} }
if (spos && spos < *size) if (spos && spos < *size)
{ {
VPRINT("split pos %zu\n",spos); VPRINT("split pos %zu\n", spos);
*split_pos = spos; *split_pos = spos;
} }
if (params.disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER; if (params.disorder_tls)
if (params.oob_tls) *split_flags |= SPLIT_FLAG_OOB; *split_flags |= SPLIT_FLAG_DISORDER;
if (params.oob_tls)
*split_flags |= SPLIT_FLAG_OOB;
} }
} }
else if (params.split_any_protocol && params.split_pos < *size) else if (params.split_any_protocol && params.split_pos < *size)
@ -243,11 +260,14 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
if (bHaveHost && bBypass && !bHostExcluded && *params.hostlist_auto_filename) if (bHaveHost && bBypass && !bHostExcluded && *params.hostlist_auto_filename)
{ {
DBGPRINT("tamper_out put hostname : %s\n", Host); DBGPRINT("tamper_out put hostname : %s\n", Host);
if (ctrack->hostname) free(ctrack->hostname); if (ctrack->hostname)
ctrack->hostname=strdup(Host); free(ctrack->hostname);
ctrack->hostname = strdup(Host);
} }
if (params.disorder) *split_flags |= SPLIT_FLAG_DISORDER; if (params.disorder)
if (params.oob) *split_flags |= SPLIT_FLAG_OOB; *split_flags |= SPLIT_FLAG_DISORDER;
if (params.oob)
*split_flags |= SPLIT_FLAG_OOB;
} }
static void auto_hostlist_reset_fail_counter(const char *hostname) static void auto_hostlist_reset_fail_counter(const char *hostname)
@ -289,7 +309,7 @@ static void auto_hostlist_failed(const char *hostname)
HostFailPoolDel(&params.hostlist_auto_fail_counters, fail_counter); HostFailPoolDel(&params.hostlist_auto_fail_counters, fail_counter);
VPRINT("auto hostlist : rechecking %s to avoid duplicates\n", hostname); VPRINT("auto hostlist : rechecking %s to avoid duplicates\n", hostname);
bool bExcluded=false; bool bExcluded = false;
if (!HostlistCheck(hostname, &bExcluded) && !bExcluded) if (!HostlistCheck(hostname, &bExcluded) && !bExcluded)
{ {
VPRINT("auto hostlist : adding %s\n", hostname); 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); DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname);
@ -324,9 +344,9 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
{ {
HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters);
if (ctrack->l7proto==HTTP && ctrack->hostname) if (ctrack->l7proto == HTTP && ctrack->hostname)
{ {
if (IsHttpReply(segment,*size)) if (IsHttpReply(segment, *size))
{ {
VPRINT("incoming HTTP reply detected for hostname %s\n", ctrack->hostname); VPRINT("incoming HTTP reply detected for hostname %s\n", ctrack->hostname);
bFail = HttpReplyLooksLikeDPIRedirect(segment, *size, 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 // received not http reply. do not monitor this connection anymore
VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname); VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname);
} }
if (bFail) auto_hostlist_failed(ctrack->hostname); if (bFail)
auto_hostlist_failed(ctrack->hostname);
} }
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->hostname); if (!bFail)
auto_hostlist_reset_fail_counter(ctrack->hostname);
} }
ctrack->bTamperInCutoff = true; ctrack->bTamperInCutoff = true;
} }
@ -356,7 +376,8 @@ void rst_in(t_ctrack *ctrack)
{ {
DBGPRINT("rst_in hostname=%s\n", ctrack->hostname); DBGPRINT("rst_in hostname=%s\n", ctrack->hostname);
if (!*params.hostlist_auto_filename) return; if (!*params.hostlist_auto_filename)
return;
HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters);
@ -371,7 +392,8 @@ void hup_out(t_ctrack *ctrack)
{ {
DBGPRINT("hup_out hostname=%s\n", ctrack->hostname); DBGPRINT("hup_out hostname=%s\n", ctrack->hostname);
if (!*params.hostlist_auto_filename) return; if (!*params.hostlist_auto_filename)
return;
HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters);

View File

@ -7,7 +7,12 @@
#define SPLIT_FLAG_DISORDER 0x01 #define SPLIT_FLAG_DISORDER 0x01
#define SPLIT_FLAG_OOB 0x02 #define SPLIT_FLAG_OOB 0x02
typedef enum {UNKNOWN=0, HTTP, TLS} t_l7proto; typedef enum
{
UNKNOWN = 0,
HTTP,
TLS
} t_l7proto;
typedef struct typedef struct
{ {
// common state // common state
@ -17,8 +22,8 @@ typedef struct
char *hostname; char *hostname;
} t_ctrack; } t_ctrack;
void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags); void 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_in(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size);
// connection reset by remote leg // connection reset by remote leg
void rst_in(t_ctrack *ctrack); void rst_in(t_ctrack *ctrack);
// local leg closed connection (timeout waiting response ?) // local leg closed connection (timeout waiting response ?)

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@
#define BACKLOG 10 #define BACKLOG 10
#define MAX_EPOLL_EVENTS 64 #define MAX_EPOLL_EVENTS 64
#define IP_TRANSPARENT 19 //So that application compiles on OpenWRT #define IP_TRANSPARENT 19 // So that application compiles on OpenWrt
#define SPLICE_LEN 65536 #define SPLICE_LEN 65536
#define DEFAULT_MAX_CONN 512 #define DEFAULT_MAX_CONN 512
#define DEFAULT_MAX_ORPHAN_TIME 5 #define DEFAULT_MAX_ORPHAN_TIME 5
@ -19,9 +19,10 @@
int event_loop(const int *listen_fd, size_t listen_fd_ct); int event_loop(const int *listen_fd, size_t listen_fd_ct);
//Three different states of a connection // Three different states of a connection
enum{ enum
CONN_UNAVAILABLE=0, // connecting {
CONN_UNAVAILABLE = 0, // connecting
CONN_AVAILABLE, // operational CONN_AVAILABLE, // operational
CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked
CONN_CLOSED // will be deleted soon CONN_CLOSED // will be deleted soon
@ -34,13 +35,14 @@ typedef uint8_t conn_state_t;
struct send_buffer struct send_buffer
{ {
uint8_t *data; uint8_t *data;
size_t len,pos; size_t len, pos;
int ttl, flags; int ttl, flags;
}; };
typedef struct send_buffer send_buffer_t; typedef struct send_buffer send_buffer_t;
enum{ enum
CONN_TYPE_TRANSPARENT=0, {
CONN_TYPE_TRANSPARENT = 0,
CONN_TYPE_SOCKS CONN_TYPE_SOCKS
}; };
typedef uint8_t conn_type_t; typedef uint8_t conn_type_t;
@ -59,8 +61,9 @@ struct tproxy_conn
time_t orphan_since; time_t orphan_since;
// socks5 state machine // socks5 state machine
enum { enum
S_WAIT_HANDSHAKE=0, {
S_WAIT_HANDSHAKE = 0,
S_WAIT_REQUEST, S_WAIT_REQUEST,
S_WAIT_RESOLVE, S_WAIT_RESOLVE,
S_WAIT_CONNECTION, S_WAIT_CONNECTION,
@ -70,11 +73,11 @@ struct tproxy_conn
struct resolve_item *socks_ri; struct resolve_item *socks_ri;
// these value are used in flow control. we do not use ET (edge triggered) polling // these value are used in flow control. we do not use ET (edge triggered) polling
// if we dont disable notifications they will come endlessly until condition becomes false and will eat all cpu time // if we don't disable notifications they will come endlessly until condition becomes false and will eat all cpu time
bool bFlowIn,bFlowOut, bShutdown, bFlowInPrev,bFlowOutPrev, bPrevRdhup; bool bFlowIn, bFlowOut, bShutdown, bFlowInPrev, bFlowOutPrev, bPrevRdhup;
// total read,write // total read,write
uint64_t trd,twr, tnrd; uint64_t trd, twr, tnrd;
// number of epoll_wait events // number of epoll_wait events
unsigned int event_count; unsigned int event_count;
@ -94,14 +97,14 @@ struct tproxy_conn
t_ctrack track; t_ctrack track;
//Create the struct which contains ptrs to next/prev element // Create the struct which contains ptrs to next/prev element
TAILQ_ENTRY(tproxy_conn) conn_ptrs; TAILQ_ENTRY(tproxy_conn)
conn_ptrs;
}; };
typedef struct tproxy_conn tproxy_conn_t; typedef struct tproxy_conn tproxy_conn_t;
//Define the struct tailhead (code in sys/queue.h is quite intuitive) // Define the struct tailhead (code in sys/queue.h is quite intuitive)
//Use tail queue for efficient delete // Use tail queue for efficient delete
TAILQ_HEAD(tailhead, tproxy_conn); TAILQ_HEAD(tailhead, tproxy_conn);
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf); bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);

File diff suppressed because it is too large Load Diff