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

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

View File

@ -27,29 +27,29 @@
#define ALLOC_STEP 16384 #define ALLOC_STEP 16384
// minimum subnet fill percent is PCTMULT/PCTDIV (for example 3/4) // minimum subnet fill percent is PCTMULT/PCTDIV (for example 3/4)
#define DEFAULT_PCTMULT 3 #define DEFAULT_PCTMULT 3
#define DEFAULT_PCTDIV 4 #define DEFAULT_PCTDIV 4
// subnet search range in "zero bit count" // subnet search range in "zero bit count"
// means search start from /(32-ZCT_MAX) to /(32-ZCT_MIN) // means search start from /(32-ZCT_MAX) to /(32-ZCT_MIN)
#define DEFAULT_V4_ZCT_MAX 10 // /22 #define DEFAULT_V4_ZCT_MAX 10 // /22
#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,16 +95,17 @@ 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
// fallback case // fallback case
for (uint8_t i = 0; i < sizeof(((struct in6_addr *)0)->s6_addr); i++) for (uint8_t i = 0; i < sizeof(((struct in6_addr *)0)->s6_addr); i++)
@ -124,7 +125,8 @@ static uint32_t unique6(struct in6_addr *pu, uint32_t ct)
uint32_t i, j, k; 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,44 +178,43 @@ 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;
uint32_t pctmult, pctdiv; // for v4 uint32_t pctmult, pctdiv; // for v4
uint32_t zct_min, zct_max; // for v4 and v6 uint32_t zct_min, zct_max; // for v4 and v6
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,20 +406,19 @@ 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))
{ {
if ((i = sscanf(str, "%u.%u.%u.%u-%u.%u.%u.%u", &u1, &u2, &u3, &u4, &u11, &u22, &u33, &u44)) >= 8 && if ((i = sscanf(str, "%u.%u.%u.%u-%u.%u.%u.%u", &u1, &u2, &u3, &u4, &u11, &u22, &u33, &u44)) >= 8 &&
!(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00) && !(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00) &&
!(u11 & 0xFFFFFF00) && !(u22 & 0xFFFFFF00) && !(u33 & 0xFFFFFF00) && !(u44 & 0xFFFFFF00)) !(u11 & 0xFFFFFF00) && !(u22 & 0xFFFFFF00) && !(u33 & 0xFFFFFF00) && !(u44 & 0xFFFFFF00))
{ {
printf("%u.%u.%u.%u-%u.%u.%u.%u\n", u1, u2, u3, u4, u11, u22, u33, u44); 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,25 +20,25 @@
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. */
#define SWAP(a, b, size) \ #define SWAP(a, b, size) \
do \ do \
{ \ { \
size_t __size = (size); \ size_t __size = (size); \
char *__a = (a), *__b = (b); \ char *__a = (a), *__b = (b); \
do \ do \
{ \ { \
char __tmp = *__a; \ char __tmp = *__a; \
*__a++ = *__b; \ *__a++ = *__b; \
*__b++ = __tmp; \ *__b++ = __tmp; \
} while (--__size > 0); \ } while (--__size > 0); \
} while (0) } while (0)
/* Discontinue quicksort algorithm when partition gets below this size. /* Discontinue quicksort algorithm when partition gets below this size.
This particular magic number was chosen to work best on a Sun 4/260. */ This particular magic number was chosen to work best on a Sun 4/260. */
@ -46,21 +46,20 @@
/* Stack node declarations used to store unfulfilled partition obligations. */ /* 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
log(MAX_THRESH)). Since total_elements has type size_t, we get as log(MAX_THRESH)). Since total_elements has type size_t, we get as
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;
@ -99,101 +97,100 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
return; return;
if (total_elems > MAX_THRESH) if (total_elems > MAX_THRESH)
{
char *lo = base_ptr;
char *hi = &lo[size * (total_elems - 1)];
stack_node stack[STACK_SIZE];
stack_node *top = stack;
PUSH(NULL, NULL);
while (STACK_NOT_EMPTY)
{ {
char *lo = base_ptr; char *left_ptr;
char *hi = &lo[size * (total_elems - 1)]; char *right_ptr;
stack_node stack[STACK_SIZE];
stack_node *top = stack;
PUSH (NULL, NULL); /* Select median value from among LO, MID, and HI. Rearrange
LO and HI so the three values are sorted. This lowers the
probability of picking a pathological pivot value and
skips a comparison for both the LEFT_PTR and RIGHT_PTR in
the while loops. */
while (STACK_NOT_EMPTY) char *mid = lo + size * ((hi - lo) / size >> 1);
if ((*cmp)((void *)mid, (void *)lo, arg) < 0)
SWAP(mid, lo, size);
if ((*cmp)((void *)hi, (void *)mid, arg) < 0)
SWAP(mid, hi, size);
else
goto jump_over;
if ((*cmp)((void *)mid, (void *)lo, arg) < 0)
SWAP(mid, lo, size);
jump_over:;
left_ptr = lo + size;
right_ptr = hi - size;
/* Here's the famous ``collapse the walls'' section of quicksort.
Gotta like those tight inner loops! They are the main reason
that this algorithm runs much faster than others. */
do
{
while ((*cmp)((void *)left_ptr, (void *)mid, arg) < 0)
left_ptr += size;
while ((*cmp)((void *)mid, (void *)right_ptr, arg) < 0)
right_ptr -= size;
if (left_ptr < right_ptr)
{ {
char *left_ptr; SWAP(left_ptr, right_ptr, size);
char *right_ptr; if (mid == left_ptr)
mid = right_ptr;
/* Select median value from among LO, MID, and HI. Rearrange else if (mid == right_ptr)
LO and HI so the three values are sorted. This lowers the mid = left_ptr;
probability of picking a pathological pivot value and left_ptr += size;
skips a comparison for both the LEFT_PTR and RIGHT_PTR in right_ptr -= size;
the while loops. */
char *mid = lo + size * ((hi - lo) / size >> 1);
if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
SWAP (mid, lo, size);
if ((*cmp) ((void *) hi, (void *) mid, arg) < 0)
SWAP (mid, hi, size);
else
goto jump_over;
if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
SWAP (mid, lo, size);
jump_over:;
left_ptr = lo + size;
right_ptr = hi - size;
/* Here's the famous ``collapse the walls'' section of quicksort.
Gotta like those tight inner loops! They are the main reason
that this algorithm runs much faster than others. */
do
{
while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
left_ptr += size;
while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
right_ptr -= size;
if (left_ptr < right_ptr)
{
SWAP (left_ptr, right_ptr, size);
if (mid == left_ptr)
mid = right_ptr;
else if (mid == right_ptr)
mid = left_ptr;
left_ptr += size;
right_ptr -= size;
}
else if (left_ptr == right_ptr)
{
left_ptr += size;
right_ptr -= size;
break;
}
}
while (left_ptr <= right_ptr);
/* Set up pointers for next iteration. First determine whether
left and right partitions are below the threshold size. If so,
ignore one or both. Otherwise, push the larger partition's
bounds on the stack and continue sorting the smaller one. */
if ((size_t) (right_ptr - lo) <= max_thresh)
{
if ((size_t) (hi - left_ptr) <= max_thresh)
/* Ignore both small partitions. */
POP (lo, hi);
else
/* Ignore small left partition. */
lo = left_ptr;
}
else if ((size_t) (hi - left_ptr) <= max_thresh)
/* Ignore small right partition. */
hi = right_ptr;
else if ((right_ptr - lo) > (hi - left_ptr))
{
/* Push larger left partition indices. */
PUSH (lo, right_ptr);
lo = left_ptr;
}
else
{
/* Push larger right partition indices. */
PUSH (left_ptr, hi);
hi = right_ptr;
}
} }
else if (left_ptr == right_ptr)
{
left_ptr += size;
right_ptr -= size;
break;
}
} while (left_ptr <= right_ptr);
/* Set up pointers for next iteration. First determine whether
left and right partitions are below the threshold size. If so,
ignore one or both. Otherwise, push the larger partition's
bounds on the stack and continue sorting the smaller one. */
if ((size_t)(right_ptr - lo) <= max_thresh)
{
if ((size_t)(hi - left_ptr) <= max_thresh)
/* Ignore both small partitions. */
POP(lo, hi);
else
/* Ignore small left partition. */
lo = left_ptr;
}
else if ((size_t)(hi - left_ptr) <= max_thresh)
/* Ignore small right partition. */
hi = right_ptr;
else if ((right_ptr - lo) > (hi - left_ptr))
{
/* Push larger left partition indices. */
PUSH(lo, right_ptr);
lo = left_ptr;
}
else
{
/* Push larger right partition indices. */
PUSH(left_ptr, hi);
hi = right_ptr;
}
} }
}
/* Once the BASE_PTR array is partially sorted by quicksort the rest /* Once the BASE_PTR array is partially sorted by quicksort the rest
is completely sorted using insertion sort, since this is efficient is completely sorted using insertion sort, since this is efficient
@ -214,37 +211,37 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size,
and the operation speeds up insertion sort's inner loop. */ 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. */
run_ptr = base_ptr + size; run_ptr = base_ptr + size;
while ((run_ptr += size) <= end_ptr) while ((run_ptr += size) <= end_ptr)
{
tmp_ptr = run_ptr - size;
while ((*cmp)((void *)run_ptr, (void *)tmp_ptr, arg) < 0)
tmp_ptr -= size;
tmp_ptr += size;
if (tmp_ptr != run_ptr)
{ {
tmp_ptr = run_ptr - size; char *trav;
while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
tmp_ptr -= size;
tmp_ptr += size; trav = run_ptr + size;
if (tmp_ptr != run_ptr) while (--trav >= run_ptr)
{ {
char *trav; char c = *trav;
char *hi, *lo;
trav = run_ptr + size; for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
while (--trav >= run_ptr) *hi = *lo;
{ *hi = c;
char c = *trav; }
char *hi, *lo;
for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
*hi = *lo;
*hi = c;
}
}
} }
}
} }
} }

View File

@ -2,5 +2,5 @@
// GNU qsort is 2x faster than musl // 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,18 +77,21 @@ 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 == '.')
for (; *dom; dom++)
if (*dom < 0x20 || (*dom & 0x80) || !(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z')))
return false; return false;
for (; *dom; dom++)
if (*dom < 0x20 || (*dom & 0x80) || !(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z')))
return false;
return true; return true;
} }
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
@ -99,7 +103,7 @@ static struct
int threads; int threads;
time_t start_time; time_t start_time;
pthread_mutex_t flock; pthread_mutex_t flock;
pthread_mutex_t slock; // stats lock pthread_mutex_t slock; // stats lock
int stats_every, stats_ct, stats_ct_ok; // stats int stats_every, stats_ct, stats_ct_ok; // stats
FILE *F_log_resolved, *F_log_failed; FILE *F_log_resolved, *F_log_failed;
} glob; } glob;
@ -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)
{ {
@ -128,8 +133,12 @@ static void interlocked_fprintf(FILE *stream, const char * format, ...)
} }
} }
#define ELOG(format, ...) interlocked_fprintf(stderr, "[%d] " format "\n", tid, ##__VA_ARGS__) #define 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,64 +2,65 @@
#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++;
} }
else else
result = 0; result = 0;
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;
} }
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;
} }
count >>= 1; /* nr of 64-bit words.. */ count >>= 1; /* nr of 64-bit words.. */
if (count) if (count)
{ {
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,52 +333,59 @@ 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,
t->track.ack_last, t->track.pos_reply); t->track.ack_last, t->track.pos_reply);
printf(" req_retrans=%u cutoff=%u wss_cutoff=%u d_cutoff=%u hostname=%s l7proto=%s\n", printf(" req_retrans=%u cutoff=%u wss_cutoff=%u d_cutoff=%u hostname=%s l7proto=%s\n",
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, ConntrackProtoName(t->track.l7proto)); t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, ConntrackProtoName(t->track.l7proto));
}; };
} }
void ReasmClear(t_reassemble *reasm) 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,68 +18,82 @@
#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. {
uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session. uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size.
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet' uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session.
size_t size_present; // how many bytes already stored in 'packet' size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
size_t size_present; // how many bytes already stored in 'packet'
} t_reassemble; } t_reassemble;
// 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
time_t t_start, t_last; time_t t_start, t_last;
uint64_t pcounter_orig, pcounter_reply; // packet counter uint64_t pcounter_orig, pcounter_reply; // packet counter
uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload) uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload)
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
// tcp only state, not used in udp // tcp only state, not used in udp
t_connstate state; t_connstate state;
uint32_t seq0, ack0; // starting seq and ack uint32_t seq0, ack0; // starting seq and ack
uint16_t winsize_orig, winsize_reply; // last seen window size uint16_t winsize_orig, winsize_reply; // last seen window size
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none uint8_t 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;
bool b_cutoff; // mark for deletion bool b_cutoff; // mark for deletion
bool b_wssize_cutoff, b_desync_cutoff; bool b_wssize_cutoff, b_desync_cutoff;
t_l7proto l7proto; t_l7proto l7proto;
char *hostname; char *hostname;
bool hostname_ah_check; // should perform autohostlist checks bool hostname_ah_check; // should perform autohostlist checks
t_reassemble reasm_orig; t_reassemble reasm_orig;
struct rawpacket_tailhead delayed; struct rawpacket_tailhead delayed;
} t_ctrack; } t_ctrack;
@ -88,13 +101,13 @@ typedef struct
typedef struct typedef struct
{ {
t_ctrack track; t_ctrack track;
UT_hash_handle hh; // makes this structure hashable UT_hash_handle hh; // makes this structure hashable
t_conn conn; // key t_conn conn; // key
} t_conntrack_pool; } t_conntrack_pool;
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,6 +1,6 @@
#pragma once #pragma once
#include "gcm.h" #include "gcm.h"
// mode : AES_ENCRYPT, AES_DECRYPT // mode : AES_ENCRYPT, AES_DECRYPT
int aes_gcm_crypt(int mode, uint8_t *output, const uint8_t *input, size_t input_length, const uint8_t *key, const size_t key_len, const uint8_t *iv, const size_t iv_len, const uint8_t *adata, size_t adata_len, uint8_t *atag, size_t atag_len); int aes_gcm_crypt(int mode, uint8_t *output, const uint8_t *input, size_t input_length, const uint8_t *key, const size_t key_len, const uint8_t *iv, const size_t iv_len, const uint8_t *adata, size_t adata_len, uint8_t *atag, size_t atag_len);

View File

@ -1,29 +1,29 @@
/****************************************************************************** /******************************************************************************
* *
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL * THIS 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"
static int aes_tables_inited = 0; // run-once flag for performing key static int aes_tables_inited = 0; // run-once flag for performing key
// expasion table generation (see below) // expasion table generation (see below)
/* /*
* The following static local tables must be filled-in before the first use of * The following static local tables must be filled-in before the first use of
* the GCM or AES ciphers. They are used for the AES key expansion/scheduling * the GCM or AES ciphers. They are used for the AES key expansion/scheduling
@ -37,175 +37,189 @@ static int aes_tables_inited = 0; // run-once flag for performing key
* the GCM input, we ONLY NEED AES encryption. Thus, to save space AES * 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];
static uint32_t FT2[256]; static uint32_t FT2[256];
static uint32_t FT3[256]; static uint32_t FT3[256];
#if AES_DECRYPTION // We ONLY need reverse for decryption #if AES_DECRYPTION // We ONLY need reverse for decryption
static uchar RSb[256]; // Reverse substitution box (RSb) static uchar RSb[256]; // Reverse substitution box (RSb)
static uint32_t RT0[256]; // Reverse key schedule assembly tables static uint32_t RT0[256]; // Reverse key schedule assembly tables
static uint32_t RT1[256]; static uint32_t RT1[256];
static uint32_t RT2[256]; static uint32_t RT2[256];
static uint32_t RT3[256]; static uint32_t RT3[256];
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
static uint32_t RCON[10]; // AES round constants static uint32_t RCON[10]; // AES round constants
/* /*
* Platform Endianness Neutralizing Load and Store Macro definitions * 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
* *
* Fills the AES key expansion tables allocated above with their static * Fills the AES key expansion tables allocated above with their static
* data. This is not "per key" data, but static system-wide read-only * data. This is not "per key" data, but static system-wide read-only
* table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once * table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once
* at system initialization to setup the tables for all subsequent use. * at system initialization to setup the tables for all subsequent use.
* *
******************************************************************************/ ******************************************************************************/
void aes_init_keygen_tables(void) void aes_init_keygen_tables(void)
{ {
int i, x, y, z; // general purpose iteration and computation locals int i, x, y, z; // general purpose iteration and computation locals
int pow[256]; int 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;
} }
// fill the forward and reverse substitution boxes // fill the forward and reverse substitution boxes
FSb[0x00] = 0x63; FSb[0x00] = 0x63;
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
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);
MIX(x, y); MIX(x, y);
MIX(x, y); MIX(x, y);
FSb[i] = (uchar)(x ^= 0x63); FSb[i] = (uchar)(x ^= 0x63);
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
RSb[x] = (uchar)i; 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;
FT0[i] = ((uint32_t)y) ^ ((uint32_t)x << 8) ^ FT0[i] = ((uint32_t)y) ^ ((uint32_t)x << 8) ^
((uint32_t)x << 16) ^ ((uint32_t)z << 24); ((uint32_t)x << 16) ^ ((uint32_t)z << 24);
FT1[i] = ROTL8(FT0[i]); FT1[i] = ROTL8(FT0[i]);
FT2[i] = ROTL8(FT1[i]); FT2[i] = ROTL8(FT1[i]);
FT3[i] = ROTL8(FT2[i]); FT3[i] = ROTL8(FT2[i]);
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
x = RSb[i]; x = RSb[i];
RT0[i] = ((uint32_t)MUL(0x0E, x)) ^ RT0[i] = ((uint32_t)MUL(0x0E, x)) ^
((uint32_t)MUL(0x09, x) << 8) ^ ((uint32_t)MUL(0x09, x) << 8) ^
((uint32_t)MUL(0x0D, x) << 16) ^ ((uint32_t)MUL(0x0D, x) << 16) ^
((uint32_t)MUL(0x0B, x) << 24); ((uint32_t)MUL(0x0B, x) << 24);
RT1[i] = ROTL8(RT0[i]); RT1[i] = ROTL8(RT0[i]);
RT2[i] = ROTL8(RT1[i]); RT2[i] = ROTL8(RT1[i]);
RT3[i] = ROTL8(RT2[i]); RT3[i] = ROTL8(RT2[i]);
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
} }
aes_tables_inited = 1; // flag that the tables have been generated aes_tables_inited = 1; // flag that the tables have been generated
} // to permit subsequent use of the AES cipher } // to permit subsequent use of the AES cipher
/****************************************************************************** /******************************************************************************
* *
@ -218,25 +232,27 @@ void aes_init_keygen_tables(void)
* *
******************************************************************************/ ******************************************************************************/
int aes_set_encryption_key(aes_context *ctx, int aes_set_encryption_key(aes_context *ctx,
const uchar *key, const uchar *key,
uint keysize) uint keysize)
{ {
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) ^
((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^ ((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[3]) & 0xFF] << 24); ((uint32_t)FSb[(RK[3]) & 0xFF] << 24);
RK[5] = RK[1] ^ RK[4]; RK[5] = RK[1] ^ RK[4];
RK[6] = RK[2] ^ RK[5]; RK[6] = RK[2] ^ RK[5];
@ -245,12 +261,13 @@ 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) ^
((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^ ((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[5]) & 0xFF] << 24); ((uint32_t)FSb[(RK[5]) & 0xFF] << 24);
RK[7] = RK[1] ^ RK[6]; RK[7] = RK[1] ^ RK[6];
RK[8] = RK[2] ^ RK[7]; RK[8] = RK[2] ^ RK[7];
@ -261,22 +278,23 @@ 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) ^
((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^ ((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[7]) & 0xFF] << 24); ((uint32_t)FSb[(RK[7]) & 0xFF] << 24);
RK[9] = RK[1] ^ RK[8]; RK[9] = RK[1] ^ RK[8];
RK[10] = RK[2] ^ RK[9]; RK[10] = RK[2] ^ RK[9];
RK[11] = RK[3] ^ RK[10]; RK[11] = RK[3] ^ RK[10];
RK[12] = RK[4] ^ RK[12] = RK[4] ^
((uint32_t)FSb[(RK[11]) & 0xFF]) ^ ((uint32_t)FSb[(RK[11]) & 0xFF]) ^
((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^ ((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24); ((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24);
RK[13] = RK[5] ^ RK[12]; RK[13] = RK[5] ^ RK[12];
RK[14] = RK[6] ^ RK[13]; RK[14] = RK[6] ^ RK[13];
@ -287,10 +305,10 @@ 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
/****************************************************************************** /******************************************************************************
* *
@ -303,36 +321,38 @@ int aes_set_encryption_key(aes_context *ctx,
* *
******************************************************************************/ ******************************************************************************/
int aes_set_decryption_key(aes_context *ctx, int aes_set_decryption_key(aes_context *ctx,
const uchar *key, const uchar *key,
uint keysize) uint keysize)
{ {
int i, j; int i, j;
aes_context cty; // a calling aes context for set_encryption_key aes_context cty; // a calling aes context for set_encryption_key
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
uint32_t *SK; uint32_t *SK;
int ret; int ret;
cty.rounds = ctx->rounds; // initialize our local aes context cty.rounds = ctx->rounds; // initialize our local aes context
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++) { {
*RK++ = RT0[FSb[(*SK) & 0xFF]] ^ for (j = 0; j < 4; j++, SK++)
{
*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]] ^
RT3[FSb[(*SK >> 24) & 0xFF]]; RT3[FSb[(*SK >> 24) & 0xFF]];
}
} }
CPY128 // copy a 128-bit block from *SK to *RK }
memset(&cty, 0, sizeof(aes_context)); // clear local aes context CPY128 // copy a 128-bit block from *SK to *RK
return(0); memset(&cty, 0, sizeof(aes_context)); // clear local aes context
return (0);
} }
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
@ -344,34 +364,42 @@ int aes_set_decryption_key(aes_context *ctx,
* Invoked to establish the key schedule for subsequent encryption/decryption * Invoked to establish the key schedule for subsequent encryption/decryption
* *
******************************************************************************/ ******************************************************************************/
int aes_setkey(aes_context *ctx, // AES context provided by our caller int aes_setkey(aes_context *ctx, // AES context provided by our caller
int mode, // ENCRYPT or DECRYPT flag int mode, // ENCRYPT or DECRYPT flag
const uchar *key, // pointer to the key const uchar *key, // pointer to the key
uint keysize) // key length in bytes uint keysize) // key length in bytes
{ {
// since table initialization is not thread safe, we could either add // since table initialization is not thread safe, we could either add
// 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));
} }
/****************************************************************************** /******************************************************************************
@ -384,20 +412,24 @@ int aes_setkey(aes_context *ctx, // AES context provided by our caller
* *
******************************************************************************/ ******************************************************************************/
int aes_cipher(aes_context *ctx, int aes_cipher(aes_context *ctx,
const uchar input[16], const uchar input[16],
uchar output[16]) uchar output[16])
{ {
int i; int i;
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals
RK = ctx->rk; 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
if (ctx->mode == DECRYPT) if (ctx->mode == DECRYPT)
{ {
@ -409,29 +441,29 @@ 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) ^
((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24); ((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24);
} }
else /* ENCRYPT */ else /* ENCRYPT */
{ {
@ -445,31 +477,31 @@ 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) ^
((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24); ((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24);
#if AES_DECRYPTION // whether AES decryption is supported #if AES_DECRYPTION // whether AES decryption is supported
} }
#endif /* AES_DECRYPTION */ #endif /* AES_DECRYPTION */
@ -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,35 +1,35 @@
/****************************************************************************** /******************************************************************************
* *
* 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
/******************************************************************************/ /******************************************************************************/
#define AES_DECRYPTION 0 // whether AES decryption is supported #define AES_DECRYPTION 0 // whether AES decryption is supported
/******************************************************************************/ /******************************************************************************/
#include <string.h> #include <string.h>
#define AES_ENCRYPT 1 // specify whether we're encrypting #define AES_ENCRYPT 1 // specify whether we're encrypting
#define AES_DECRYPT 0 // or decrypting #define AES_DECRYPT 0 // or decrypting
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <basetsd.h> #include <basetsd.h>
@ -38,41 +38,39 @@ typedef UINT32 uint32_t;
#include <inttypes.h> #include <inttypes.h>
#endif #endif
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 rounds; // keysize-based rounds count int mode; // 1 for Encryption, 0 for Decryption
uint32_t *rk; // pointer to current round key int rounds; // keysize-based rounds count
uint32_t buf[68]; // key expansion buffer uint32_t *rk; // pointer to current round key
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
******************************************************************************/ ******************************************************************************/
int aes_setkey(aes_context *ctx, // pointer to context int aes_setkey(aes_context *ctx, // pointer to context
int mode, // 1 or 0 for Encrypt/Decrypt int mode, // 1 or 0 for Encrypt/Decrypt
const uchar *key, // AES input key const uchar *key, // AES input key
uint keysize); // size in bytes (must be 16, 24, 32 for uint keysize); // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively) // 128, 192 or 256-bit keys respectively)
// returns 0 for success // returns 0 for success
/****************************************************************************** /******************************************************************************
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data * AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
******************************************************************************/ ******************************************************************************/
int aes_cipher(aes_context *ctx, // pointer to context int aes_cipher(aes_context *ctx, // pointer to context
const uchar input[16], // 128-bit block to en/decipher const uchar input[16], // 128-bit block to en/decipher
uchar output[16]); // 128-bit output result block uchar output[16]); // 128-bit output result block
// returns 0 for success // returns 0 for success

View File

@ -1,26 +1,26 @@
/****************************************************************************** /******************************************************************************
* *
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL * THIS 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,80 +41,79 @@
* *
******************************************************************************/ ******************************************************************************/
/* 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
* an intriguing construction which takes two 128-bit strings (also the cipher's * an intriguing construction which takes two 128-bit strings (also the cipher's
* block size and the fundamental operation size for the system) and hashes them * block size and the fundamental operation size for the system) and hashes them
* into a third 128-bit result. * into a third 128-bit result.
* *
* Many implementation solutions have been worked out that use large precomputed * Many implementation solutions have been worked out that use large precomputed
* table lookups in place of more time consuming bit fiddling, and this approach * table lookups in place of more time consuming bit fiddling, and this approach
* can be scaled easily upward or downward as needed to change the time/space * can be scaled easily upward or downward as needed to change the time/space
* tradeoff. It's been studied extensively and there's a solid body of theory and * tradeoff. It's been studied extensively and there's a solid body of theory and
* practice. For example, without using any lookup tables an implementation * practice. For example, without using any lookup tables an implementation
* might obtain 119 cycles per byte throughput, whereas using a simple, though * might obtain 119 cycles per byte throughput, whereas using a simple, though
* large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13 * large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13
* cycles per byte. * cycles per byte.
* *
* And Intel's processors have, since 2010, included an instruction which does * And Intel's processors have, since 2010, included an instruction which does
* the entire 128x128->128 bit job in just several 64x64->128 bit pieces. * the entire 128x128->128 bit job in just several 64x64->128 bit pieces.
* *
* Since SQRL is interactive, and only processing a few 128-bit blocks, I've * Since SQRL is interactive, and only processing a few 128-bit blocks, I've
* settled upon a relatively slower but appealing small-table compromise which * settled upon a relatively slower but appealing small-table compromise which
* folds a bunch of not only time consuming but also bit twiddling into a simple * folds a bunch of not only time consuming but also bit twiddling into a simple
* 16-entry table which is attributed to Victor Shoup's 1996 work while at * 16-entry table which is attributed to Victor Shoup's 1996 work while at
* Bellcore: "On Fast and Provably Secure MessageAuthentication Based on * Bellcore: "On Fast and Provably Secure MessageAuthentication Based on
* Universal Hashing." See: http://www.shoup.net/papers/macs.pdf * Universal Hashing." See: http://www.shoup.net/papers/macs.pdf
* 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 *
* * Must be called once to initialize the GCM library.
* Must be called once to initialize the GCM library. *
* * At present, this only calls the AES keygen table generator, which expands
* At present, this only calls the AES keygen table generator, which expands * the AES keying tables for use. This is NOT A THREAD-SAFE function, so it
* the AES keying tables for use. This is NOT A THREAD-SAFE function, so it * MUST be called during system initialization before a multi-threading
* MUST be called during system initialization before a multi-threading * environment is running.
* environment is running. *
* ******************************************************************************/
******************************************************************************/
int gcm_initialize(void) int gcm_initialize(void)
{ {
aes_init_keygen_tables(); aes_init_keygen_tables();
return(0); return (0);
} }
/****************************************************************************** /******************************************************************************
* *
* GCM_MULT * GCM_MULT
@ -124,9 +123,9 @@ int gcm_initialize(void)
* 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field. * 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
* *
******************************************************************************/ ******************************************************************************/
static void gcm_mult(gcm_context *ctx, // pointer to established context static void gcm_mult(gcm_context *ctx, // pointer to established context
const uchar x[16], // pointer to 128-bit input vector const uchar x[16], // pointer to 128-bit input vector
uchar output[16]) // pointer to 128-bit output vector uchar output[16]) // pointer to 128-bit output vector
{ {
int i; int i;
uchar lo, hi, rem; uchar lo, hi, rem;
@ -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
@ -172,26 +172,26 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
* *
******************************************************************************/ ******************************************************************************/
int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
const uchar *key, // pointer to the AES encryption key const uchar *key, // pointer to the AES encryption key
const uint keysize) // size in bytes (must be 16, 24, 32 for const uint keysize) // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively) // 128, 192 or 256-bit keys respectively)
{ {
int ret, i, j; int ret, i, j;
uint64_t hi, lo; uint64_t hi, lo;
uint64_t vl, vh; uint64_t vl, vh;
unsigned char h[16]; unsigned char h[16];
memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context
memset(h, 0, 16); // initialize the block to encrypt memset(h, 0, 16); // initialize the block to encrypt
// 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);
vh = (uint64_t)hi << 32 | lo; vh = (uint64_t)hi << 32 | lo;
@ -199,31 +199,33 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
GET_UINT32_BE(lo, h, 12); GET_UINT32_BE(lo, h, 12);
vl = (uint64_t)hi << 32 | lo; vl = (uint64_t)hi << 32 | lo;
ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128) ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128)
ctx->HH[8] = vh; ctx->HH[8] = vh;
ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128) ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128)
ctx->HL[0] = 0; 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.
@ -245,18 +247,18 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
* mode, and preprocesses the initialization vector and additional AEAD data. * mode, and preprocesses the initialization vector and additional AEAD data.
* *
******************************************************************************/ ******************************************************************************/
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // GCM_ENCRYPT or GCM_DECRYPT int mode, // GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to initialization vector const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12) size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // ptr to additional AEAD data (NULL if none) const uchar *add, // ptr 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)
{ {
int ret; // our error return if the AES encrypt fails int ret; // our error return if the AES encrypt fails
uchar work_buf[16]; // XOR source built from provided IV if len != 16 uchar work_buf[16]; // XOR source built from provided IV if len != 16
const uchar *p; // general purpose array pointer const uchar *p; // general purpose array pointer
size_t use_len; // byte count to process, up to 16 bytes size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator size_t i; // local loop iterator
// since the context might be reused under the same key // since the context might be reused under the same key
// we zero the working buffers for this next new process // we zero the working buffers for this next new process
@ -265,42 +267,48 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
ctx->len = 0; ctx->len = 0;
ctx->add_len = 0; ctx->add_len = 0;
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)
memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff { // GCM natively uses a 12-byte, 96-bit IV
ctx->y[15] = 1; // start "counting" from 1 (not 0) memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff
ctx->y[15] = 1; // start "counting" from 1 (not 0)
} }
else // if we don't have a 12-byte IV, we GHASH whatever we've been given else // if we don't have a 12-byte IV, we GHASH whatever we've been given
{ {
memset(work_buf, 0x00, 16); // clear the working buffer memset(work_buf, 0x00, 16); // clear the working buffer
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);
} }
/****************************************************************************** /******************************************************************************
@ -314,48 +322,53 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
* have a partial block length of < 128 bits.) * have a partial block length of < 128 bits.)
* *
******************************************************************************/ ******************************************************************************/
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process size_t length, // length, in bytes, of data to process
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
{ {
int ret; // our error return if the AES encrypt fails int ret; // our error return if the AES encrypt fails
uchar ectr[16]; // counter-mode cipher output for XORing uchar ectr[16]; // counter-mode cipher output for XORing
size_t use_len; // byte count to process, up to 16 bytes size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator size_t i; // local loop iterator
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.
// if we're ENcrypting we XOR in the post-XOR (output) // if we're ENcrypting we XOR in the post-XOR (output)
// results, but if we're DEcrypting we XOR in the input // results, but if we're DEcrypting we XOR in the input
// data // data
ctx->buf[i] ^= output[i]; ctx->buf[i] ^= output[i];
} }
} }
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, {
// i.e. before saving to ouput data, otherwise if the input // but if we're DEcrypting we XOR in the input data first,
// and output buffer are the same (inplace decryption) we // i.e. before saving to ouput data, otherwise if the input
// and output buffer are the same (inplace decryption) we
// would not get the correct auth tag // would not get the correct auth tag
ctx->buf[i] ^= input[i]; ctx->buf[i] ^= input[i];
@ -364,13 +377,13 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
output[i] = (uchar)(ectr[i] ^ input[i]); output[i] = (uchar)(ectr[i] ^ input[i]);
} }
} }
gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation
length -= use_len; // drop the remaining byte count to process length -= use_len; // drop the remaining byte count to process
input += use_len; // bump our input pointer forward input += use_len; // bump our input pointer forward
output += use_len; // bump our output pointer forward output += use_len; // bump our output pointer forward
} }
return(0); return (0);
} }
/****************************************************************************** /******************************************************************************
@ -381,18 +394,20 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
* It performs the final GHASH to produce the resulting authentication TAG. * It performs the final GHASH to produce the resulting authentication TAG.
* *
******************************************************************************/ ******************************************************************************/
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // pointer to buffer which receives the tag uchar *tag, // pointer to buffer which receives the tag
size_t tag_len) // length, in bytes, of the tag-receiving buf size_t tag_len) // length, in bytes, of the tag-receiving buf
{ {
uchar work_buf[16]; uchar work_buf[16];
uint64_t orig_len = ctx->len * 8; uint64_t orig_len = ctx->len * 8;
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
@ -426,29 +442,28 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
* *
******************************************************************************/ ******************************************************************************/
int gcm_crypt_and_tag( int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to the 12-byte initialization vector const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12 size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data size_t length, // byte length of the cipher data
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
{ /* { /*
assuming that the caller has already invoked gcm_setkey to assuming that the caller has already invoked gcm_setkey to
prepare the gcm context with the keying material, we simply prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn... invoke each of the three GCM sub-functions in turn...
*/ */
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
@ -462,37 +477,38 @@ int gcm_crypt_and_tag(
* *
******************************************************************************/ ******************************************************************************/
int gcm_auth_decrypt( int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12 size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data size_t length, // byte length of the cipher data
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
{ {
uchar check_tag[16]; // the tag generated and returned by decryption uchar check_tag[16]; // the tag generated and returned by decryption
int diff; // an ORed flag to detect authentication errors int diff; // an ORed flag to detect authentication errors
size_t i; // our local iterator size_t i; // our local iterator
/* /*
we use GCM_DECRYPT_AND_TAG (above) to perform our decryption we use GCM_DECRYPT_AND_TAG (above) to perform our decryption
(which is an identical XORing to reverse the previous one) (which is an identical XORing to reverse the previous one)
and also to re-generate the matching authentication tag and also to re-generate the matching authentication tag
*/ */
gcm_crypt_and_tag(ctx, AES_DECRYPT, iv, iv_len, add, add_len, gcm_crypt_and_tag(ctx, AES_DECRYPT, iv, iv_len, add, add_len,
input, output, length, check_tag, tag_len); input, output, length, check_tag, tag_len);
// now we verify the authentication tag in 'constant time' // now we verify the authentication tag in 'constant time'
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)
memset(output, 0, length); // if so... wipe the output data { // see whether any bits differed?
return(GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE memset(output, 0, length); // if so... wipe the output data
return (GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
} }
return(0); return (0);
} }
/****************************************************************************** /******************************************************************************

View File

@ -1,73 +1,70 @@
/****************************************************************************** /******************************************************************************
* *
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL * THIS 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
#include "aes.h" // gcm_context includes aes_context #include "aes.h" // gcm_context includes aes_context
#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 {
uint64_t len; // cipher data length processed so far int mode; // cipher direction: encrypt/decrypt
uint64_t add_len; // total add data length uint64_t len; // cipher data length processed so far
uint64_t HL[16]; // precalculated lo-half HTable uint64_t add_len; // total add data length
uint64_t HH[16]; // precalculated hi-half HTable uint64_t HL[16]; // precalculated lo-half HTable
uchar base_ectr[16]; // first counter-mode cipher output for tag uint64_t HH[16]; // precalculated hi-half HTable
uchar y[16]; // the current cipher-input IV|Counter value uchar base_ectr[16]; // first counter-mode cipher output for tag
uchar buf[16]; // buf working value uchar y[16]; // the current cipher-input IV|Counter value
aes_context aes_ctx; // cipher context used uchar buf[16]; // buf working value
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
******************************************************************************/ ******************************************************************************/
int gcm_setkey(gcm_context *ctx, // caller-provided context ptr int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
const uchar *key, // pointer to cipher key const uchar *key, // pointer to cipher key
const uint keysize // size in bytes (must be 16, 24, 32 for const uint keysize // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively) // 128, 192 or 256-bit keys respectively)
); // returns 0 for success ); // returns 0 for success
/****************************************************************************** /******************************************************************************
* *
@ -87,18 +84,17 @@ int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
* *
******************************************************************************/ ******************************************************************************/
int gcm_crypt_and_tag( int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0) int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to the 12-byte initialization vector const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12 size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data size_t length, // byte length of the cipher data
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
/****************************************************************************** /******************************************************************************
* *
@ -113,17 +109,16 @@ int gcm_crypt_and_tag(
* *
******************************************************************************/ ******************************************************************************/
int gcm_auth_decrypt( int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12 size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data size_t length, // byte length of the cipher data
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
/****************************************************************************** /******************************************************************************
* *
@ -133,13 +128,12 @@ int gcm_auth_decrypt(
* mode, and preprocesses the initialization vector and additional AEAD data. * mode, and preprocesses the initialization vector and additional AEAD data.
* *
******************************************************************************/ ******************************************************************************/
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // ENCRYPT (1) or DECRYPT (0) int mode, // ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to initialization vector const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12) size_t iv_len, // IV length in bytes (should == 12)
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)
/****************************************************************************** /******************************************************************************
* *
@ -152,11 +146,10 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
* have a partial block length of < 128 bits.) * have a partial block length of < 128 bits.)
* *
******************************************************************************/ ******************************************************************************/
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process size_t length, // length, in bytes, of data to process
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
/****************************************************************************** /******************************************************************************
* *
@ -166,10 +159,9 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
* It performs the final GHASH to produce the resulting authentication TAG. * It performs the final GHASH to produce the resulting authentication TAG.
* *
******************************************************************************/ ******************************************************************************/
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context 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
/****************************************************************************** /******************************************************************************
* *

View File

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

View File

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

View File

@ -10,16 +10,16 @@
*/ */
#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.
*/ */
#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) #define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) #define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
#endif /* USE_MODIFIED_MACROS */ #endif /* USE_MODIFIED_MACROS */
#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) #define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z))

View File

@ -85,12 +85,13 @@
/* /*
* All SHA functions return one of these values. * 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 */
shaStateError, /* called Input after FinalBits or Result */ shaStateError, /* called Input after FinalBits or Result */
shaBadParam /* passed a bad parameter */ shaBadParam /* passed a bad parameter */
}; };
#endif /* _SHA_enum_ */ #endif /* _SHA_enum_ */
@ -98,41 +99,50 @@ 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 */
int_least16_t Message_Block_Index; /* Message_Block array index */ int_least16_t Message_Block_Index; /* Message_Block array index */
/* 512-bit message blocks */ /* 512-bit message blocks */
uint8_t Message_Block[SHA256_Message_Block_Size]; uint8_t Message_Block[SHA256_Message_Block_Size];
int Computed; /* Is the hash computed? */ int Computed; /* Is the hash computed? */
int Corrupted; /* Cumulative corruption code */ int Corrupted; /* Cumulative corruption code */
} SHA256Context; } SHA256Context;
/* /*
@ -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 */ {
union { int whichSha; /* which SHA is being used */
SHA224Context sha224Context; SHA256Context sha256Context; union
{
SHA224Context sha224Context;
SHA256Context sha256Context;
} ctx; } ctx;
} USHAContext; } USHAContext;
@ -157,15 +170,16 @@ 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 hashSize; /* hash size of SHA being used */ int whichSha; /* which SHA is being used */
int blockSize; /* block size of SHA being used */ int hashSize; /* hash size of SHA being used */
USHAContext shaContext; /* SHA context */ int blockSize; /* block size of SHA being used */
USHAContext shaContext; /* SHA context */
unsigned char k_opad[USHA_Max_Message_Block_Size]; unsigned char k_opad[USHA_Max_Message_Block_Size];
/* outer padding - key XORd with opad */ /* outer padding - key XORd with opad */
int Computed; /* Is the MAC computed? */ int Computed; /* Is the MAC computed? */
int Corrupted; /* Cumulative corruption code */ int Corrupted; /* Cumulative corruption code */
} HMACContext; } HMACContext;
@ -173,47 +187,47 @@ 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 */
unsigned char prk[USHAMaxHashSize]; unsigned char prk[USHAMaxHashSize];
/* pseudo-random key - output of hkdfInput */ /* pseudo-random key - output of hkdfInput */
int Computed; /* Is the key material computed? */ int Computed; /* Is the key material computed? */
int Corrupted; /* Cumulative corruption code */ int Corrupted; /* Cumulative corruption code */
} HKDFContext; } 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,
unsigned int bytecount); unsigned int bytecount);
int SHA224FinalBits(SHA224Context *, uint8_t bits, int SHA224FinalBits(SHA224Context *, uint8_t bits,
unsigned int bit_count); unsigned int bit_count);
int SHA224Result(SHA224Context *, int SHA224Result(SHA224Context *,
uint8_t Message_Digest[SHA224HashSize]); uint8_t Message_Digest[SHA224HashSize]);
/* SHA-256 */ /* SHA-256 */
int SHA256Reset(SHA256Context *); int SHA256Reset(SHA256Context *);
int SHA256Input(SHA256Context *, const uint8_t *bytes, int SHA256Input(SHA256Context *, const uint8_t *bytes,
unsigned int bytecount); unsigned int bytecount);
int SHA256FinalBits(SHA256Context *, uint8_t bits, int SHA256FinalBits(SHA256Context *, uint8_t bits,
unsigned int bit_count); unsigned int bit_count);
int SHA256Result(SHA256Context *, int SHA256Result(SHA256Context *,
uint8_t Message_Digest[SHA256HashSize]); uint8_t Message_Digest[SHA256HashSize]);
/* Unified SHA functions, chosen by whichSha */ /* Unified SHA functions, chosen by whichSha */
int USHAReset(USHAContext *context, SHAversion whichSha); int USHAReset(USHAContext *context, SHAversion whichSha);
int USHAInput(USHAContext *context, int USHAInput(USHAContext *context,
const uint8_t *bytes, unsigned int bytecount); const uint8_t *bytes, unsigned int bytecount);
int USHAFinalBits(USHAContext *context, int USHAFinalBits(USHAContext *context,
uint8_t bits, unsigned int bit_count); uint8_t bits, unsigned int bit_count);
int USHAResult(USHAContext *context, int USHAResult(USHAContext *context,
uint8_t Message_Digest[USHAMaxHashSize]); uint8_t Message_Digest[USHAMaxHashSize]);
int USHABlockSize(enum SHAversion whichSha); int USHABlockSize(enum SHAversion whichSha);
int USHAHashSize(enum SHAversion whichSha); int USHAHashSize(enum SHAversion whichSha);
@ -222,12 +236,12 @@ int USHAHashSize(enum SHAversion whichSha);
* for all SHAs. * for all SHAs.
* This interface allows a fixed-length text input to be used. * This interface allows a fixed-length text input to be used.
*/ */
int hmac(SHAversion whichSha, /* which SHA algorithm to use */ int hmac(SHAversion whichSha, /* which SHA algorithm to use */
const unsigned char *text, /* pointer to data stream */ const unsigned char *text, /* pointer to data stream */
size_t text_len, /* length of data stream */ size_t text_len, /* length of data stream */
const unsigned char *key, /* pointer to authentication key */ const unsigned char *key, /* pointer to authentication key */
size_t key_len, /* length of authentication key */ size_t key_len, /* length of authentication key */
uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */
/* /*
* HMAC Keyed-Hashing for Message Authentication, RFC 2104, * HMAC Keyed-Hashing for Message Authentication, RFC 2104,
@ -235,31 +249,30 @@ int hmac(SHAversion whichSha, /* which SHA algorithm to use */
* This interface allows any length of text input to be used. * This interface allows any length of text input to be used.
*/ */
int hmacReset(HMACContext *context, enum SHAversion whichSha, int hmacReset(HMACContext *context, enum SHAversion whichSha,
const unsigned char *key, size_t key_len); const unsigned char *key, size_t key_len);
int hmacInput(HMACContext *context, const unsigned char *text, int hmacInput(HMACContext *context, const unsigned char *text,
size_t text_len); size_t text_len);
int hmacFinalBits(HMACContext *context, uint8_t bits, int hmacFinalBits(HMACContext *context, uint8_t bits,
unsigned int bit_count); unsigned int bit_count);
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.
*/ */
int hkdf(SHAversion whichSha, 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,
@ -267,12 +280,12 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ],
* This interface allows any length of text input to be used. * This interface allows any length of text input to be used.
*/ */
int hkdfReset(HKDFContext *context, enum SHAversion whichSha, int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
const unsigned char *salt, size_t salt_len); const unsigned char *salt, size_t salt_len);
int hkdfInput(HKDFContext *context, const unsigned char *ikm, int hkdfInput(HKDFContext *context, const unsigned char *ikm,
size_t ikm_len); size_t ikm_len);
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);
int hkdfResult(HKDFContext *context, int hkdfResult(HKDFContext *context,
uint8_t prk[USHAMaxHashSize], uint8_t prk[USHAMaxHashSize],
const unsigned char *info, size_t info_len, const unsigned char *info, size_t info_len,
uint8_t okm[USHAMaxHashSize], size_t okm_len); uint8_t okm[USHAMaxHashSize], size_t okm_len);

View File

@ -44,54 +44,53 @@
#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.
* Set Corrupted when overflow has occurred. * Set Corrupted when overflow has occurred.
*/ */
static uint32_t addTemp; 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);
static void SHA224_256ProcessMessageBlock(SHA256Context *context); static void SHA224_256ProcessMessageBlock(SHA256Context *context);
static void SHA224_256Finalize(SHA256Context *context, static void SHA224_256Finalize(SHA256Context *context,
uint8_t Pad_Byte); uint8_t Pad_Byte);
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
@ -133,7 +132,7 @@ int SHA224Reset(SHA224Context *context)
* *
*/ */
int SHA224Input(SHA224Context *context, const uint8_t *message_array, int SHA224Input(SHA224Context *context, const uint8_t *message_array,
unsigned int length) unsigned int length)
{ {
return SHA256Input(context, message_array, length); return SHA256Input(context, message_array, length);
} }
@ -183,7 +182,7 @@ int SHA224FinalBits(SHA224Context *context,
* sha Error Code. * sha Error Code.
*/ */
int SHA224Result(SHA224Context *context, int SHA224Result(SHA224Context *context,
uint8_t Message_Digest[SHA224HashSize]) uint8_t Message_Digest[SHA224HashSize])
{ {
return SHA224_256ResultN(context, Message_Digest, SHA224HashSize); return SHA224_256ResultN(context, Message_Digest, SHA224HashSize);
} }
@ -227,27 +226,32 @@ int SHA256Reset(SHA256Context *context)
* sha Error Code. * sha Error Code.
*/ */
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;
if ((SHA224_256AddLength(context, 8) == shaSuccess) && if ((SHA224_256AddLength(context, 8) == shaSuccess) &&
(context->Message_Block_Index == SHA256_Message_Block_Size)) (context->Message_Block_Index == SHA256_Message_Block_Size))
SHA224_256ProcessMessageBlock(context); SHA224_256ProcessMessageBlock(context);
message_array++; 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,10 +347,11 @@ 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;
context->Intermediate_Hash[0] = H0[0]; context->Intermediate_Hash[0] = H0[0];
context->Intermediate_Hash[1] = H0[1]; context->Intermediate_Hash[1] = H0[1];
@ -355,7 +362,7 @@ static int SHA224_256Reset(SHA256Context *context, uint32_t *H0)
context->Intermediate_Hash[6] = H0[6]; context->Intermediate_Hash[6] = H0[6];
context->Intermediate_Hash[7] = H0[7]; context->Intermediate_Hash[7] = H0[7];
context->Computed = 0; context->Computed = 0;
context->Corrupted = shaSuccess; context->Corrupted = shaSuccess;
return shaSuccess; return shaSuccess;
@ -396,12 +403,11 @@ 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 */ uint32_t A, B, C, D, E, F, G, H; /* Word buffers */
uint32_t A, B, C, D, E, F, G, H; /* Word buffers */
/* /*
* Initialize the first 16 words in the array W * Initialize the first 16 words in the array W
@ -412,8 +418,8 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
(((uint32_t)context->Message_Block[t4 + 2]) << 8) | (((uint32_t)context->Message_Block[t4 + 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;
@ -468,14 +475,14 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
* sha Error Code. * sha Error Code.
*/ */
static void SHA224_256Finalize(SHA256Context *context, static void SHA224_256Finalize(SHA256Context *context,
uint8_t Pad_Byte) uint8_t Pad_Byte)
{ {
int i; int i;
SHA224_256PadMessage(context, Pad_Byte); SHA224_256PadMessage(context, Pad_Byte);
/* message may be sensitive, so clear it out */ /* message may be sensitive, so clear it out */
for (i = 0; i < SHA256_Message_Block_Size; ++i) for (i = 0; i < SHA256_Message_Block_Size; ++i)
context->Message_Block[i] = 0; context->Message_Block[i] = 0;
context->Length_High = 0; /* and clear length */ context->Length_High = 0; /* and clear length */
context->Length_Low = 0; context->Length_Low = 0;
context->Computed = 1; context->Computed = 1;
} }
@ -505,7 +512,7 @@ static void SHA224_256Finalize(SHA256Context *context,
* Nothing. * Nothing.
*/ */
static void SHA224_256PadMessage(SHA256Context *context, static void SHA224_256PadMessage(SHA256Context *context,
uint8_t Pad_Byte) uint8_t Pad_Byte)
{ {
/* /*
* Check to see if the current message block is too small to hold * Check to see if the current message block is too small to hold
@ -513,15 +520,17 @@ static void SHA224_256PadMessage(SHA256Context *context,
* block, process it, and then continue padding into a second * block, 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;
case SHA224: switch (context->whichSha)
return SHA224Input((SHA224Context*)&context->ctx, bytes, {
bytecount); case SHA224:
case SHA256: return SHA224Input((SHA224Context *)&context->ctx, bytes,
return SHA256Input((SHA256Context*)&context->ctx, bytes, bytecount);
bytecount); case SHA256:
default: return shaBadParam; return SHA256Input((SHA256Context *)&context->ctx, bytes,
bytecount);
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;
case SHA224: switch (context->whichSha)
return SHA224FinalBits((SHA224Context*)&context->ctx, bits, {
bit_count); case SHA224:
case SHA256: return SHA224FinalBits((SHA224Context *)&context->ctx, bits,
return SHA256FinalBits((SHA256Context*)&context->ctx, bits, bit_count);
bit_count); case SHA256:
default: return shaBadParam; return SHA256FinalBits((SHA256Context *)&context->ctx, bits,
bit_count);
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;
case SHA224: switch (context->whichSha)
return SHA224Result((SHA224Context*)&context->ctx, {
Message_Digest); case SHA224:
case SHA256: return SHA224Result((SHA224Context *)&context->ctx,
return SHA256Result((SHA256Context*)&context->ctx, Message_Digest);
Message_Digest); case SHA256:
default: return shaBadParam; return SHA256Result((SHA256Context *)&context->ctx,
Message_Digest);
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; {
default: case SHA224:
case SHA256: return SHA256_Message_Block_Size; return SHA224_Message_Block_Size;
default:
case SHA256:
return SHA256_Message_Block_Size;
} }
} }
@ -183,9 +200,12 @@ int USHABlockSize(enum SHAversion whichSha)
*/ */
int USHAHashSize(enum SHAversion whichSha) int USHAHashSize(enum SHAversion whichSha)
{ {
switch (whichSha) { switch (whichSha)
case SHA224: return SHA224HashSize; {
default: case SHA224:
case SHA256: return SHA256HashSize; return SHA224HashSize;
default:
case SHA256:
return SHA256HashSize;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@
#include <netinet/udp.h> #include <netinet/udp.h>
#ifndef IPV6_FREEBIND #ifndef IPV6_FREEBIND
#define IPV6_FREEBIND 78 #define IPV6_FREEBIND 78
#endif #endif
#ifdef __CYGWIN__ #ifdef __CYGWIN__
@ -30,7 +30,7 @@
#endif #endif
#ifndef AF_DIVERT #ifndef AF_DIVERT
#define AF_DIVERT 44 /* divert(4) */ #define AF_DIVERT 44 /* divert(4) */
#endif #endif
#ifndef PF_DIVERT #ifndef PF_DIVERT
#define PF_DIVERT AF_DIVERT #define PF_DIVERT AF_DIVERT
@ -40,24 +40,24 @@
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment); uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);
uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment); uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
#define FOOL_NONE 0x00 #define FOOL_NONE 0x00
#define FOOL_MD5SIG 0x01 #define FOOL_MD5SIG 0x01
#define FOOL_BADSUM 0x02 #define FOOL_BADSUM 0x02
#define FOOL_TS 0x04 #define FOOL_TS 0x04
#define FOOL_BADSEQ 0x08 #define FOOL_BADSEQ 0x08
#define FOOL_HOPBYHOP 0x10 #define FOOL_HOPBYHOP 0x10
#define FOOL_HOPBYHOP2 0x20 #define FOOL_HOPBYHOP2 0x20
#define FOOL_DESTOPT 0x40 #define FOOL_DESTOPT 0x40
#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
#define VERDICT_DROP 2 #define VERDICT_DROP 2
#define VERDICT_MASK 3 #define VERDICT_MASK 3
#define VERDICT_NOCSUM 4 #define VERDICT_NOCSUM 4
// seq and wsize have network byte order // seq and wsize have network byte order
bool prepare_tcp_segment4( bool prepare_tcp_segment4(
@ -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,
@ -144,11 +143,11 @@ bool ip_frag(
size_t frag_pos, uint32_t ident, size_t frag_pos, uint32_t ident,
uint8_t *pkt1, size_t *pkt1_size, uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_size); uint8_t *pkt2, size_t *pkt2_size);
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,49 +146,55 @@ 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;
return true; return true;
} }
void dbgprint_socket_buffers(int fd) void dbgprint_socket_buffers(int fd)
{ {
if (params.debug) if (params.debug)
@ -190,7 +204,7 @@ void dbgprint_socket_buffers(int fd)
sz = sizeof(int); sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &v, &sz)) if (!getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &v, &sz))
DLOG("fd=%d SO_RCVBUF=%d\n", fd, v); DLOG("fd=%d SO_RCVBUF=%d\n", fd, v);
sz = sizeof(int); sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &v, &sz)) if (!getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &v, &sz))
DLOG("fd=%d SO_SNDBUF=%d\n", fd, v); DLOG("fd=%d SO_SNDBUF=%d\n", fd, v);
} }
@ -216,14 +230,14 @@ bool set_socket_buffers(int fd, int rcvbuf, int sndbuf)
uint64_t pntoh64(const void *p) 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

@ -8,17 +8,19 @@
static bool addpool(strpool **hostlist, char **s, const char *end) 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,19 +67,20 @@ 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;
} }
} }
else else
{ {
DLOG_CONDUP("loading plain text list\n"); DLOG_CONDUP("loading plain text list\n");
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)
@ -36,30 +40,31 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
free(rp); free(rp);
return NULL; return NULL;
} }
rp->dst = *dst; rp->dst = *dst;
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);
return rp; return rp;
} }
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,31 +53,31 @@ static void syslog_buffered(int priority, const char *format, va_list args)
static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list args) 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:
break; break;
} }
} }
return r; return r;
@ -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

@ -13,27 +13,32 @@
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#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
#define BADSEQ_INCREMENT_DEFAULT -10000 #define BADSEQ_INCREMENT_DEFAULT -10000
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000 #define BADSEQ_ACK_INCREMENT_DEFAULT -66000
#define IPFRAG_UDP_DEFAULT 8 #define IPFRAG_UDP_DEFAULT 8
#define IPFRAG_TCP_DEFAULT 32 #define IPFRAG_TCP_DEFAULT 32
#define UDPLEN_INCREMENT_DEFAULT 2 #define UDPLEN_INCREMENT_DEFAULT 2
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3 #define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
#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

@ -5,33 +5,33 @@
#include <stdio.h> #include <stdio.h>
#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); \ { \
HASH_DEL(*ppool, elem); \ free(elem->str); \
free(elem); \ HASH_DEL(*ppool, elem); \
} free(elem); \
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
} }
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype *)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
}
#undef uthash_nonfatal_oom #undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt) #define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
@ -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,38 +5,41 @@
#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 */ {
UT_hash_handle hh; /* makes this structure hashable */ char *str; /* key */
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; {
LIST_ENTRY(str_list) next; char *str;
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) */
UT_hash_handle hh; /* makes this structure hashable */ UT_hash_handle hh; /* makes this structure hashable */
} 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,83 +92,97 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
} }
const char *HttpFind2ndLevelDomain(const char *host) const char *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
// extract 2nd level domains // extract 2nd level domains
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)
{
case httpreqpos_method:
// recognize some tpws pre-applied hacks
method=http;
if (sz<10) break;
if (*method=='\n' || *method=='\r') method++;
if (*method=='\n' || *method=='\r') method++;
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
if (i<3 || *method!=' ') break;
return method-http-1;
case httpreqpos_host:
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
{
host+=5;
if (*host==' ') host++;
return host-http;
}
break;
case httpreqpos_pos:
break;
default:
return 0;
}
return hpos_pos<sz ? hpos_pos : 0;
}
switch (tpos_type)
{
case httpreqpos_method:
// recognize some tpws pre-applied hacks
method = http;
if (sz < 10)
break;
if (*method == '\n' || *method == '\r')
method++;
if (*method == '\n' || *method == '\r')
method++;
for (i = 0; i < 7; i++)
if (*method >= 'A' && *method <= 'Z')
method++;
if (i < 3 || *method != ' ')
break;
return method - http - 1;
case httpreqpos_host:
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
{
host += 5;
if (*host == ' ')
host++;
return host - http;
}
break;
case httpreqpos_pos:
break;
default:
return 0;
}
return hpos_pos < sz ? hpos_pos : 0;
}
uint16_t TLSRecordDataLen(const uint8_t *data) uint16_t TLSRecordDataLen(const uint8_t *data)
{ {
@ -173,7 +194,7 @@ size_t TLSRecordLen(const uint8_t *data)
} }
bool IsTLSRecordFull(const uint8_t *data, size_t len) 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;
@ -418,7 +475,7 @@ static bool is_quic_draft_max(uint32_t draft_version, uint8_t max_version)
} }
static bool is_quic_v2(uint32_t version) static bool is_quic_v2(uint32_t version)
{ {
return version == 0x6b3343cf; return version == 0x6b3343cf;
} }
static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len) static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len)
@ -426,9 +483,11 @@ static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, co
uint8_t hkdflabel[64]; 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,16 +41,23 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK); bool 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 cid[QUIC_MAX_CID_LENGTH]; uint8_t len;
uint8_t cid[QUIC_MAX_CID_LENGTH];
} quic_cid_t; } quic_cid_t;
bool IsQUICInitial(const uint8_t *data, size_t len); bool IsQUICInitial(const uint8_t *data, size_t len);
@ -55,5 +68,5 @@ uint8_t QUICDraftVersion(uint32_t version);
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid); bool 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);

186
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,19 +177,19 @@ 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
return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) >= 0; return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) >= 0;
} }
@ -201,42 +200,41 @@ bool sec_harden(void)
DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)"); 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)
{ {
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];
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

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
#ifndef SHIM_SYS_EPOLL_H #ifndef SHIM_SYS_EPOLL_H
#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; {
int fd; void *ptr;
uint32_t u32; int fd;
uint64_t u64; uint32_t u32;
} epoll_data_t; uint64_t u64;
} epoll_data_t;
struct epoll_event { struct epoll_event
uint32_t events; {
epoll_data_t data; uint32_t events;
} 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

@ -21,14 +21,16 @@
// TODO(jan): Remove this once the definition is exposed in <sys/time.h> in // TODO(jan): Remove this once the definition is exposed in <sys/time.h> in
// 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_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
if ((vsp)->tv_nsec < 0) { \ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
(vsp)->tv_sec--; \ if ((vsp)->tv_nsec < 0) \
(vsp)->tv_nsec += 1000000000L; \ { \
} \ (vsp)->tv_sec--; \
(vsp)->tv_nsec += 1000000000L; \
} \
} while (0) } while (0)
#endif #endif
@ -39,9 +41,9 @@ epollfd_close(FDContextMapNode *node)
} }
static FDContextVTable const epollfd_vtable = { static FDContextVTable const epollfd_vtable = {
.read_fun = fd_context_default_read, .read_fun = fd_context_default_read,
.write_fun = fd_context_default_write, .write_fun = fd_context_default_write,
.close_fun = epollfd_close, .close_fun = epollfd_close,
}; };
static FDContextMapNode * static FDContextMapNode *
@ -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;
} }
@ -143,33 +150,39 @@ is_no_wait_deadline(struct timespec const *deadline)
static errno_t static errno_t
epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
int *actual_cnt, struct timespec const *deadline, sigset_t const *sigs) int *actual_cnt, struct timespec const *deadline, sigset_t const *sigs)
{ {
errno_t ec; 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;
} }
@ -261,36 +285,39 @@ timeout_to_deadline(struct timespec *deadline, int to)
static errno_t 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;
} }
return epollfd_ctx_wait_or_block(&node->ctx.epollfd, ev, cnt, return epollfd_ctx_wait_or_block(&node->ctx.epollfd, ev, cnt,
actual_cnt, (to >= 0) ? &deadline : NULL, sigs); actual_cnt, (to >= 0) ? &deadline : NULL, sigs);
} }
int 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;
} }
@ -53,7 +55,7 @@ fd_context_map_node_destroy(FDContextMapNode *node)
errno_t errno_t
fd_context_default_read(FDContextMapNode *node, /**/ fd_context_default_read(FDContextMapNode *node, /**/
void *buf, size_t nbytes, size_t *bytes_transferred) void *buf, size_t nbytes, size_t *bytes_transferred)
{ {
(void)node; (void)node;
(void)buf; (void)buf;
@ -65,7 +67,7 @@ fd_context_default_read(FDContextMapNode *node, /**/
errno_t errno_t
fd_context_default_write(FDContextMapNode *node, /**/ fd_context_default_write(FDContextMapNode *node, /**/
void const *buf, size_t nbytes, size_t *bytes_transferred) void const *buf, size_t nbytes, size_t *bytes_transferred)
{ {
(void)node; (void)node;
(void)buf; (void)buf;
@ -84,18 +86,18 @@ fd_context_map_node_cmp(FDContextMapNode *e1, FDContextMapNode *e2)
} }
RB_PROTOTYPE_STATIC(fd_context_map_, fd_context_map_node_, entry, RB_PROTOTYPE_STATIC(fd_context_map_, fd_context_map_node_, entry,
fd_context_map_node_cmp); fd_context_map_node_cmp);
RB_GENERATE_STATIC(fd_context_map_, fd_context_map_node_, entry, RB_GENERATE_STATIC(fd_context_map_, fd_context_map_node_, entry,
fd_context_map_node_cmp); fd_context_map_node_cmp);
EpollShimCtx epoll_shim_ctx = { EpollShimCtx epoll_shim_ctx = {
.fd_context_map = RB_INITIALIZER(&fd_context_map), .fd_context_map = RB_INITIALIZER(&fd_context_map),
.mutex = PTHREAD_MUTEX_INITIALIZER, .mutex = PTHREAD_MUTEX_INITIALIZER,
}; };
static FDContextMapNode * static FDContextMapNode *
epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq, epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
errno_t *ec) errno_t *ec)
{ {
FDContextMapNode *node; FDContextMapNode *node;
@ -104,10 +106,11 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
find.fd = kq; find.fd = kq;
node = RB_FIND(fd_context_map_, /**/ node = RB_FIND(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, &find); &epoll_shim_ctx->fd_context_map, &find);
} }
if (node) { if (node)
{
/* /*
* If we get here, someone must have already closed the old fd * 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,14 +121,17 @@ 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;
} }
void *colliding_node = RB_INSERT(fd_context_map_, void *colliding_node = RB_INSERT(fd_context_map_,
&epoll_shim_ctx->fd_context_map, node); &epoll_shim_ctx->fd_context_map, node);
(void)colliding_node; (void)colliding_node;
assert(colliding_node == NULL); assert(colliding_node == 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);
} }
@ -164,7 +172,7 @@ epoll_shim_ctx_find_node_impl(EpollShimCtx *epoll_shim_ctx, int fd)
find.fd = fd; find.fd = fd;
node = RB_FIND(fd_context_map_, /**/ node = RB_FIND(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, &find); &epoll_shim_ctx->fd_context_map, &find);
return node; return node;
} }
@ -188,39 +196,40 @@ epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, int fd)
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex); (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);
} }
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex); (void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
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);
RB_REMOVE(fd_context_map_, /**/ RB_REMOVE(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, node); &epoll_shim_ctx->fd_context_map, node);
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex); (void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
} }
/**/ /**/
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,19 +243,22 @@ 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;
} }
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,19 +272,22 @@ 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;
} }
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

@ -16,27 +16,31 @@ struct fd_context_map_node_;
typedef struct fd_context_map_node_ FDContextMapNode; typedef struct fd_context_map_node_ FDContextMapNode;
typedef errno_t (*fd_context_read_fun)(FDContextMapNode *node, /**/ typedef errno_t (*fd_context_read_fun)(FDContextMapNode *node, /**/
void *buf, size_t nbytes, size_t *bytes_transferred); void *buf, size_t nbytes, size_t *bytes_transferred);
typedef errno_t (*fd_context_write_fun)(FDContextMapNode *node, /**/ 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;
} FDContextVTable; } FDContextVTable;
errno_t fd_context_default_read(FDContextMapNode *node, /**/ errno_t fd_context_default_read(FDContextMapNode *node, /**/
void *buf, size_t nbytes, size_t *bytes_transferred); void *buf, size_t nbytes, size_t *bytes_transferred);
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;
@ -59,13 +64,13 @@ typedef struct {
extern EpollShimCtx epoll_shim_ctx; extern EpollShimCtx epoll_shim_ctx;
FDContextMapNode *epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, FDContextMapNode *epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx,
errno_t *ec); errno_t *ec);
FDContextMapNode *epoll_shim_ctx_find_node(EpollShimCtx *epoll_shim_ctx, FDContextMapNode *epoll_shim_ctx_find_node(EpollShimCtx *epoll_shim_ctx,
int fd); int fd);
FDContextMapNode *epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, FDContextMapNode *epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx,
int fd); int fd);
void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx, void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
FDContextMapNode *node); FDContextMapNode *node);
/**/ /**/

File diff suppressed because it is too large Load Diff

View File

@ -19,12 +19,14 @@
struct registered_fds_node_; 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;
@ -101,8 +109,8 @@ errno_t epollfd_ctx_terminate(EpollFDCtx *epollfd);
void epollfd_ctx_fill_pollfds(EpollFDCtx *epollfd, struct pollfd *pfds); void epollfd_ctx_fill_pollfds(EpollFDCtx *epollfd, struct pollfd *pfds);
errno_t epollfd_ctx_ctl(EpollFDCtx *epollfd, int op, int fd2, errno_t epollfd_ctx_ctl(EpollFDCtx *epollfd, int op, int fd2,
struct epoll_event *ev); struct epoll_event *ev);
errno_t epollfd_ctx_wait(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, errno_t epollfd_ctx_wait(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
int *actual_cnt); int *actual_cnt);
#endif #endif

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_;
@ -22,7 +23,7 @@ typedef struct {
} EventFDCtx; } EventFDCtx;
errno_t eventfd_ctx_init(EventFDCtx *eventfd, int kq, unsigned int counter, errno_t eventfd_ctx_init(EventFDCtx *eventfd, int kq, unsigned int counter,
int flags); int flags);
errno_t eventfd_ctx_terminate(EventFDCtx *eventfd); errno_t eventfd_ctx_terminate(EventFDCtx *eventfd);
errno_t eventfd_ctx_write(EventFDCtx *eventfd, uint64_t value); errno_t eventfd_ctx_write(EventFDCtx *eventfd, uint64_t value);

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_value; struct timespec it_interval;
struct timespec it_value;
}; };
int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const sigset_t *sigmask); int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask);
#endif #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;
@ -30,7 +31,7 @@ errno_t timerfd_ctx_init(TimerFDCtx *timerfd, int kq, int clockid);
errno_t timerfd_ctx_terminate(TimerFDCtx *timerfd); errno_t timerfd_ctx_terminate(TimerFDCtx *timerfd);
errno_t timerfd_ctx_settime(TimerFDCtx *timerfd, int flags, errno_t timerfd_ctx_settime(TimerFDCtx *timerfd, int flags,
struct itimerspec const *new, struct itimerspec *old); struct itimerspec const *new, struct itimerspec *old);
errno_t timerfd_ctx_gettime(TimerFDCtx *timerfd, struct itimerspec *cur); errno_t timerfd_ctx_gettime(TimerFDCtx *timerfd, struct itimerspec *cur);
errno_t timerfd_ctx_read(TimerFDCtx *timerfd, uint64_t *value); errno_t timerfd_ctx_read(TimerFDCtx *timerfd, uint64_t *value);

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)
a = addrs; return false;
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

@ -8,17 +8,19 @@
static bool addpool(strpool **hostlist, char **s, const char *end) 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,19 +67,20 @@ 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;
} }
} }
else else
{ {
DLOG_CONDUP("loading plain text list\n"); DLOG_CONDUP("loading plain text list\n");
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

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

File diff suppressed because it is too large Load Diff

View File

@ -9,33 +9,33 @@ int DLOG_FILE(FILE *F, const char *format, va_list args)
} }
int DLOG_CON(const char *format, int syslog_priority, va_list args) 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,31 +43,31 @@ static void syslog_buffered(int priority, const char *format, va_list args)
static int DLOG_VA(const char *format, int syslog_priority, bool condup, int level, va_list args) 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:
break; break;
} }
} }
return r; return r;
@ -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

@ -11,21 +11,32 @@
#include "helpers.h" #include "helpers.h"
#include "protocol.h" #include "protocol.h"
#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
#define MAX_BINDS 32
struct bind_s
{ {
char bindaddr[64],bindiface[IF_NAMESIZE]; unwanted = 0,
bool bind_if6; no,
enum bindll bindll; prefer,
int bind_wait_ifup,bind_wait_ip,bind_wait_ip_ll; force
}; };
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; #define MAX_BINDS 32
struct bind_s
{
char bindaddr[64], bindiface[IF_NAMESIZE];
bool bind_if6;
enum bindll bindll;
int bind_wait_ifup, bind_wait_ip, bind_wait_ip_ll;
};
enum log_target
{
LOG_TARGET_CONSOLE = 0,
LOG_TARGET_FILE,
LOG_TARGET_SYSLOG
};
struct params_s 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

@ -5,33 +5,33 @@
#include <stdio.h> #include <stdio.h>
#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); \ { \
HASH_DEL(*ppool, elem); \ free(elem->str); \
free(elem); \ HASH_DEL(*ppool, elem); \
} free(elem); \
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
} }
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype *)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
}
#undef uthash_nonfatal_oom #undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt) #define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
@ -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,38 +5,41 @@
#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 */ {
UT_hash_handle hh; /* makes this structure hashable */ char *str; /* key */
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; {
LIST_ENTRY(str_list) next; char *str;
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) */
UT_hash_handle hh; /* makes this structure hashable */ UT_hash_handle hh; /* makes this structure hashable */
} 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,85 +91,98 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
} }
const char *HttpFind2ndLevelDomain(const char *host) const char *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
// extract 2nd level domains // extract 2nd level domains
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++;
if (*method=='\n' || *method=='\r') method++;
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
if (i<3 || *method!=' ') break;
return method-http-1;
case httpreqpos_host:
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
{
host+=5;
if (*host==' ') host++;
return host-http;
}
break; break;
case httpreqpos_pos: if (*method == '\n' || *method == '\r')
method++;
if (*method == '\n' || *method == '\r')
method++;
for (i = 0; i < 7; i++)
if (*method >= 'A' && *method <= 'Z')
method++;
if (i < 3 || *method != ' ')
break; break;
default: return method - http - 1;
return 0; case httpreqpos_host:
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
{
host += 5;
if (*host == ' ')
host++;
return host - http;
}
break;
case httpreqpos_pos:
break;
default:
return 0;
} }
return hpos_pos<sz ? hpos_pos : 0; return hpos_pos < sz ? hpos_pos : 0;
} }
uint16_t TLSRecordDataLen(const uint8_t *data) 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,23 +331,24 @@ 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,74 +55,79 @@ 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;
} }
memset(&nl, 0, sizeof(nl)); memset(&nl, 0, sizeof(nl));
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
} }
break; break;
case AF_INET6: case AF_INET6:
{ {
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

@ -7,7 +7,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <semaphore.h> #include <semaphore.h>
#include <fcntl.h> #include <fcntl.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#include <sys/syscall.h> #include <sys/syscall.h>
@ -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);
} }
@ -57,7 +58,7 @@ int resolver_thread_count(void)
{ {
return resolver.bInit ? resolver.threads : 0; return resolver.bInit ? resolver.threads : 0;
} }
static void *resolver_thread(void *arg) static void *resolver_thread(void *arg)
{ {
int r; int r;
@ -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;
} }
@ -149,19 +153,19 @@ void resolver_deinit(void)
pthread_kill(resolver.thread[t], SIGUSR1); pthread_kill(resolver.thread[t], SIGUSR1);
pthread_join(resolver.thread[t], NULL); pthread_join(resolver.thread[t], NULL);
} }
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,48 +194,51 @@ 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;
} }
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

@ -8,12 +8,13 @@
struct resolve_item struct resolve_item
{ {
char dom[256]; // request dom char dom[256]; // request dom
struct sockaddr_storage ss; // resolve result struct sockaddr_storage ss; // resolve result
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,19 +150,19 @@ 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
return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) >= 0; return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) >= 0;
} }
@ -174,42 +173,41 @@ bool sec_harden(void)
DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)"); 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)
{ {
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];
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,87 +3,91 @@
#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_GSSAPI 1
#define S5_AUTH_NONE 0 #define S5_AUTH_USERPASS 2
#define S5_AUTH_GSSAPI 1 #define S5_AUTH_UNACCEPTABLE 0xFF
#define S5_AUTH_USERPASS 2
#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
#define S5_CMD_BIND 2 #define S5_CMD_BIND 2
#define S5_CMD_UDP_ASSOC 3 #define S5_CMD_UDP_ASSOC 3
#define S5_ATYP_IP4 1 #define S5_ATYP_IP4 1
#define S5_ATYP_DOM 3 #define S5_ATYP_DOM 3
#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
#define S5_REP_NOT_ALLOWED_BY_RULESET 2 #define S5_REP_NOT_ALLOWED_BY_RULESET 2
#define S5_REP_NETWORK_UNREACHABLE 3 #define S5_REP_NETWORK_UNREACHABLE 3
#define S5_REP_HOST_UNREACHABLE 4 #define S5_REP_HOST_UNREACHABLE 4
#define S5_REP_CONN_REFUSED 5 #define S5_REP_CONN_REFUSED 5
#define S5_REP_TTL_EXPIRED 6 #define S5_REP_TTL_EXPIRED 6
#define S5_REP_COMMAND_NOT_SUPPORTED 7 #define S5_REP_COMMAND_NOT_SUPPORTED 7
#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,36 +9,40 @@
#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;
const char *method; const char *method;
bool bBypass = false, bHaveHost = false, bHostExcluded = false; bool bBypass = false, bHaveHost = false, bHostExcluded = false;
char *pc, Host[256]; char *pc, Host[256];
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,39 +85,41 @@ 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");
p = segment + method_len + 1; p = segment + method_len + 1;
pos = method_len + 1; pos = method_len + 1;
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;
VPRINT("Adding %s to host name at pos %zu\n", params.hostdot ? "dot" : "tab", pos); VPRINT("Adding %s to host name at pos %zu\n", params.hostdot ? "dot" : "tab", pos);
memmove(p + 1, p, *size - pos); memmove(p + 1, p, *size - pos);
*p = params.hostdot ? '.' : '\t'; // insert dot or tab *p = params.hostdot ? '.' : '\t'; // insert dot or tab
(*size)++; // block will grow by 1 byte (*size)++; // block will grow by 1 byte
} }
} }
if (params.domcase && HttpFindHost(&pHost,segment,*size)) if (params.domcase && HttpFindHost(&pHost, segment, *size))
{ {
p = pHost + 5; 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,78 +127,83 @@ 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
VPRINT("host padding with %zu bytes\n", hostpad); VPRINT("host padding with %zu bytes\n", hostpad);
p = pHost; p = pHost;
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,52 +215,59 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
{ {
spos = TLSPos(params.split_tls, params.split_pos, segment, *size, 0); 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)
*split_pos = params.split_pos; *split_pos = params.split_pos;
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)
@ -255,7 +275,7 @@ static void auto_hostlist_reset_fail_counter(const char *hostname)
if (hostname) if (hostname)
{ {
hostfail_pool *fail_counter; hostfail_pool *fail_counter;
fail_counter = HostFailPoolFind(params.hostlist_auto_fail_counters, hostname); fail_counter = HostFailPoolFind(params.hostlist_auto_fail_counters, hostname);
if (fail_counter) if (fail_counter)
{ {
@ -287,9 +307,9 @@ static void auto_hostlist_failed(const char *hostname)
{ {
VPRINT("auto hostlist : fail threshold reached. adding %s to auto hostlist\n", hostname); VPRINT("auto hostlist : fail threshold reached. adding %s to auto hostlist\n", 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

@ -4,10 +4,15 @@
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#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,21 +10,22 @@
#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
#define DEFAULT_TCP_USER_TIMEOUT_LOCAL 10 #define DEFAULT_TCP_USER_TIMEOUT_LOCAL 10
#define DEFAULT_TCP_USER_TIMEOUT_REMOTE 20 #define DEFAULT_TCP_USER_TIMEOUT_REMOTE 20
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_AVAILABLE, // operational CONN_UNAVAILABLE = 0, // connecting
CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked CONN_AVAILABLE, // operational
CONN_CLOSED // will be deleted soon CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked
CONN_CLOSED // will be deleted soon
}; };
typedef uint8_t conn_state_t; typedef uint8_t conn_state_t;
@ -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;
@ -48,8 +50,8 @@ typedef uint8_t conn_type_t;
struct tproxy_conn struct tproxy_conn
{ {
bool listener; // true - listening socket. false = connecion socket bool listener; // true - listening socket. false = connecion socket
bool remote; // false - accepted, true - connected bool remote; // false - accepted, true - connected
int efd; // epoll fd int efd; // epoll fd
int fd; int fd;
int splice_pipe[2]; int splice_pipe[2];
conn_state_t state; conn_state_t state;
@ -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