From c1db09b19ec6c1ef24c3716e8ffea502789e61b2 Mon Sep 17 00:00:00 2001 From: conc3rned Date: Tue, 17 Sep 2024 16:19:54 +0300 Subject: [PATCH] Linting and formatting of `.c` and `.h` with C/C++ IntelliSence --- ip2net/ip2net.c | 183 +-- ip2net/qsort.c | 269 ++-- ip2net/qsort.h | 4 +- mdig/mdig.c | 128 +- nfq/checksum.c | 79 +- nfq/checksum.h | 12 +- nfq/conntrack.c | 220 +-- nfq/conntrack.h | 77 +- nfq/crypto/aes-gcm.h | 2 +- nfq/crypto/aes.c | 494 +++---- nfq/crypto/aes.h | 82 +- nfq/crypto/gcm.c | 404 +++--- nfq/crypto/gcm.h | 158 +-- nfq/crypto/hkdf.c | 197 +-- nfq/crypto/hmac.c | 130 +- nfq/crypto/sha-private.h | 10 +- nfq/crypto/sha.h | 161 ++- nfq/crypto/sha224-256.c | 166 +-- nfq/crypto/usha.c | 100 +- nfq/darkmagic.c | 1153 ++++++++-------- nfq/darkmagic.h | 52 +- nfq/desync.c | 1401 +++++++++---------- nfq/desync.h | 5 +- nfq/gzip.c | 18 +- nfq/gzip.h | 4 +- nfq/helpers.c | 203 +-- nfq/helpers.h | 25 +- nfq/hostlist.c | 52 +- nfq/nfqws.c | 937 ++++++------- nfq/packet_queue.c | 37 +- nfq/packet_queue.h | 7 +- nfq/params.c | 58 +- nfq/params.h | 49 +- nfq/pools.c | 72 +- nfq/pools.h | 39 +- nfq/protocol.c | 555 +++++--- nfq/protocol.h | 31 +- nfq/sec.c | 186 ++- nfq/sec.h | 57 +- nfq/uthash.h | 1880 ++++++++++++++------------ nfq/win.c | 4 +- nfq/win.h | 1 - nfq/windivert/windivert.h | 973 +++++++------ tpws/epoll-shim/include/sys/epoll.h | 61 +- tpws/epoll-shim/src/epoll.c | 134 +- tpws/epoll-shim/src/epoll_shim_ctx.c | 85 +- tpws/epoll-shim/src/epoll_shim_ctx.h | 31 +- tpws/epoll-shim/src/epollfd_ctx.c | 802 +++++++---- tpws/epoll-shim/src/epollfd_ctx.h | 28 +- tpws/epoll-shim/src/eventfd_ctx.h | 5 +- tpws/epoll-shim/src/fix.c | 4 +- tpws/epoll-shim/src/fix.h | 9 +- tpws/epoll-shim/src/signalfd_ctx.h | 3 +- tpws/epoll-shim/src/timerfd_ctx.h | 5 +- tpws/gzip.c | 18 +- tpws/gzip.h | 4 +- tpws/helpers.c | 159 +-- tpws/helpers.h | 27 +- tpws/hostlist.c | 52 +- tpws/macos/net/pfvar.h | 76 +- tpws/macos/sys/tree.h | 1451 +++++++++++--------- tpws/params.c | 59 +- tpws/params.h | 43 +- tpws/pools.c | 72 +- tpws/pools.h | 39 +- tpws/protocol.c | 242 ++-- tpws/protocol.h | 20 +- tpws/redirect.c | 139 +- tpws/resolver.c | 109 +- tpws/resolver.h | 9 +- tpws/sec.c | 167 ++- tpws/sec.h | 56 +- tpws/socks.h | 96 +- tpws/tamper.c | 196 +-- tpws/tamper.h | 15 +- tpws/tpws.c | 673 ++++----- tpws/tpws.h | 2 +- tpws/tpws_conn.c | 1082 ++++++++------- tpws/tpws_conn.h | 55 +- tpws/uthash.h | 1880 ++++++++++++++------------ 80 files changed, 9996 insertions(+), 8587 deletions(-) diff --git a/ip2net/ip2net.c b/ip2net/ip2net.c index 793ee72..b7289b3 100644 --- a/ip2net/ip2net.c +++ b/ip2net/ip2net.c @@ -27,29 +27,29 @@ #define ALLOC_STEP 16384 // minimum subnet fill percent is PCTMULT/PCTDIV (for example 3/4) -#define DEFAULT_PCTMULT 3 -#define DEFAULT_PCTDIV 4 +#define DEFAULT_PCTMULT 3 +#define DEFAULT_PCTDIV 4 // subnet search range in "zero bit count" // means search start from /(32-ZCT_MAX) to /(32-ZCT_MIN) #define DEFAULT_V4_ZCT_MAX 10 // /22 #define DEFAULT_V4_ZCT_MIN 2 // /30 #define DEFAULT_V6_ZCT_MAX 72 // /56 #define DEFAULT_V6_ZCT_MIN 64 // /64 -// must be no less than N ipv6 in subnet -#define DEFAULT_V6_THRESHOLD 5 +// must be no less than N IPv6 in subnet +#define DEFAULT_V6_THRESHOLD 5 -static int ucmp(const void * a, const void * b, void *arg) +static int ucmp(const void *a, const void *b, void *arg) { - if (*(uint32_t*)a < *(uint32_t*)b) + if (*(uint32_t *)a < *(uint32_t *)b) return -1; - else if (*(uint32_t*)a > *(uint32_t*)b) + else if (*(uint32_t *)a > *(uint32_t *)b) return 1; else return 0; } static uint32_t mask_from_bitcount(uint32_t zct) { - return zct<32 ? ~((1 << zct) - 1) : 0; + return zct < 32 ? ~((1 << zct) - 1) : 0; } // make presorted array unique. return number of unique items. // 1,1,2,3,3,0,0,0 (ct=8) => 1,2,3,0 (ct=4) @@ -59,18 +59,18 @@ static uint32_t unique(uint32_t *pu, uint32_t ct) for (i = j = 0; j < ct; i++) { u = pu[j++]; - for (; j < ct && pu[j] == u; j++); + for (; j < ct && pu[j] == u; j++) + ; pu[i] = u; } return i; } - - #if defined(__GNUC__) && !defined(__llvm__) -__attribute__((optimize ("no-strict-aliasing"))) +__attribute__((optimize("no-strict-aliasing"))) #endif -static int cmp6(const void * a, const void * b, void *arg) +static int +cmp6(const void *a, const void *b, void *arg) { // this function is critical for sort performance // on big endian systems cpu byte order is equal to network byte order @@ -79,15 +79,15 @@ static int cmp6(const void * a, const void * b, void *arg) // 64-bit archs often have cpu command to reverse byte order // assume that a and b are properly aligned -#if defined(__BYTE_ORDER__) && ((__BYTE_ORDER__==__ORDER_BIG_ENDIAN__) || (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)) +#if defined(__BYTE_ORDER__) && ((__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - uint64_t aa,bb; -#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - aa = __builtin_bswap64(((uint64_t*)((struct in6_addr *)a)->s6_addr)[0]); - bb = __builtin_bswap64(((uint64_t*)((struct in6_addr *)b)->s6_addr)[0]); + uint64_t aa, bb; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + aa = __builtin_bswap64(((uint64_t *)((struct in6_addr *)a)->s6_addr)[0]); + bb = __builtin_bswap64(((uint64_t *)((struct in6_addr *)b)->s6_addr)[0]); #else - aa = ((uint64_t*)((struct in6_addr *)a)->s6_addr)[0]; - bb = ((uint64_t*)((struct in6_addr *)b)->s6_addr)[0]; + aa = ((uint64_t *)((struct in6_addr *)a)->s6_addr)[0]; + bb = ((uint64_t *)((struct in6_addr *)b)->s6_addr)[0]; #endif if (aa < bb) return -1; @@ -95,16 +95,17 @@ static int cmp6(const void * a, const void * b, void *arg) return 1; else { -#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - aa = __builtin_bswap64(((uint64_t*)((struct in6_addr *)a)->s6_addr)[1]); - bb = __builtin_bswap64(((uint64_t*)((struct in6_addr *)b)->s6_addr)[1]); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + aa = __builtin_bswap64(((uint64_t *)((struct in6_addr *)a)->s6_addr)[1]); + bb = __builtin_bswap64(((uint64_t *)((struct in6_addr *)b)->s6_addr)[1]); #else - aa = ((uint64_t*)((struct in6_addr *)a)->s6_addr)[1]; - bb = ((uint64_t*)((struct in6_addr *)b)->s6_addr)[1]; + aa = ((uint64_t *)((struct in6_addr *)a)->s6_addr)[1]; + bb = ((uint64_t *)((struct in6_addr *)b)->s6_addr)[1]; #endif - return aa < bb ? -1 : aa > bb ? 1 : 0; + return aa < bb ? -1 : aa > bb ? 1 + : 0; } - + #else // fallback case for (uint8_t i = 0; i < sizeof(((struct in6_addr *)0)->s6_addr); i++) @@ -124,7 +125,8 @@ static uint32_t unique6(struct in6_addr *pu, uint32_t ct) uint32_t i, j, k; for (i = j = 0; j < ct; i++) { - for (k = j++; j < ct && !memcmp(pu + j, pu + k, sizeof(struct in6_addr)); j++); + for (k = j++; j < ct && !memcmp(pu + j, pu + k, sizeof(struct in6_addr)); j++) + ; pu[i] = pu[k]; } return i; @@ -132,26 +134,26 @@ static uint32_t unique6(struct in6_addr *pu, uint32_t ct) static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a) { if (zct >= 128) - memset(a->s6_addr,0x00,16); + memset(a->s6_addr, 0x00, 16); else { int32_t n = (127 - zct) >> 3; - memset(a->s6_addr,0xFF,n); - memset(a->s6_addr+n,0x00,16-n); + memset(a->s6_addr, 0xFF, n); + memset(a->s6_addr + n, 0x00, 16 - n); a->s6_addr[n] = ~((1 << (zct & 7)) - 1); } } static struct in6_addr ip6_mask[129]; static void mask_from_bitcount6_prepare(void) { - for (int zct=0;zct<=128;zct++) mask_from_bitcount6_make(zct, ip6_mask+zct); + for (int zct = 0; zct <= 128; zct++) + mask_from_bitcount6_make(zct, ip6_mask + zct); } static inline const struct in6_addr *mask_from_bitcount6(uint32_t zct) { - return ip6_mask+zct; + return ip6_mask + zct; } - /* // this is "correct" solution for strict aliasing feature // but I don't like this style of coding @@ -176,44 +178,43 @@ static void ip6_and(const struct in6_addr *a, const struct in6_addr *b, struct i // result = a & b // assume that a and b are properly aligned #if defined(__GNUC__) && !defined(__llvm__) -__attribute__((optimize ("no-strict-aliasing"))) +__attribute__((optimize("no-strict-aliasing"))) #endif -static void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result) +static void +ip6_and(const struct in6_addr *restrict a, const struct in6_addr *restrict b, struct in6_addr *restrict result) { #ifdef __SIZEOF_INT128__ // gcc and clang have 128 bit int types on some 64-bit archs. take some advantage - *((unsigned __int128*)result->s6_addr) = *((unsigned __int128*)a->s6_addr) & *((unsigned __int128*)b->s6_addr); + *((unsigned __int128 *)result->s6_addr) = *((unsigned __int128 *)a->s6_addr) & *((unsigned __int128 *)b->s6_addr); #else - ((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0]; - ((uint64_t*)result->s6_addr)[1] = ((uint64_t*)a->s6_addr)[1] & ((uint64_t*)b->s6_addr)[1]; + ((uint64_t *)result->s6_addr)[0] = ((uint64_t *)a->s6_addr)[0] & ((uint64_t *)b->s6_addr)[0]; + ((uint64_t *)result->s6_addr)[1] = ((uint64_t *)a->s6_addr)[1] & ((uint64_t *)b->s6_addr)[1]; #endif } static void rtrim(char *s) { if (s) - for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0'; + for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) + *p = '\0'; } - static struct params_s { bool ipv6; - uint32_t pctmult, pctdiv; // for v4 + uint32_t pctmult, pctdiv; // for v4 uint32_t zct_min, zct_max; // for v4 and v6 - uint32_t v6_threshold; // for v6 + uint32_t v6_threshold; // for v6 } params; - static void exithelp(void) { printf( - " -4\t\t\t\t; ipv4 list (default)\n" - " -6\t\t\t\t; ipv6 list\n" - " --prefix-length=min[-max]\t; consider prefix lengths from 'min' to 'max'. examples : 22-30 (ipv4), 56-64 (ipv6)\n" - " --v4-threshold=mul/div\t\t; ipv4 only : include subnets with more than mul/div ips. example : 3/4\n" - " --v6-threshold=N\t\t; ipv6 only : include subnets with more than N v6 ips. example : 5\n" - ); + " -4\t\t\t\t; IPv4 list (default)\n" + " -6\t\t\t\t; IPv6 list\n" + " --prefix-length=min[-max]\t; consider prefix lengths from 'min' to 'max'. examples : 22-30 (IPv4), 56-64 (IPv6)\n" + " --v4-threshold=mul/div\t\t; IPv4 only : include subnets with more than mul/div ips. example : 3/4\n" + " --v6-threshold=N\t\t; IPv6 only : include subnets with more than N v6 ips. example : 5\n"); exit(1); } @@ -221,7 +222,7 @@ static void parse_params(int argc, char *argv[]) { int option_index = 0; int v, i; - uint32_t plen1=-1, plen2=-1; + uint32_t plen1 = -1, plen2 = -1; memset(¶ms, 0, sizeof(params)); params.pctmult = DEFAULT_PCTMULT; @@ -229,18 +230,18 @@ static void parse_params(int argc, char *argv[]) params.v6_threshold = DEFAULT_V6_THRESHOLD; const struct option long_options[] = { - { "help",no_argument,0,0 },// optidx=0 - { "h",no_argument,0,0 },// optidx=1 - { "4",no_argument,0,0 },// optidx=2 - { "6",no_argument,0,0 },// optidx=3 - { "prefix-length",required_argument,0,0 },// optidx=4 - { "v4-threshold",required_argument,0,0 },// optidx=5 - { "v6-threshold",required_argument,0,0 },// optidx=6 - { NULL,0,NULL,0 } - }; + {"help", no_argument, 0, 0}, // optidx=0 + {"h", no_argument, 0, 0}, // optidx=1 + {"4", no_argument, 0, 0}, // optidx=2 + {"6", no_argument, 0, 0}, // optidx=3 + {"prefix-length", required_argument, 0, 0}, // optidx=4 + {"v4-threshold", required_argument, 0, 0}, // optidx=5 + {"v6-threshold", required_argument, 0, 0}, // optidx=6 + {NULL, 0, NULL, 0}}; while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { - if (v) exithelp(); + if (v) + exithelp(); switch (option_index) { case 0: @@ -254,9 +255,10 @@ static void parse_params(int argc, char *argv[]) params.ipv6 = true; break; case 4: - i = sscanf(optarg,"%u-%u",&plen1,&plen2); - if (i == 1) plen2 = plen1; - if (i<=0 || plen2=params.pctdiv) + if (i != 2 || params.pctdiv < 2 || params.pctmult < 1 || params.pctmult >= params.pctdiv) { fprintf(stderr, "invalid parameter for v4-threshold : %s\n", optarg); exit(1); @@ -272,7 +274,7 @@ static void parse_params(int argc, char *argv[]) break; case 6: i = sscanf(optarg, "%u", ¶ms.v6_threshold); - if (i != 1 || params.v6_threshold<1) + if (i != 1 || params.v6_threshold < 1) { fprintf(stderr, "invalid parameter for v6-threshold : %s\n", optarg); exit(1); @@ -280,19 +282,20 @@ static void parse_params(int argc, char *argv[]) break; } } - if (plen1 != -1 && ((!params.ipv6 && (plen1>31 || plen2>31)) || (params.ipv6 && (plen1>127 || plen2>127)))) + if (plen1 != -1 && ((!params.ipv6 && (plen1 > 31 || plen2 > 31)) || (params.ipv6 && (plen1 > 127 || plen2 > 127)))) { fprintf(stderr, "invalid parameter for prefix-length\n"); exit(1); } - params.zct_min = params.ipv6 ? plen2==-1 ? DEFAULT_V6_ZCT_MIN : 128-plen2 : plen2==-1 ? DEFAULT_V4_ZCT_MIN : 32-plen2; - params.zct_max = params.ipv6 ? plen1==-1 ? DEFAULT_V6_ZCT_MAX : 128-plen1 : plen1==-1 ? DEFAULT_V4_ZCT_MAX : 32-plen1; + params.zct_min = params.ipv6 ? plen2 == -1 ? DEFAULT_V6_ZCT_MIN : 128 - plen2 : plen2 == -1 ? DEFAULT_V4_ZCT_MIN + : 32 - plen2; + params.zct_max = params.ipv6 ? plen1 == -1 ? DEFAULT_V6_ZCT_MAX : 128 - plen1 : plen1 == -1 ? DEFAULT_V4_ZCT_MAX + : 32 - plen1; } - int main(int argc, char **argv) { - char str[256],d; + char str[256], d; uint32_t ipct = 0, iplist_size = 0, pos = 0, p, zct, ip_ct, pos_end; parse_params(argc, argv); @@ -313,25 +316,27 @@ int main(int argc, char **argv) } if (inet_pton(AF_INET6, str, &a)) { - if (d=='/') + if (d == '/') { // we have subnet ip6/y // output it as is - if (sscanf(s + 1, "%u", &zct)==1 && zct!=128) + if (sscanf(s + 1, "%u", &zct) == 1 && zct != 128) { - if (zct<128) printf("%s/%u\n", str, zct); + if (zct < 128) + printf("%s/%u\n", str, zct); continue; } } - else if (d=='-') + else if (d == '-') { - if (inet_pton(AF_INET6, s+1, &a)) printf("%s-%s\n", str, s+1); + if (inet_pton(AF_INET6, s + 1, &a)) + printf("%s-%s\n", str, s + 1); continue; } if (ipct >= iplist_size) { iplist_size += ALLOC_STEP; - iplist_new = (struct in6_addr*)(iplist ? realloc(iplist, sizeof(*iplist)*iplist_size) : malloc(sizeof(*iplist)*iplist_size)); + iplist_new = (struct in6_addr *)(iplist ? realloc(iplist, sizeof(*iplist) * iplist_size) : malloc(sizeof(*iplist) * iplist_size)); if (!iplist_new) { free(iplist); @@ -371,7 +376,8 @@ int main(int argc, char **argv) if (memcmp(&ip_start, &ip, sizeof(ip))) break; } - if (ip_ct == 1) break; + if (ip_ct == 1) + break; if (ip_ct >= params.v6_threshold) { // network found. but is there smaller network with the same ip_ct ? dont do carpet bombing if possible, use smaller subnets @@ -400,20 +406,19 @@ int main(int argc, char **argv) } else // ipv4 { - uint32_t u1,u2,u3,u4, u11,u22,u33,u44, ip; + uint32_t u1, u2, u3, u4, u11, u22, u33, u44, ip; uint32_t *iplist = NULL, *iplist_new, i; while (fgets(str, sizeof(str), stdin)) { - if ((i = sscanf(str, "%u.%u.%u.%u-%u.%u.%u.%u", &u1, &u2, &u3, &u4, &u11, &u22, &u33, &u44)) >= 8 && + if ((i = sscanf(str, "%u.%u.%u.%u-%u.%u.%u.%u", &u1, &u2, &u3, &u4, &u11, &u22, &u33, &u44)) >= 8 && !(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00) && !(u11 & 0xFFFFFF00) && !(u22 & 0xFFFFFF00) && !(u33 & 0xFFFFFF00) && !(u44 & 0xFFFFFF00)) { printf("%u.%u.%u.%u-%u.%u.%u.%u\n", u1, u2, u3, u4, u11, u22, u33, u44); } - else - if ((i = sscanf(str, "%u.%u.%u.%u/%u", &u1, &u2, &u3, &u4, &zct)) >= 4 && - !(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00)) + else if ((i = sscanf(str, "%u.%u.%u.%u/%u", &u1, &u2, &u3, &u4, &zct)) >= 4 && + !(u1 & 0xFFFFFF00) && !(u2 & 0xFFFFFF00) && !(u3 & 0xFFFFFF00) && !(u4 & 0xFFFFFF00)) { if (i == 5 && zct != 32) { @@ -428,7 +433,7 @@ int main(int argc, char **argv) if (ipct >= iplist_size) { iplist_size += ALLOC_STEP; - iplist_new = (uint32_t*)(iplist ? realloc(iplist, sizeof(*iplist)*iplist_size) : malloc(sizeof(*iplist)*iplist_size)); + iplist_new = (uint32_t *)(iplist ? realloc(iplist, sizeof(*iplist) * iplist_size) : malloc(sizeof(*iplist) * iplist_size)); if (!iplist_new) { free(iplist); @@ -456,12 +461,14 @@ int main(int argc, char **argv) mask = mask_from_bitcount(zct); ip_start = iplist[pos] & mask; subnet_ct = ~mask + 1; - if (iplist[pos] > (ip_start + subnet_ct*(params.pctdiv - params.pctmult) / params.pctdiv)) + if (iplist[pos] > (ip_start + subnet_ct * (params.pctdiv - params.pctmult) / params.pctdiv)) continue; // ip is higher than (1-PCT). definitely coverage is not enough. skip searching ip_end = ip_start | ~mask; - for (p=pos+1, ip_ct=1; p < ipct && iplist[p] <= ip_end; p++) ip_ct++; // count ips within subnet range - if (ip_ct == 1) break; - if (ip_ct >= (subnet_ct*params.pctmult / params.pctdiv)) + for (p = pos + 1, ip_ct = 1; p < ipct && iplist[p] <= ip_end; p++) + ip_ct++; // count ips within subnet range + if (ip_ct == 1) + break; + if (ip_ct >= (subnet_ct * params.pctmult / params.pctdiv)) { // network found. but is there smaller network with the same ip_ct ? dont do carpet bombing if possible, use smaller subnets if (!ip_ct_best || ip_ct == ip_ct_best) diff --git a/ip2net/qsort.c b/ip2net/qsort.c index 2ee1185..3dd694f 100644 --- a/ip2net/qsort.c +++ b/ip2net/qsort.c @@ -20,25 +20,25 @@ Engineering a sort function; Jon Bentley and M. Douglas McIlroy; Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */ -//#include +// #include #include #include -//#include +// #include #include "qsort.h" /* Byte-wise swap two items of size SIZE. */ -#define SWAP(a, b, size) \ - do \ - { \ - size_t __size = (size); \ - char *__a = (a), *__b = (b); \ - do \ - { \ - char __tmp = *__a; \ - *__a++ = *__b; \ - *__b++ = __tmp; \ - } while (--__size > 0); \ - } while (0) +#define SWAP(a, b, size) \ + do \ + { \ + size_t __size = (size); \ + char *__a = (a), *__b = (b); \ + do \ + { \ + char __tmp = *__a; \ + *__a++ = *__b; \ + *__b++ = __tmp; \ + } while (--__size > 0); \ + } while (0) /* Discontinue quicksort algorithm when partition gets below this size. This particular magic number was chosen to work best on a Sun 4/260. */ @@ -46,21 +46,20 @@ /* Stack node declarations used to store unfulfilled partition obligations. */ typedef struct - { - char *lo; - char *hi; - } stack_node; +{ + char *lo; + char *hi; +} stack_node; /* The next 4 #defines implement a very fast in-line stack abstraction. */ /* The stack needs log (total_elements) entries (we could even subtract log(MAX_THRESH)). Since total_elements has type size_t, we get as upper bound for log (total_elements): bits per byte (CHAR_BIT) * sizeof(size_t). */ -#define STACK_SIZE (CHAR_BIT * sizeof(size_t)) -#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top)) -#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) -#define STACK_NOT_EMPTY (stack < top) - +#define STACK_SIZE (CHAR_BIT * sizeof(size_t)) +#define PUSH(low, high) ((void)((top->lo = (low)), (top->hi = (high)), ++top)) +#define POP(low, high) ((void)(--top, (low = top->lo), (high = top->hi))) +#define STACK_NOT_EMPTY (stack < top) /* Order size using quicksort. This implementation incorporates four optimizations discussed in Sedgewick: @@ -86,11 +85,10 @@ typedef struct smaller partition. This *guarantees* no more than log (total_elems) stack size is needed (actually O(1) in this case)! */ -void -gnu_quicksort (void *const pbase, size_t total_elems, size_t size, - __gnu_compar_d_fn_t cmp, void *arg) +void gnu_quicksort(void *const pbase, size_t total_elems, size_t size, + __gnu_compar_d_fn_t cmp, void *arg) { - char *base_ptr = (char *) pbase; + char *base_ptr = (char *)pbase; const size_t max_thresh = MAX_THRESH * size; @@ -99,101 +97,100 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size, return; if (total_elems > MAX_THRESH) + { + char *lo = base_ptr; + char *hi = &lo[size * (total_elems - 1)]; + stack_node stack[STACK_SIZE]; + stack_node *top = stack; + + PUSH(NULL, NULL); + + while (STACK_NOT_EMPTY) { - char *lo = base_ptr; - char *hi = &lo[size * (total_elems - 1)]; - stack_node stack[STACK_SIZE]; - stack_node *top = stack; + char *left_ptr; + char *right_ptr; - PUSH (NULL, NULL); + /* Select median value from among LO, MID, and HI. Rearrange + LO and HI so the three values are sorted. This lowers the + probability of picking a pathological pivot value and + skips a comparison for both the LEFT_PTR and RIGHT_PTR in + the while loops. */ - while (STACK_NOT_EMPTY) + char *mid = lo + size * ((hi - lo) / size >> 1); + + if ((*cmp)((void *)mid, (void *)lo, arg) < 0) + SWAP(mid, lo, size); + if ((*cmp)((void *)hi, (void *)mid, arg) < 0) + SWAP(mid, hi, size); + else + goto jump_over; + if ((*cmp)((void *)mid, (void *)lo, arg) < 0) + SWAP(mid, lo, size); + jump_over:; + + left_ptr = lo + size; + right_ptr = hi - size; + + /* Here's the famous ``collapse the walls'' section of quicksort. + Gotta like those tight inner loops! They are the main reason + that this algorithm runs much faster than others. */ + do + { + while ((*cmp)((void *)left_ptr, (void *)mid, arg) < 0) + left_ptr += size; + + while ((*cmp)((void *)mid, (void *)right_ptr, arg) < 0) + right_ptr -= size; + + if (left_ptr < right_ptr) { - char *left_ptr; - char *right_ptr; - - /* Select median value from among LO, MID, and HI. Rearrange - LO and HI so the three values are sorted. This lowers the - probability of picking a pathological pivot value and - skips a comparison for both the LEFT_PTR and RIGHT_PTR in - the while loops. */ - - char *mid = lo + size * ((hi - lo) / size >> 1); - - if ((*cmp) ((void *) mid, (void *) lo, arg) < 0) - SWAP (mid, lo, size); - if ((*cmp) ((void *) hi, (void *) mid, arg) < 0) - SWAP (mid, hi, size); - else - goto jump_over; - if ((*cmp) ((void *) mid, (void *) lo, arg) < 0) - SWAP (mid, lo, size); - jump_over:; - - left_ptr = lo + size; - right_ptr = hi - size; - - /* Here's the famous ``collapse the walls'' section of quicksort. - Gotta like those tight inner loops! They are the main reason - that this algorithm runs much faster than others. */ - do - { - while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0) - left_ptr += size; - - while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0) - right_ptr -= size; - - if (left_ptr < right_ptr) - { - SWAP (left_ptr, right_ptr, size); - if (mid == left_ptr) - mid = right_ptr; - else if (mid == right_ptr) - mid = left_ptr; - left_ptr += size; - right_ptr -= size; - } - else if (left_ptr == right_ptr) - { - left_ptr += size; - right_ptr -= size; - break; - } - } - while (left_ptr <= right_ptr); - - /* Set up pointers for next iteration. First determine whether - left and right partitions are below the threshold size. If so, - ignore one or both. Otherwise, push the larger partition's - bounds on the stack and continue sorting the smaller one. */ - - if ((size_t) (right_ptr - lo) <= max_thresh) - { - if ((size_t) (hi - left_ptr) <= max_thresh) - /* Ignore both small partitions. */ - POP (lo, hi); - else - /* Ignore small left partition. */ - lo = left_ptr; - } - else if ((size_t) (hi - left_ptr) <= max_thresh) - /* Ignore small right partition. */ - hi = right_ptr; - else if ((right_ptr - lo) > (hi - left_ptr)) - { - /* Push larger left partition indices. */ - PUSH (lo, right_ptr); - lo = left_ptr; - } - else - { - /* Push larger right partition indices. */ - PUSH (left_ptr, hi); - hi = right_ptr; - } + SWAP(left_ptr, right_ptr, size); + if (mid == left_ptr) + mid = right_ptr; + else if (mid == right_ptr) + mid = left_ptr; + left_ptr += size; + right_ptr -= size; } + else if (left_ptr == right_ptr) + { + left_ptr += size; + right_ptr -= size; + break; + } + } while (left_ptr <= right_ptr); + + /* Set up pointers for next iteration. First determine whether + left and right partitions are below the threshold size. If so, + ignore one or both. Otherwise, push the larger partition's + bounds on the stack and continue sorting the smaller one. */ + + if ((size_t)(right_ptr - lo) <= max_thresh) + { + if ((size_t)(hi - left_ptr) <= max_thresh) + /* Ignore both small partitions. */ + POP(lo, hi); + else + /* Ignore small left partition. */ + lo = left_ptr; + } + else if ((size_t)(hi - left_ptr) <= max_thresh) + /* Ignore small right partition. */ + hi = right_ptr; + else if ((right_ptr - lo) > (hi - left_ptr)) + { + /* Push larger left partition indices. */ + PUSH(lo, right_ptr); + lo = left_ptr; + } + else + { + /* Push larger right partition indices. */ + PUSH(left_ptr, hi); + hi = right_ptr; + } } + } /* Once the BASE_PTR array is partially sorted by quicksort the rest is completely sorted using insertion sort, since this is efficient @@ -214,37 +211,37 @@ gnu_quicksort (void *const pbase, size_t total_elems, size_t size, and the operation speeds up insertion sort's inner loop. */ for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) - if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0) + if ((*cmp)((void *)run_ptr, (void *)tmp_ptr, arg) < 0) tmp_ptr = run_ptr; if (tmp_ptr != base_ptr) - SWAP (tmp_ptr, base_ptr, size); + SWAP(tmp_ptr, base_ptr, size); /* Insertion sort, running from left-hand-side up to right-hand-side. */ run_ptr = base_ptr + size; while ((run_ptr += size) <= end_ptr) + { + tmp_ptr = run_ptr - size; + while ((*cmp)((void *)run_ptr, (void *)tmp_ptr, arg) < 0) + tmp_ptr -= size; + + tmp_ptr += size; + if (tmp_ptr != run_ptr) { - tmp_ptr = run_ptr - size; - while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0) - tmp_ptr -= size; + char *trav; - tmp_ptr += size; - if (tmp_ptr != run_ptr) - { - char *trav; + trav = run_ptr + size; + while (--trav >= run_ptr) + { + char c = *trav; + char *hi, *lo; - trav = run_ptr + size; - while (--trav >= run_ptr) - { - char c = *trav; - char *hi, *lo; - - for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) - *hi = *lo; - *hi = c; - } - } + for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) + *hi = *lo; + *hi = c; + } } + } } } diff --git a/ip2net/qsort.h b/ip2net/qsort.h index f537ab7..16d650e 100644 --- a/ip2net/qsort.h +++ b/ip2net/qsort.h @@ -2,5 +2,5 @@ // GNU qsort is 2x faster than musl -typedef int (*__gnu_compar_d_fn_t) (const void *, const void *, void *); -void gnu_quicksort (void *const pbase, size_t total_elems, size_t size, __gnu_compar_d_fn_t cmp, void *arg); +typedef int (*__gnu_compar_d_fn_t)(const void *, const void *, void *); +void gnu_quicksort(void *const pbase, size_t total_elems, size_t size, __gnu_compar_d_fn_t cmp, void *arg); diff --git a/mdig/mdig.c b/mdig/mdig.c index 047e7b6..ed2ae4b 100644 --- a/mdig/mdig.c +++ b/mdig/mdig.c @@ -34,10 +34,11 @@ static void trimstr(char *s) { char *p; - for (p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0'; + for (p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) + *p = '\0'; } -static const char* eai_str(int r) +static const char *eai_str(int r) { switch (r) { @@ -76,18 +77,21 @@ static const char* eai_str(int r) static bool dom_valid(char *dom) { - if (!dom || *dom=='.') return false; - for (; *dom; dom++) - if (*dom < 0x20 || (*dom & 0x80) || !(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z'))) + if (!dom || *dom == '.') return false; + for (; *dom; dom++) + if (*dom < 0x20 || (*dom & 0x80) || !(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z'))) + return false; return true; } static void invalid_domain_beautify(char *dom) { for (int i = 0; *dom && i < 64; i++, dom++) - if (*dom < 0x20 || *dom>0x7F) *dom = '?'; - if (*dom) *dom = 0; + if (*dom < 0x20 || *dom > 0x7F) + *dom = '?'; + if (*dom) + *dom = 0; } #define FAMILY4 1 @@ -99,7 +103,7 @@ static struct int threads; time_t start_time; pthread_mutex_t flock; - pthread_mutex_t slock; // stats lock + pthread_mutex_t slock; // stats lock int stats_every, stats_ct, stats_ct_ok; // stats FILE *F_log_resolved, *F_log_failed; } glob; @@ -111,11 +115,12 @@ static char interlocked_get_dom(char *dom, size_t size) pthread_mutex_lock(&glob.flock); s = fgets(dom, size, stdin); pthread_mutex_unlock(&glob.flock); - if (!s) return 0; + if (!s) + return 0; trimstr(s); return 1; } -static void interlocked_fprintf(FILE *stream, const char * format, ...) +static void interlocked_fprintf(FILE *stream, const char *format, ...) { if (stream) { @@ -128,8 +133,12 @@ static void interlocked_fprintf(FILE *stream, const char * format, ...) } } -#define ELOG(format, ...) interlocked_fprintf(stderr, "[%d] " format "\n", tid, ##__VA_ARGS__) -#define VLOG(format, ...) {if (glob.verbose) ELOG(format, ##__VA_ARGS__);} +#define ELOG(format, ...) interlocked_fprintf(stderr, "[%d] " format "\n", tid, ##__VA_ARGS__) +#define VLOG(format, ...) \ + { \ + if (glob.verbose) \ + ELOG(format, ##__VA_ARGS__); \ + } static void print_addrinfo(struct addrinfo *ai) { @@ -139,11 +148,11 @@ static void print_addrinfo(struct addrinfo *ai) switch (ai->ai_family) { case AF_INET: - if (inet_ntop(ai->ai_family, &((struct sockaddr_in*)ai->ai_addr)->sin_addr, str, sizeof(str))) + if (inet_ntop(ai->ai_family, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, str, sizeof(str))) interlocked_fprintf(stdout, "%s\n", str); break; case AF_INET6: - if (inet_ntop(ai->ai_family, &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, str, sizeof(str))) + if (inet_ntop(ai->ai_family, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, str, sizeof(str))) interlocked_fprintf(stdout, "%s\n", str); break; } @@ -155,8 +164,8 @@ static void stat_print(int ct, int ct_ok) { if (glob.stats_every > 0) { - time_t tm = time(NULL)-glob.start_time; - interlocked_fprintf(stderr, "mdig stats : %02u:%02u:%02u : domains=%d success=%d error=%d\n", (unsigned int)(tm/3600), (unsigned int)((tm/60)%60), (unsigned int)(tm%60), ct, ct_ok, ct - ct_ok); + time_t tm = time(NULL) - glob.start_time; + interlocked_fprintf(stderr, "mdig stats : %02u:%02u:%02u : domains=%d success=%d error=%d\n", (unsigned int)(tm / 3600), (unsigned int)((tm / 60) % 60), (unsigned int)(tm % 60), ct, ct_ok, ct - ct_ok); } } @@ -170,7 +179,8 @@ static void stat_plus(bool is_ok) ct_ok = glob.stats_ct_ok += is_ok; pthread_mutex_unlock(&glob.slock); - if (!(ct % glob.stats_every)) stat_print(ct, ct_ok); + if (!(ct % glob.stats_every)) + stat_print(ct, ct_ok); } } @@ -198,7 +208,8 @@ static void *t_resolver(void *arg) VLOG("started"); memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = (glob.family == FAMILY4) ? AF_INET : (glob.family == FAMILY6) ? AF_INET6 : AF_UNSPEC; + hints.ai_family = (glob.family == FAMILY4) ? AF_INET : (glob.family == FAMILY6) ? AF_INET6 + : AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; while (interlocked_get_dom(dom, sizeof(dom))) @@ -211,7 +222,8 @@ static void *t_resolver(void *arg) strncpy(s_ip, dom, sizeof(s_ip)); s_mask = strchr(s_ip, '/'); - if (s_mask) *s_mask++ = 0; + if (s_mask) + *s_mask++ = 0; family = GetAddrFamily(s_ip); if (family) { @@ -221,12 +233,18 @@ static void *t_resolver(void *arg) bool mask_needed = false; if (s_mask) { - if (sscanf(s_mask, "%u", &mask)==1) + if (sscanf(s_mask, "%u", &mask) == 1) { switch (family) { - case AF_INET: is_ok = mask <= 32; mask_needed = mask < 32; break; - case AF_INET6: is_ok = mask <= 128; mask_needed = mask < 128; break; + case AF_INET: + is_ok = mask <= 32; + mask_needed = mask < 32; + break; + case AF_INET6: + is_ok = mask <= 128; + mask_needed = mask < 128; + break; } } } @@ -248,7 +266,8 @@ static void *t_resolver(void *arg) if ((r = getaddrinfo(dom, NULL, &hints, &result))) { VLOG("failed to resolve %s : result %d (%s)", dom, r, eai_str(r)); - if (r == EAI_AGAIN) continue; // temporary failure. should retry + if (r == EAI_AGAIN) + continue; // temporary failure. should retry } else { @@ -262,11 +281,11 @@ static void *t_resolver(void *arg) else if (glob.verbose) { char dom2[sizeof(dom)]; - strcpy(dom2,dom); + strcpy(dom2, dom); invalid_domain_beautify(dom2); VLOG("invalid domain : %s", dom2); } - interlocked_fprintf(is_ok ? glob.F_log_resolved : glob.F_log_failed,"%s\n",dom); + interlocked_fprintf(is_ok ? glob.F_log_resolved : glob.F_log_failed, "%s\n", dom); } stat_plus(is_ok); } @@ -292,7 +311,7 @@ static int run_threads(void) pthread_mutex_destroy(&glob.flock); return 10; } - t = (pthread_t*)malloc(sizeof(pthread_t)*glob.threads); + t = (pthread_t *)malloc(sizeof(pthread_t) * glob.threads); if (!t) { fprintf(stderr, "out of memory\n"); @@ -302,7 +321,7 @@ static int run_threads(void) } for (thread = 0; thread < glob.threads; thread++) { - if (pthread_create(t + thread, NULL, t_resolver, (void*)(size_t)thread)) + if (pthread_create(t + thread, NULL, t_resolver, (void *)(size_t)thread)) { interlocked_fprintf(stderr, "failed to create thread #%d\n", thread); break; @@ -327,25 +346,23 @@ static void exithelp(void) " --verbose\t\t; print query progress to stderr\n" " --stats=N\t\t; print resolve stats to stderr every N domains\n" " --log-resolved=\t; log successfully resolved domains to a file\n" - " --log-failed=\t; log failed domains to a file\n" - ); + " --log-failed=\t; log failed domains to a file\n"); exit(1); } int main(int argc, char **argv) { int r, v, option_index = 0; - char fn1[256],fn2[256]; + char fn1[256], fn2[256]; static const struct option long_options[] = { - {"help",no_argument,0,0}, // optidx=0 - {"threads",required_argument,0,0}, // optidx=1 - {"family",required_argument,0,0}, // optidx=2 - {"verbose",no_argument,0,0}, // optidx=3 - {"stats",required_argument,0,0}, // optidx=4 - {"log-resolved",required_argument,0,0}, // optidx=5 - {"log-failed",required_argument,0,0}, // optidx=6 - {NULL,0,NULL,0} - }; + {"help", no_argument, 0, 0}, // optidx=0 + {"threads", required_argument, 0, 0}, // optidx=1 + {"family", required_argument, 0, 0}, // optidx=2 + {"verbose", no_argument, 0, 0}, // optidx=3 + {"stats", required_argument, 0, 0}, // optidx=4 + {"log-resolved", required_argument, 0, 0}, // optidx=5 + {"log-failed", required_argument, 0, 0}, // optidx=6 + {NULL, 0, NULL, 0}}; memset(&glob, 0, sizeof(glob)); *fn1 = *fn2 = 0; @@ -353,7 +370,8 @@ int main(int argc, char **argv) glob.threads = 1; while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { - if (v) exithelp(); + if (v) + exithelp(); switch (option_index) { case 0: /* help */ @@ -387,12 +405,12 @@ int main(int argc, char **argv) glob.stats_every = optarg ? atoi(optarg) : 0; break; case 5: /* log-resolved */ - strncpy(fn1,optarg,sizeof(fn1)); - fn1[sizeof(fn1)-1] = 0; + strncpy(fn1, optarg, sizeof(fn1)); + fn1[sizeof(fn1) - 1] = 0; break; case 6: /* log-failed */ - strncpy(fn2,optarg,sizeof(fn2)); - fn2[sizeof(fn2)-1] = 0; + strncpy(fn2, optarg, sizeof(fn2)); + fn2[sizeof(fn2) - 1] = 0; break; } } @@ -401,35 +419,39 @@ int main(int argc, char **argv) WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData)) { - fprintf(stderr,"WSAStartup failed\n"); + fprintf(stderr, "WSAStartup failed\n"); return 4; } #endif if (*fn1) { - glob.F_log_resolved = fopen(fn1,"wt"); + glob.F_log_resolved = fopen(fn1, "wt"); if (!glob.F_log_resolved) { - fprintf(stderr,"failed to create %s\n",fn1); - r=5; goto ex; + fprintf(stderr, "failed to create %s\n", fn1); + r = 5; + goto ex; } } if (*fn2) { - glob.F_log_failed = fopen(fn2,"wt"); + glob.F_log_failed = fopen(fn2, "wt"); if (!glob.F_log_failed) { - fprintf(stderr,"failed to create %s\n",fn2); - r=5; goto ex; + fprintf(stderr, "failed to create %s\n", fn2); + r = 5; + goto ex; } } r = run_threads(); ex: - if (glob.F_log_resolved) fclose(glob.F_log_resolved); - if (glob.F_log_failed) fclose(glob.F_log_failed); + if (glob.F_log_resolved) + fclose(glob.F_log_resolved); + if (glob.F_log_failed) + fclose(glob.F_log_failed); return r; } diff --git a/nfq/checksum.c b/nfq/checksum.c index dcc3657..d9471ef 100644 --- a/nfq/checksum.c +++ b/nfq/checksum.c @@ -2,64 +2,65 @@ #include "checksum.h" #include -//#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) -//#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) +// #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) +// #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) static uint16_t from64to16(uint64_t x) { - uint32_t u = (uint32_t)(uint16_t)x + (uint16_t)(x>>16) + (uint16_t)(x>>32) + (uint16_t)(x>>48); - return (uint16_t)u + (uint16_t)(u>>16); + uint32_t u = (uint32_t)(uint16_t)x + (uint16_t)(x >> 16) + (uint16_t)(x >> 32) + (uint16_t)(x >> 48); + return (uint16_t)u + (uint16_t)(u >> 16); } // this function preserves data alignment requirements (otherwise it will be damn slow on mips arch) // and uses 64-bit arithmetics to improve speed -// taken from linux source code -static uint16_t do_csum(const uint8_t * buff, size_t len) +// taken from Linux source code +static uint16_t do_csum(const uint8_t *buff, size_t len) { uint8_t odd; size_t count; - uint64_t result,w,carry=0; + uint64_t result, w, carry = 0; uint16_t u16; - if (!len) return 0; + if (!len) + return 0; odd = (uint8_t)(1 & (size_t)buff); if (odd) { // any endian compatible u16 = 0; - *((uint8_t*)&u16+1) = *buff; + *((uint8_t *)&u16 + 1) = *buff; result = u16; len--; buff++; } else result = 0; - count = len >> 1; /* nr of 16-bit words.. */ + count = len >> 1; /* nr of 16-bit words.. */ if (count) { - if (2 & (size_t) buff) + if (2 & (size_t)buff) { - result += *(uint16_t *) buff; + result += *(uint16_t *)buff; count--; len -= 2; buff += 2; } - count >>= 1; /* nr of 32-bit words.. */ + count >>= 1; /* nr of 32-bit words.. */ if (count) { - if (4 & (size_t) buff) + if (4 & (size_t)buff) { - result += *(uint32_t *) buff; + result += *(uint32_t *)buff; count--; len -= 4; buff += 4; } - count >>= 1; /* nr of 64-bit words.. */ + count >>= 1; /* nr of 64-bit words.. */ if (count) { do { - w = *(uint64_t *) buff; + w = *(uint64_t *)buff; count--; buff += 8; result += carry; @@ -71,13 +72,13 @@ static uint16_t do_csum(const uint8_t * buff, size_t len) } if (len & 4) { - result += *(uint32_t *) buff; + result += *(uint32_t *)buff; buff += 4; } } if (len & 2) { - result += *(uint16_t *) buff; + result += *(uint16_t *)buff; buff += 2; } } @@ -85,54 +86,54 @@ static uint16_t do_csum(const uint8_t * buff, size_t len) { // any endian compatible u16 = 0; - *(uint8_t*)&u16 = *buff; + *(uint8_t *)&u16 = *buff; result += u16; } u16 = from64to16(result); - if (odd) u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8); + if (odd) + u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8); return u16; } uint16_t csum_partial(const void *buff, size_t len) { - return do_csum(buff,len); + return do_csum(buff, len); } uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum) { - return ~from64to16((uint64_t)saddr + daddr + sum + htonl(len+proto)); + return ~from64to16((uint64_t)saddr + daddr + sum + htonl(len + proto)); } uint16_t ip4_compute_csum(const void *buff, size_t len) { - return ~from64to16(do_csum(buff,len)); + return ~from64to16(do_csum(buff, len)); } void ip4_fix_checksum(struct ip *ip) { ip->ip_sum = 0; - ip->ip_sum = ip4_compute_csum(ip, ip->ip_hl<<2); + ip->ip_sum = ip4_compute_csum(ip, ip->ip_hl << 2); } uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum) { - uint64_t a = (uint64_t)sum + htonl(len+proto) + - *(uint32_t*)saddr + *((uint32_t*)saddr+1) + *((uint32_t*)saddr+2) + *((uint32_t*)saddr+3) + - *(uint32_t*)daddr + *((uint32_t*)daddr+1) + *((uint32_t*)daddr+2) + *((uint32_t*)daddr+3); + uint64_t a = (uint64_t)sum + htonl(len + proto) + + *(uint32_t *)saddr + *((uint32_t *)saddr + 1) + *((uint32_t *)saddr + 2) + *((uint32_t *)saddr + 3) + + *(uint32_t *)daddr + *((uint32_t *)daddr + 1) + *((uint32_t *)daddr + 2) + *((uint32_t *)daddr + 3); return ~from64to16(a); } - -void tcp4_fix_checksum(struct tcphdr *tcp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr) +void tcp4_fix_checksum(struct tcphdr *tcp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr) { tcp->th_sum = 0; - tcp->th_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_TCP,csum_partial(tcp,len)); + tcp->th_sum = csum_tcpudp_magic(src_addr->s_addr, dest_addr->s_addr, len, IPPROTO_TCP, csum_partial(tcp, len)); } -void tcp6_fix_checksum(struct tcphdr *tcp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr) +void tcp6_fix_checksum(struct tcphdr *tcp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr) { tcp->th_sum = 0; - tcp->th_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp,len)); + tcp->th_sum = csum_ipv6_magic(src_addr, dest_addr, len, IPPROTO_TCP, csum_partial(tcp, len)); } -void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr) +void tcp_fix_checksum(struct tcphdr *tcp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr) { if (ip) tcp4_fix_checksum(tcp, len, &ip->ip_src, &ip->ip_dst); @@ -140,17 +141,17 @@ void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const st tcp6_fix_checksum(tcp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst); } -void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr) +void udp4_fix_checksum(struct udphdr *udp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr) { udp->uh_sum = 0; - udp->uh_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_UDP,csum_partial(udp,len)); + udp->uh_sum = csum_tcpudp_magic(src_addr->s_addr, dest_addr->s_addr, len, IPPROTO_UDP, csum_partial(udp, len)); } -void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr) +void udp6_fix_checksum(struct udphdr *udp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr) { udp->uh_sum = 0; - udp->uh_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_UDP,csum_partial(udp,len)); + udp->uh_sum = csum_ipv6_magic(src_addr, dest_addr, len, IPPROTO_UDP, csum_partial(udp, len)); } -void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr) +void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr) { if (ip) udp4_fix_checksum(udp, len, &ip->ip_src, &ip->ip_dst); diff --git a/nfq/checksum.h b/nfq/checksum.h index c33831e..08f229e 100644 --- a/nfq/checksum.h +++ b/nfq/checksum.h @@ -18,10 +18,10 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8 uint16_t ip4_compute_csum(const void *buff, size_t len); void ip4_fix_checksum(struct ip *ip); -void tcp4_fix_checksum(struct tcphdr *tcp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr); -void tcp6_fix_checksum(struct tcphdr *tcp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr); -void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr); +void tcp4_fix_checksum(struct tcphdr *tcp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr); +void tcp6_fix_checksum(struct tcphdr *tcp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr); +void tcp_fix_checksum(struct tcphdr *tcp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr); -void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr); -void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr); -void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr); +void udp4_fix_checksum(struct udphdr *udp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr); +void udp6_fix_checksum(struct udphdr *udp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr); +void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr); diff --git a/nfq/conntrack.c b/nfq/conntrack.c index 62a79db..221a7f5 100644 --- a/nfq/conntrack.c +++ b/nfq/conntrack.c @@ -12,11 +12,11 @@ static void ut_oom_recover(void *elem) oom = true; } -static const char *connstate_s[]={"SYN","ESTABLISHED","FIN"}; +static const char *connstate_s[] = {"SYN", "ESTABLISHED", "FIN"}; static void connswap(const t_conn *c, t_conn *c2) { - memset(c2,0,sizeof(*c2)); + memset(c2, 0, sizeof(*c2)); c2->l3proto = c->l3proto; c2->l4proto = c->l4proto; c2->src = c->dst; @@ -49,7 +49,11 @@ static void ConntrackFreeElem(t_conntrack_pool *elem) static void ConntrackPoolDestroyPool(t_conntrack_pool **pp) { t_conntrack_pool *elem, *tmp; - HASH_ITER(hh, *pp, elem, tmp) { HASH_DEL(*pp, elem); ConntrackFreeElem(elem); } + HASH_ITER(hh, *pp, elem, tmp) + { + HASH_DEL(*pp, elem); + ConntrackFreeElem(elem); + } } void ConntrackPoolDestroy(t_conntrack *p) { @@ -61,7 +65,7 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s p->timeout_syn = timeout_syn; p->timeout_established = timeout_established; p->timeout_fin = timeout_fin; - p->timeout_udp= timeout_udp; + p->timeout_udp = timeout_udp; p->t_purge_interval = purge_interval; time(&p->t_last_purge); p->pool = NULL; @@ -69,7 +73,7 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s void ConntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr) { - memset(c,0,sizeof(*c)); + memset(c, 0, sizeof(*c)); if (ip) { c->l3proto = IPPROTO_IP; @@ -87,7 +91,6 @@ void ConntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const s extract_ports(tcphdr, udphdr, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport); } - static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *c) { t_conntrack_pool *t; @@ -97,7 +100,7 @@ static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn * static void ConntrackInitTrack(t_ctrack *t) { - memset(t,0,sizeof(*t)); + memset(t, 0, sizeof(*t)); t->scale_orig = t->scale_reply = SCALE_NONE; time(&t->t_start); rawpacket_queue_init(&t->delayed); @@ -111,11 +114,16 @@ static void ConntrackReInitTrack(t_ctrack *t) static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c) { t_conntrack_pool *ctnew; - if (!(ctnew = malloc(sizeof(*ctnew)))) return NULL; + if (!(ctnew = malloc(sizeof(*ctnew)))) + return NULL; ctnew->conn = *c; oom = false; HASH_ADD(hh, *pp, conn, sizeof(*c), ctnew); - if (oom) { free(ctnew); return NULL; } + if (oom) + { + free(ctnew); + return NULL; + } ConntrackInitTrack(&ctnew->track); return ctnew; } @@ -128,38 +136,41 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr if (bReverse) { t->pcounter_reply++; - t->pdcounter_reply+=!!len_payload; - + t->pdcounter_reply += !!len_payload; } else { t->pcounter_orig++; - t->pdcounter_orig+=!!len_payload; + t->pdcounter_orig += !!len_payload; } if (tcphdr) { if (tcp_syn_segment(tcphdr)) { - if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry + if (t->state != SYN) + ConntrackReInitTrack(t); // erase current entry t->seq0 = ntohl(tcphdr->th_seq); } else if (tcp_synack_segment(tcphdr)) { - if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry - if (!t->seq0) t->seq0 = ntohl(tcphdr->th_ack)-1; + if (t->state != SYN) + ConntrackReInitTrack(t); // erase current entry + if (!t->seq0) + t->seq0 = ntohl(tcphdr->th_ack) - 1; t->ack0 = ntohl(tcphdr->th_seq); } - else if (tcphdr->th_flags & (TH_FIN|TH_RST)) + else if (tcphdr->th_flags & (TH_FIN | TH_RST)) { t->state = FIN; } else { - if (t->state==SYN) + if (t->state == SYN) { - t->state=ESTABLISHED; - if (!bReverse && !t->ack0) t->ack0 = ntohl(tcphdr->th_ack)-1; + t->state = ESTABLISHED; + if (!bReverse && !t->ack0) + t->ack0 = ntohl(tcphdr->th_ack) - 1; } } scale = tcp_find_scale_factor(tcphdr); @@ -169,8 +180,8 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr t->ack_last = ntohl(tcphdr->th_seq); t->pos_reply = t->ack_last + len_payload; t->winsize_reply = ntohs(tcphdr->th_win); - if (scale!=SCALE_NONE) t->scale_reply = scale; - + if (scale != SCALE_NONE) + t->scale_reply = scale; } else { @@ -178,20 +189,21 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr t->pos_orig = t->seq_last + len_payload; t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack); t->winsize_orig = ntohs(tcphdr->th_win); - if (scale!=SCALE_NONE) t->scale_orig = scale; + if (scale != SCALE_NONE) + t->scale_orig = scale; } } else { if (bReverse) { - t->ack_last=t->pos_reply; - t->pos_reply+=len_payload; + t->ack_last = t->pos_reply; + t->pos_reply += len_payload; } else { - t->seq_last=t->pos_orig; - t->pos_orig+=len_payload; + t->seq_last = t->pos_orig; + t->pos_orig += len_payload; } } @@ -200,23 +212,27 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, t_ctrack **ctrack, bool *bReverse) { - t_conn conn,connswp; + t_conn conn, connswp; t_conntrack_pool *ctr; - ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr); - if ((ctr=ConntrackPoolSearch(*pp,&conn))) + ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr); + if ((ctr = ConntrackPoolSearch(*pp, &conn))) { - if (bReverse) *bReverse = false; - if (ctrack) *ctrack = &ctr->track; + if (bReverse) + *bReverse = false; + if (ctrack) + *ctrack = &ctr->track; return true; } else { - connswap(&conn,&connswp); - if ((ctr=ConntrackPoolSearch(*pp,&connswp))) + connswap(&conn, &connswp); + if ((ctr = ConntrackPoolSearch(*pp, &connswp))) { - if (bReverse) *bReverse = true; - if (ctrack) *ctrack = &ctr->track; + if (bReverse) + *bReverse = true; + if (ctrack) + *ctrack = &ctr->track; return true; } } @@ -233,25 +249,25 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co t_conntrack_pool *ctr; bool b_rev; - ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr); - if ((ctr=ConntrackPoolSearch(*pp,&conn))) + ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr); + if ((ctr = ConntrackPoolSearch(*pp, &conn))) { - ConntrackFeedPacket(&ctr->track, (b_rev=false), tcphdr, len_payload); + ConntrackFeedPacket(&ctr->track, (b_rev = false), tcphdr, len_payload); goto ok; } else { - connswap(&conn,&connswp); - if ((ctr=ConntrackPoolSearch(*pp,&connswp))) + connswap(&conn, &connswp); + if ((ctr = ConntrackPoolSearch(*pp, &connswp))) { - ConntrackFeedPacket(&ctr->track, (b_rev=true), tcphdr, len_payload); + ConntrackFeedPacket(&ctr->track, (b_rev = true), tcphdr, len_payload); goto ok; } } b_rev = tcphdr && tcp_synack_segment(tcphdr); if ((tcphdr && tcp_syn_segment(tcphdr)) || b_rev || udphdr) { - if ((ctr=ConntrackNew(pp, b_rev ? &connswp : &conn))) + if ((ctr = ConntrackNew(pp, b_rev ? &connswp : &conn))) { ConntrackFeedPacket(&ctr->track, b_rev, tcphdr, len_payload); goto ok; @@ -259,32 +275,36 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co } return false; ok: - if (ctrack) *ctrack = &ctr->track; - if (bReverse) *bReverse = b_rev; + if (ctrack) + *ctrack = &ctr->track; + if (bReverse) + *bReverse = b_rev; return true; } bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse) { - return ConntrackPoolFeedPool(&p->pool,ip,ip6,tcphdr,udphdr,len_payload,ctrack,bReverse); + return ConntrackPoolFeedPool(&p->pool, ip, ip6, tcphdr, udphdr, len_payload, ctrack, bReverse); } static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr) { t_conn conn, connswp; t_conntrack_pool *t; - ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr); - if (!(t=ConntrackPoolSearch(*pp,&conn))) + ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr); + if (!(t = ConntrackPoolSearch(*pp, &conn))) { - connswap(&conn,&connswp); - t=ConntrackPoolSearch(*pp,&connswp); + connswap(&conn, &connswp); + t = ConntrackPoolSearch(*pp, &connswp); } - if (!t) return false; - HASH_DEL(*pp, t); ConntrackFreeElem(t); + if (!t) + return false; + HASH_DEL(*pp, t); + ConntrackFreeElem(t); return true; } bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr) { - return ConntrackPoolDropPool(&p->pool,ip,ip6,tcphdr,udphdr); + return ConntrackPoolDropPool(&p->pool, ip, ip6, tcphdr, udphdr); } void ConntrackPoolPurge(t_conntrack *p) @@ -292,19 +312,19 @@ void ConntrackPoolPurge(t_conntrack *p) time_t tidle, tnow = time(NULL); t_conntrack_pool *t, *tmp; - if ((tnow - p->t_last_purge)>=p->t_purge_interval) + if ((tnow - p->t_last_purge) >= p->t_purge_interval) { - HASH_ITER(hh, p->pool , t, tmp) { + HASH_ITER(hh, p->pool, t, tmp) + { tidle = tnow - t->track.t_last; - if ( t->track.b_cutoff || - (t->conn.l4proto==IPPROTO_TCP && ( - (t->track.state==SYN && tidle>=p->timeout_syn) || - (t->track.state==ESTABLISHED && tidle>=p->timeout_established) || - (t->track.state==FIN && tidle>=p->timeout_fin)) - ) || (t->conn.l4proto==IPPROTO_UDP && tidle>=p->timeout_udp) - ) + if (t->track.b_cutoff || + (t->conn.l4proto == IPPROTO_TCP && ((t->track.state == SYN && tidle >= p->timeout_syn) || + (t->track.state == ESTABLISHED && tidle >= p->timeout_established) || + (t->track.state == FIN && tidle >= p->timeout_fin))) || + (t->conn.l4proto == IPPROTO_UDP && tidle >= p->timeout_udp)) { - HASH_DEL(p->pool, t); ConntrackFreeElem(t); + HASH_DEL(p->pool, t); + ConntrackFreeElem(t); } } p->t_last_purge = tnow; @@ -313,52 +333,59 @@ void ConntrackPoolPurge(t_conntrack *p) static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsize) { - if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize) *buf=0; + if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize) + *buf = 0; } static const char *ConntrackProtoName(t_l7proto proto) { - switch(proto) + switch (proto) { - case HTTP: return "HTTP"; - case TLS: return "TLS"; - case QUIC: return "QUIC"; - case WIREGUARD: return "WIREGUARD"; - case DHT: return "DHT"; - default: return "UNKNOWN"; + case HTTP: + return "HTTP"; + case TLS: + return "TLS"; + case QUIC: + return "QUIC"; + case WIREGUARD: + return "WIREGUARD"; + case DHT: + return "DHT"; + default: + return "UNKNOWN"; } } void ConntrackPoolDump(const t_conntrack *p) { t_conntrack_pool *t, *tmp; - char sa1[40],sa2[40]; + char sa1[40], sa2[40]; time_t tnow = time(NULL); - HASH_ITER(hh, p->pool, t, tmp) { + HASH_ITER(hh, p->pool, t, tmp) + { taddr2str(t->conn.l3proto, &t->conn.src, sa1, sizeof(sa1)); taddr2str(t->conn.l3proto, &t->conn.dst, sa2, sizeof(sa2)); printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu packets_orig=d%llu/n%llu packets_reply=d%llu/n%llu ", - proto_name(t->conn.l4proto), - sa1, t->conn.sport, sa2, t->conn.dport, - t->conn.l4proto==IPPROTO_TCP ? connstate_s[t->track.state] : "-", - (unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last), - (unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig, - (unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply); - if (t->conn.l4proto==IPPROTO_TCP) + proto_name(t->conn.l4proto), + sa1, t->conn.sport, sa2, t->conn.dport, + t->conn.l4proto == IPPROTO_TCP ? connstate_s[t->track.state] : "-", + (unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last), + (unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig, + (unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply); + if (t->conn.l4proto == IPPROTO_TCP) printf("seq0=%u rseq=%u pos_orig=%u ack0=%u rack=%u pos_reply=%u wsize_orig=%u:%d wsize_reply=%u:%d", - t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0, - t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0, - t->track.winsize_orig, t->track.scale_orig==SCALE_NONE ? -1 : t->track.scale_orig, - t->track.winsize_reply, t->track.scale_reply==SCALE_NONE ? -1 : t->track.scale_reply); + t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0, + t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0, + t->track.winsize_orig, t->track.scale_orig == SCALE_NONE ? -1 : t->track.scale_orig, + t->track.winsize_reply, t->track.scale_reply == SCALE_NONE ? -1 : t->track.scale_reply); else printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u", - t->track.seq_last, t->track.pos_orig, - t->track.ack_last, t->track.pos_reply); + t->track.seq_last, t->track.pos_orig, + t->track.ack_last, t->track.pos_reply); printf(" req_retrans=%u cutoff=%u wss_cutoff=%u d_cutoff=%u hostname=%s l7proto=%s\n", - t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, ConntrackProtoName(t->track.l7proto)); + t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, ConntrackProtoName(t->track.l7proto)); }; } - void ReasmClear(t_reassemble *reasm) { if (reasm->packet) @@ -371,7 +398,8 @@ void ReasmClear(t_reassemble *reasm) bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start) { reasm->packet = malloc(size_requested); - if (!reasm->packet) return false; + if (!reasm->packet) + return false; reasm->size = size_requested; reasm->size_present = 0; reasm->seq = seq_start; @@ -380,19 +408,23 @@ bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start) bool ReasmResize(t_reassemble *reasm, size_t new_size) { uint8_t *p = realloc(reasm->packet, new_size); - if (!p) return false; + if (!p) + return false; reasm->packet = p; reasm->size = new_size; - if (reasm->size_present > new_size) reasm->size_present = new_size; + if (reasm->size_present > new_size) + reasm->size_present = new_size; return true; } bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len) { - if (reasm->seq!=seq) return false; // fail session if out of sequence - + if (reasm->seq != seq) + return false; // fail session if out of sequence + size_t szcopy; szcopy = reasm->size - reasm->size_present; - if (lenpacket + reasm->size_present, payload, szcopy); reasm->size_present += szcopy; reasm->seq += (uint32_t)szcopy; @@ -401,5 +433,5 @@ bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t le } bool ReasmHasSpace(t_reassemble *reasm, size_t len) { - return (reasm->size_present+len)<=reasm->size; + return (reasm->size_present + len) <= reasm->size; } diff --git a/nfq/conntrack.h b/nfq/conntrack.h index 6b05da3..d542f11 100644 --- a/nfq/conntrack.h +++ b/nfq/conntrack.h @@ -1,6 +1,5 @@ #pragma once - // this conntrack is not bullet-proof // its designed to satisfy dpi desync needs only @@ -19,68 +18,82 @@ #include #include - -//#define HASH_BLOOM 20 +// #define HASH_BLOOM 20 #define HASH_NONFATAL_OOM 1 #undef HASH_FUNCTION #define HASH_FUNCTION HASH_BER #include "uthash.h" -#define RETRANS_COUNTER_STOP ((uint8_t)-1) +#define RETRANS_COUNTER_STOP ((uint8_t) - 1) -typedef union { +typedef union +{ struct in_addr ip; struct in6_addr ip6; } t_addr; typedef struct { t_addr src, dst; - uint16_t sport,dport; - uint8_t l3proto; // IPPROTO_IP, IPPROTO_IPV6 + uint16_t sport, dport; + uint8_t l3proto; // IPPROTO_IP, IPPROTO_IPV6 uint8_t l4proto; // IPPROTO_TCP, IPPROTO_UDP } t_conn; // this structure helps to reassemble continuous packets streams. it does not support out-of-orders -typedef struct { - uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size. - uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session. - size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet' - size_t size_present; // how many bytes already stored in 'packet' +typedef struct +{ + uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size. + uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session. + size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet' + size_t size_present; // how many bytes already stored in 'packet' } t_reassemble; // SYN - SYN or SYN/ACK received // ESTABLISHED - any except SYN or SYN/ACK received // FIN - FIN or RST received -typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate; -typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto; +typedef enum +{ + SYN = 0, + ESTABLISHED, + FIN +} t_connstate; +typedef enum +{ + UNKNOWN = 0, + HTTP, + TLS, + QUIC, + WIREGUARD, + DHT +} t_l7proto; typedef struct { // common state time_t t_start, t_last; - uint64_t pcounter_orig, pcounter_reply; // packet counter + uint64_t pcounter_orig, pcounter_reply; // packet counter uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload) - uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current - uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current + uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current + uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current // tcp only state, not used in udp t_connstate state; - uint32_t seq0, ack0; // starting seq and ack - uint16_t winsize_orig, winsize_reply; // last seen window size - uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none - - uint8_t req_retrans_counter; // number of request retransmissions - bool req_seq_present,req_seq_finalized,req_seq_abandoned; - uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions) + uint32_t seq0, ack0; // starting seq and ack + uint16_t winsize_orig, winsize_reply; // last seen window size + uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none + + uint8_t req_retrans_counter; // number of request retransmissions + bool req_seq_present, req_seq_finalized, req_seq_abandoned; + uint32_t req_seq_start, req_seq_end; // sequence interval of the request (to track retransmissions) uint8_t autottl; - bool b_cutoff; // mark for deletion + bool b_cutoff; // mark for deletion bool b_wssize_cutoff, b_desync_cutoff; t_l7proto l7proto; char *hostname; - bool hostname_ah_check; // should perform autohostlist checks - + bool hostname_ah_check; // should perform autohostlist checks + t_reassemble reasm_orig; struct rawpacket_tailhead delayed; } t_ctrack; @@ -88,13 +101,13 @@ typedef struct typedef struct { t_ctrack track; - UT_hash_handle hh; // makes this structure hashable - t_conn conn; // key + UT_hash_handle hh; // makes this structure hashable + t_conn conn; // key } t_conntrack_pool; typedef struct { // inactivity time to purge an entry in each connection state - uint32_t timeout_syn,timeout_established,timeout_fin,timeout_udp; + uint32_t timeout_syn, timeout_established, timeout_fin, timeout_udp; time_t t_purge_interval, t_last_purge; t_conntrack_pool *pool; } t_conntrack; @@ -117,5 +130,5 @@ void ReasmClear(t_reassemble *reasm); bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len); // check if it has enough space to buffer 'len' bytes bool ReasmHasSpace(t_reassemble *reasm, size_t len); -inline static bool ReasmIsEmpty(t_reassemble *reasm) {return !reasm->size;} -inline static bool ReasmIsFull(t_reassemble *reasm) {return !ReasmIsEmpty(reasm) && (reasm->size==reasm->size_present);} +inline static bool ReasmIsEmpty(t_reassemble *reasm) { return !reasm->size; } +inline static bool ReasmIsFull(t_reassemble *reasm) { return !ReasmIsEmpty(reasm) && (reasm->size == reasm->size_present); } diff --git a/nfq/crypto/aes-gcm.h b/nfq/crypto/aes-gcm.h index d836001..b788524 100644 --- a/nfq/crypto/aes-gcm.h +++ b/nfq/crypto/aes-gcm.h @@ -1,6 +1,6 @@ #pragma once -#include "gcm.h" +#include "gcm.h" // mode : AES_ENCRYPT, AES_DECRYPT int aes_gcm_crypt(int mode, uint8_t *output, const uint8_t *input, size_t input_length, const uint8_t *key, const size_t key_len, const uint8_t *iv, const size_t iv_len, const uint8_t *adata, size_t adata_len, uint8_t *atag, size_t atag_len); diff --git a/nfq/crypto/aes.c b/nfq/crypto/aes.c index 1ce55ef..01e2514 100644 --- a/nfq/crypto/aes.c +++ b/nfq/crypto/aes.c @@ -1,29 +1,29 @@ /****************************************************************************** -* -* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL -* -* This is a simple and straightforward implementation of the AES Rijndael -* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus -* of this work was correctness & accuracy. It is written in 'C' without any -* particular focus upon optimization or speed. It should be endian (memory -* byte order) neutral since the few places that care are handled explicitly. -* -* This implementation of Rijndael was created by Steven M. Gibson of GRC.com. -* -* It is intended for general purpose use, but was written in support of GRC's -* reference implementation of the SQRL (Secure Quick Reliable Login) client. -* -* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html -* -* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE -* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. -* -*******************************************************************************/ + * + * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL + * + * This is a simple and straightforward implementation of the AES Rijndael + * 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus + * of this work was correctness & accuracy. It is written in 'C' without any + * particular focus upon optimization or speed. It should be endian (memory + * byte order) neutral since the few places that care are handled explicitly. + * + * This implementation of Rijndael was created by Steven M. Gibson of GRC.com. + * + * It is intended for general purpose use, but was written in support of GRC's + * reference implementation of the SQRL (Secure Quick Reliable Login) client. + * + * See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html + * + * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE + * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. + * + *******************************************************************************/ #include "aes.h" -static int aes_tables_inited = 0; // run-once flag for performing key - // expasion table generation (see below) +static int aes_tables_inited = 0; // run-once flag for performing key + // expasion table generation (see below) /* * The following static local tables must be filled-in before the first use of * the GCM or AES ciphers. They are used for the AES key expansion/scheduling @@ -37,175 +37,189 @@ static int aes_tables_inited = 0; // run-once flag for performing key * the GCM input, we ONLY NEED AES encryption. Thus, to save space AES * decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h. */ - // We always need our forward tables -static uchar FSb[256]; // Forward substitution box (FSb) -static uint32_t FT0[256]; // Forward key schedule assembly tables +// We always need our forward tables +static uchar FSb[256]; // Forward substitution box (FSb) +static uint32_t FT0[256]; // Forward key schedule assembly tables static uint32_t FT1[256]; static uint32_t FT2[256]; static uint32_t FT3[256]; -#if AES_DECRYPTION // We ONLY need reverse for decryption -static uchar RSb[256]; // Reverse substitution box (RSb) -static uint32_t RT0[256]; // Reverse key schedule assembly tables +#if AES_DECRYPTION // We ONLY need reverse for decryption +static uchar RSb[256]; // Reverse substitution box (RSb) +static uint32_t RT0[256]; // Reverse key schedule assembly tables static uint32_t RT1[256]; static uint32_t RT2[256]; static uint32_t RT3[256]; -#endif /* AES_DECRYPTION */ +#endif /* AES_DECRYPTION */ -static uint32_t RCON[10]; // AES round constants +static uint32_t RCON[10]; // AES round constants /* * Platform Endianness Neutralizing Load and Store Macro definitions * AES wants platform-neutral Little Endian (LE) byte ordering */ -#define GET_UINT32_LE(n,b,i) { \ - (n) = ( (uint32_t) (b)[(i) ] ) \ - | ( (uint32_t) (b)[(i) + 1] << 8 ) \ - | ( (uint32_t) (b)[(i) + 2] << 16 ) \ - | ( (uint32_t) (b)[(i) + 3] << 24 ); } +#define GET_UINT32_LE(n, b, i) \ + { \ + (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \ + } -#define PUT_UINT32_LE(n,b,i) { \ - (b)[(i) ] = (uchar) ( (n) ); \ - (b)[(i) + 1] = (uchar) ( (n) >> 8 ); \ - (b)[(i) + 2] = (uchar) ( (n) >> 16 ); \ - (b)[(i) + 3] = (uchar) ( (n) >> 24 ); } +#define PUT_UINT32_LE(n, b, i) \ + { \ + (b)[(i)] = (uchar)((n)); \ + (b)[(i) + 1] = (uchar)((n) >> 8); \ + (b)[(i) + 2] = (uchar)((n) >> 16); \ + (b)[(i) + 3] = (uchar)((n) >> 24); \ + } - /* - * AES forward and reverse encryption round processing macros - */ -#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ - FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ - FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y0 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ - FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ - FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y2 >> 24 ) & 0xFF ]; \ -} +/* + * AES forward and reverse encryption round processing macros + */ +#define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + { \ + X0 = *RK++ ^ FT0[(Y0) & 0xFF] ^ \ + FT1[(Y1 >> 8) & 0xFF] ^ \ + FT2[(Y2 >> 16) & 0xFF] ^ \ + FT3[(Y3 >> 24) & 0xFF]; \ + \ + X1 = *RK++ ^ FT0[(Y1) & 0xFF] ^ \ + FT1[(Y2 >> 8) & 0xFF] ^ \ + FT2[(Y3 >> 16) & 0xFF] ^ \ + FT3[(Y0 >> 24) & 0xFF]; \ + \ + X2 = *RK++ ^ FT0[(Y2) & 0xFF] ^ \ + FT1[(Y3 >> 8) & 0xFF] ^ \ + FT2[(Y0 >> 16) & 0xFF] ^ \ + FT3[(Y1 >> 24) & 0xFF]; \ + \ + X3 = *RK++ ^ FT0[(Y3) & 0xFF] ^ \ + FT1[(Y0 >> 8) & 0xFF] ^ \ + FT2[(Y1 >> 16) & 0xFF] ^ \ + FT3[(Y2 >> 24) & 0xFF]; \ + } -#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ - RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ - RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y2 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ - RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ - RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y0 >> 24 ) & 0xFF ]; \ -} +#define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + { \ + X0 = *RK++ ^ RT0[(Y0) & 0xFF] ^ \ + RT1[(Y3 >> 8) & 0xFF] ^ \ + RT2[(Y2 >> 16) & 0xFF] ^ \ + RT3[(Y1 >> 24) & 0xFF]; \ + \ + X1 = *RK++ ^ RT0[(Y1) & 0xFF] ^ \ + RT1[(Y0 >> 8) & 0xFF] ^ \ + RT2[(Y3 >> 16) & 0xFF] ^ \ + RT3[(Y2 >> 24) & 0xFF]; \ + \ + X2 = *RK++ ^ RT0[(Y2) & 0xFF] ^ \ + RT1[(Y1 >> 8) & 0xFF] ^ \ + RT2[(Y0 >> 16) & 0xFF] ^ \ + RT3[(Y3 >> 24) & 0xFF]; \ + \ + X3 = *RK++ ^ RT0[(Y3) & 0xFF] ^ \ + RT1[(Y2 >> 8) & 0xFF] ^ \ + RT2[(Y1 >> 16) & 0xFF] ^ \ + RT3[(Y0 >> 24) & 0xFF]; \ + } - /* - * These macros improve the readability of the key - * generation initialization code by collapsing - * repetitive common operations into logical pieces. - */ -#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) -#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) -#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) -#define MIX(x,y) { y = ( (y << 1) | (y >> 7) ) & 0xFF; x ^= y; } -#define CPY128 { *RK++ = *SK++; *RK++ = *SK++; \ - *RK++ = *SK++; *RK++ = *SK++; } +/* + * These macros improve the readability of the key + * generation initialization code by collapsing + * repetitive common operations into logical pieces. + */ +#define ROTL8(x) ((x << 8) & 0xFFFFFFFF) | (x >> 24) +#define XTIME(x) ((x << 1) ^ ((x & 0x80) ? 0x1B : 0x00)) +#define MUL(x, y) ((x && y) ? pow[(log[x] + log[y]) % 255] : 0) +#define MIX(x, y) \ + { \ + y = ((y << 1) | (y >> 7)) & 0xFF; \ + x ^= y; \ + } +#define CPY128 \ + { \ + *RK++ = *SK++; \ + *RK++ = *SK++; \ + *RK++ = *SK++; \ + *RK++ = *SK++; \ + } - /****************************************************************************** - * - * AES_INIT_KEYGEN_TABLES - * - * Fills the AES key expansion tables allocated above with their static - * data. This is not "per key" data, but static system-wide read-only - * table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once - * at system initialization to setup the tables for all subsequent use. - * - ******************************************************************************/ +/****************************************************************************** + * + * AES_INIT_KEYGEN_TABLES + * + * Fills the AES key expansion tables allocated above with their static + * data. This is not "per key" data, but static system-wide read-only + * table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once + * at system initialization to setup the tables for all subsequent use. + * + ******************************************************************************/ void aes_init_keygen_tables(void) { - int i, x, y, z; // general purpose iteration and computation locals + int i, x, y, z; // general purpose iteration and computation locals int pow[256]; int log[256]; - if (aes_tables_inited) return; + if (aes_tables_inited) + return; // fill the 'pow' and 'log' tables over GF(2^8) - for (i = 0, x = 1; i < 256; i++) { + for (i = 0, x = 1; i < 256; i++) + { pow[i] = x; log[x] = i; x = (x ^ XTIME(x)) & 0xFF; } // compute the round constants - for (i = 0, x = 1; i < 10; i++) { + for (i = 0, x = 1; i < 10; i++) + { RCON[i] = (uint32_t)x; x = XTIME(x) & 0xFF; } // fill the forward and reverse substitution boxes FSb[0x00] = 0x63; -#if AES_DECRYPTION // whether AES decryption is supported +#if AES_DECRYPTION // whether AES decryption is supported RSb[0x63] = 0x00; #endif /* AES_DECRYPTION */ - for (i = 1; i < 256; i++) { + for (i = 1; i < 256; i++) + { x = y = pow[255 - log[i]]; MIX(x, y); MIX(x, y); MIX(x, y); MIX(x, y); FSb[i] = (uchar)(x ^= 0x63); -#if AES_DECRYPTION // whether AES decryption is supported +#if AES_DECRYPTION // whether AES decryption is supported RSb[x] = (uchar)i; #endif /* AES_DECRYPTION */ - } // generate the forward and reverse key expansion tables - for (i = 0; i < 256; i++) { + for (i = 0; i < 256; i++) + { x = FSb[i]; y = XTIME(x) & 0xFF; z = (y ^ x) & 0xFF; FT0[i] = ((uint32_t)y) ^ ((uint32_t)x << 8) ^ - ((uint32_t)x << 16) ^ ((uint32_t)z << 24); + ((uint32_t)x << 16) ^ ((uint32_t)z << 24); FT1[i] = ROTL8(FT0[i]); FT2[i] = ROTL8(FT1[i]); FT3[i] = ROTL8(FT2[i]); -#if AES_DECRYPTION // whether AES decryption is supported +#if AES_DECRYPTION // whether AES decryption is supported x = RSb[i]; RT0[i] = ((uint32_t)MUL(0x0E, x)) ^ - ((uint32_t)MUL(0x09, x) << 8) ^ - ((uint32_t)MUL(0x0D, x) << 16) ^ - ((uint32_t)MUL(0x0B, x) << 24); + ((uint32_t)MUL(0x09, x) << 8) ^ + ((uint32_t)MUL(0x0D, x) << 16) ^ + ((uint32_t)MUL(0x0B, x) << 24); RT1[i] = ROTL8(RT0[i]); RT2[i] = ROTL8(RT1[i]); RT3[i] = ROTL8(RT2[i]); #endif /* AES_DECRYPTION */ } - aes_tables_inited = 1; // flag that the tables have been generated -} // to permit subsequent use of the AES cipher + aes_tables_inited = 1; // flag that the tables have been generated +} // to permit subsequent use of the AES cipher /****************************************************************************** * @@ -218,25 +232,27 @@ void aes_init_keygen_tables(void) * ******************************************************************************/ int aes_set_encryption_key(aes_context *ctx, - const uchar *key, - uint keysize) + const uchar *key, + uint keysize) { - uint i; // general purpose iteration local + uint i; // general purpose iteration local uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer - for (i = 0; i < (keysize >> 2); i++) { + for (i = 0; i < (keysize >> 2); i++) + { GET_UINT32_LE(RK[i], key, i << 2); } switch (ctx->rounds) { case 10: - for (i = 0; i < 10; i++, RK += 4) { + for (i = 0; i < 10; i++, RK += 4) + { RK[4] = RK[0] ^ RCON[i] ^ - ((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^ - ((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^ - ((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^ - ((uint32_t)FSb[(RK[3]) & 0xFF] << 24); + ((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^ + ((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^ + ((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^ + ((uint32_t)FSb[(RK[3]) & 0xFF] << 24); RK[5] = RK[1] ^ RK[4]; RK[6] = RK[2] ^ RK[5]; @@ -245,12 +261,13 @@ int aes_set_encryption_key(aes_context *ctx, break; case 12: - for (i = 0; i < 8; i++, RK += 6) { + for (i = 0; i < 8; i++, RK += 6) + { RK[6] = RK[0] ^ RCON[i] ^ - ((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^ - ((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^ - ((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^ - ((uint32_t)FSb[(RK[5]) & 0xFF] << 24); + ((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^ + ((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^ + ((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^ + ((uint32_t)FSb[(RK[5]) & 0xFF] << 24); RK[7] = RK[1] ^ RK[6]; RK[8] = RK[2] ^ RK[7]; @@ -261,22 +278,23 @@ int aes_set_encryption_key(aes_context *ctx, break; case 14: - for (i = 0; i < 7; i++, RK += 8) { + for (i = 0; i < 7; i++, RK += 8) + { RK[8] = RK[0] ^ RCON[i] ^ - ((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^ - ((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^ - ((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^ - ((uint32_t)FSb[(RK[7]) & 0xFF] << 24); + ((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^ + ((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^ + ((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^ + ((uint32_t)FSb[(RK[7]) & 0xFF] << 24); RK[9] = RK[1] ^ RK[8]; RK[10] = RK[2] ^ RK[9]; RK[11] = RK[3] ^ RK[10]; RK[12] = RK[4] ^ - ((uint32_t)FSb[(RK[11]) & 0xFF]) ^ - ((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^ - ((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^ - ((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24); + ((uint32_t)FSb[(RK[11]) & 0xFF]) ^ + ((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^ + ((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24); RK[13] = RK[5] ^ RK[12]; RK[14] = RK[6] ^ RK[13]; @@ -287,10 +305,10 @@ int aes_set_encryption_key(aes_context *ctx, default: return -1; } - return(0); + return (0); } -#if AES_DECRYPTION // whether AES decryption is supported +#if AES_DECRYPTION // whether AES decryption is supported /****************************************************************************** * @@ -303,36 +321,38 @@ int aes_set_encryption_key(aes_context *ctx, * ******************************************************************************/ int aes_set_decryption_key(aes_context *ctx, - const uchar *key, - uint keysize) + const uchar *key, + uint keysize) { int i, j; - aes_context cty; // a calling aes context for set_encryption_key - uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer + aes_context cty; // a calling aes context for set_encryption_key + uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer uint32_t *SK; int ret; - cty.rounds = ctx->rounds; // initialize our local aes context - cty.rk = cty.buf; // round count and key buf pointer + cty.rounds = ctx->rounds; // initialize our local aes context + cty.rk = cty.buf; // round count and key buf pointer if ((ret = aes_set_encryption_key(&cty, key, keysize)) != 0) - return(ret); + return (ret); SK = cty.rk + cty.rounds * 4; - CPY128 // copy a 128-bit block from *SK to *RK + CPY128 // copy a 128-bit block from *SK to *RK - for (i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8) { - for (j = 0; j < 4; j++, SK++) { - *RK++ = RT0[FSb[(*SK) & 0xFF]] ^ + for (i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8) + { + for (j = 0; j < 4; j++, SK++) + { + *RK++ = RT0[FSb[(*SK) & 0xFF]] ^ RT1[FSb[(*SK >> 8) & 0xFF]] ^ RT2[FSb[(*SK >> 16) & 0xFF]] ^ RT3[FSb[(*SK >> 24) & 0xFF]]; - } } - CPY128 // copy a 128-bit block from *SK to *RK - memset(&cty, 0, sizeof(aes_context)); // clear local aes context - return(0); + } + CPY128 // copy a 128-bit block from *SK to *RK + memset(&cty, 0, sizeof(aes_context)); // clear local aes context + return (0); } #endif /* AES_DECRYPTION */ @@ -344,34 +364,42 @@ int aes_set_decryption_key(aes_context *ctx, * Invoked to establish the key schedule for subsequent encryption/decryption * ******************************************************************************/ -int aes_setkey(aes_context *ctx, // AES context provided by our caller - int mode, // ENCRYPT or DECRYPT flag - const uchar *key, // pointer to the key - uint keysize) // key length in bytes +int aes_setkey(aes_context *ctx, // AES context provided by our caller + int mode, // ENCRYPT or DECRYPT flag + const uchar *key, // pointer to the key + uint keysize) // key length in bytes { // since table initialization is not thread safe, we could either add // system-specific mutexes and init the AES key generation tables on // demand, or ask the developer to simply call "gcm_initialize" once during // application startup before threading begins. That's what we choose. - if (!aes_tables_inited) return (-1); // fail the call when not inited. + if (!aes_tables_inited) + return (-1); // fail the call when not inited. - ctx->mode = mode; // capture the key type we're creating - ctx->rk = ctx->buf; // initialize our round key pointer + ctx->mode = mode; // capture the key type we're creating + ctx->rk = ctx->buf; // initialize our round key pointer - switch (keysize) // set the rounds count based upon the keysize + switch (keysize) // set the rounds count based upon the keysize { - case 16: ctx->rounds = 10; break; // 16-byte, 128-bit key - case 24: ctx->rounds = 12; break; // 24-byte, 192-bit key - case 32: ctx->rounds = 14; break; // 32-byte, 256-bit key - default: return(-1); + case 16: + ctx->rounds = 10; + break; // 16-byte, 128-bit key + case 24: + ctx->rounds = 12; + break; // 24-byte, 192-bit key + case 32: + ctx->rounds = 14; + break; // 32-byte, 256-bit key + default: + return (-1); } #if AES_DECRYPTION - if (mode == DECRYPT) // expand our key for encryption or decryption - return(aes_set_decryption_key(ctx, key, keysize)); - else /* ENCRYPT */ -#endif /* AES_DECRYPTION */ - return(aes_set_encryption_key(ctx, key, keysize)); + if (mode == DECRYPT) // expand our key for encryption or decryption + return (aes_set_decryption_key(ctx, key, keysize)); + else /* ENCRYPT */ +#endif /* AES_DECRYPTION */ + return (aes_set_encryption_key(ctx, key, keysize)); } /****************************************************************************** @@ -384,20 +412,24 @@ int aes_setkey(aes_context *ctx, // AES context provided by our caller * ******************************************************************************/ int aes_cipher(aes_context *ctx, - const uchar input[16], - uchar output[16]) + const uchar input[16], + uchar output[16]) { int i; - uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals RK = ctx->rk; - GET_UINT32_LE(X0, input, 0); X0 ^= *RK++; // load our 128-bit - GET_UINT32_LE(X1, input, 4); X1 ^= *RK++; // input buffer in a storage - GET_UINT32_LE(X2, input, 8); X2 ^= *RK++; // memory endian-neutral way - GET_UINT32_LE(X3, input, 12); X3 ^= *RK++; + GET_UINT32_LE(X0, input, 0); + X0 ^= *RK++; // load our 128-bit + GET_UINT32_LE(X1, input, 4); + X1 ^= *RK++; // input buffer in a storage + GET_UINT32_LE(X2, input, 8); + X2 ^= *RK++; // memory endian-neutral way + GET_UINT32_LE(X3, input, 12); + X3 ^= *RK++; -#if AES_DECRYPTION // whether AES decryption is supported +#if AES_DECRYPTION // whether AES decryption is supported if (ctx->mode == DECRYPT) { @@ -409,29 +441,29 @@ int aes_cipher(aes_context *ctx, AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); - X0 = *RK++ ^ \ - ((uint32_t)RSb[(Y0) & 0xFF]) ^ - ((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^ - ((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^ - ((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24); + X0 = *RK++ ^ + ((uint32_t)RSb[(Y0) & 0xFF]) ^ + ((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^ + ((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^ + ((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24); - X1 = *RK++ ^ \ - ((uint32_t)RSb[(Y1) & 0xFF]) ^ - ((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^ - ((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^ - ((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24); + X1 = *RK++ ^ + ((uint32_t)RSb[(Y1) & 0xFF]) ^ + ((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^ + ((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^ + ((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24); - X2 = *RK++ ^ \ - ((uint32_t)RSb[(Y2) & 0xFF]) ^ - ((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^ - ((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^ - ((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24); + X2 = *RK++ ^ + ((uint32_t)RSb[(Y2) & 0xFF]) ^ + ((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^ + ((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^ + ((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24); - X3 = *RK++ ^ \ - ((uint32_t)RSb[(Y3) & 0xFF]) ^ - ((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^ - ((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^ - ((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24); + X3 = *RK++ ^ + ((uint32_t)RSb[(Y3) & 0xFF]) ^ + ((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^ + ((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^ + ((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24); } else /* ENCRYPT */ { @@ -445,31 +477,31 @@ int aes_cipher(aes_context *ctx, AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); - X0 = *RK++ ^ \ - ((uint32_t)FSb[(Y0) & 0xFF]) ^ - ((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^ - ((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^ - ((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24); + X0 = *RK++ ^ + ((uint32_t)FSb[(Y0) & 0xFF]) ^ + ((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^ + ((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24); - X1 = *RK++ ^ \ - ((uint32_t)FSb[(Y1) & 0xFF]) ^ - ((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^ - ((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^ - ((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24); + X1 = *RK++ ^ + ((uint32_t)FSb[(Y1) & 0xFF]) ^ + ((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^ + ((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24); - X2 = *RK++ ^ \ - ((uint32_t)FSb[(Y2) & 0xFF]) ^ - ((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^ - ((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^ - ((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24); + X2 = *RK++ ^ + ((uint32_t)FSb[(Y2) & 0xFF]) ^ + ((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^ + ((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24); - X3 = *RK++ ^ \ - ((uint32_t)FSb[(Y3) & 0xFF]) ^ - ((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^ - ((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^ - ((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24); + X3 = *RK++ ^ + ((uint32_t)FSb[(Y3) & 0xFF]) ^ + ((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^ + ((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24); -#if AES_DECRYPTION // whether AES decryption is supported +#if AES_DECRYPTION // whether AES decryption is supported } #endif /* AES_DECRYPTION */ @@ -478,6 +510,6 @@ int aes_cipher(aes_context *ctx, PUT_UINT32_LE(X2, output, 8); PUT_UINT32_LE(X3, output, 12); - return(0); + return (0); } /* end of aes.c */ diff --git a/nfq/crypto/aes.h b/nfq/crypto/aes.h index b04724d..402ee04 100644 --- a/nfq/crypto/aes.h +++ b/nfq/crypto/aes.h @@ -1,35 +1,35 @@ /****************************************************************************** -* -* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL -* -* This is a simple and straightforward implementation of the AES Rijndael -* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus -* of this work was correctness & accuracy. It is written in 'C' without any -* particular focus upon optimization or speed. It should be endian (memory -* byte order) neutral since the few places that care are handled explicitly. -* -* This implementation of Rijndael was created by Steven M. Gibson of GRC.com. -* -* It is intended for general purpose use, but was written in support of GRC's -* reference implementation of the SQRL (Secure Quick Reliable Login) client. -* -* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html -* -* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE -* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. -* -*******************************************************************************/ + * + * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL + * + * This is a simple and straightforward implementation of the AES Rijndael + * 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus + * of this work was correctness & accuracy. It is written in 'C' without any + * particular focus upon optimization or speed. It should be endian (memory + * byte order) neutral since the few places that care are handled explicitly. + * + * This implementation of Rijndael was created by Steven M. Gibson of GRC.com. + * + * It is intended for general purpose use, but was written in support of GRC's + * reference implementation of the SQRL (Secure Quick Reliable Login) client. + * + * See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html + * + * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE + * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. + * + *******************************************************************************/ #pragma once /******************************************************************************/ -#define AES_DECRYPTION 0 // whether AES decryption is supported +#define AES_DECRYPTION 0 // whether AES decryption is supported /******************************************************************************/ #include -#define AES_ENCRYPT 1 // specify whether we're encrypting -#define AES_DECRYPT 0 // or decrypting +#define AES_ENCRYPT 1 // specify whether we're encrypting +#define AES_DECRYPT 0 // or decrypting #if defined(_MSC_VER) #include @@ -38,41 +38,39 @@ typedef UINT32 uint32_t; #include #endif -typedef unsigned char uchar; // add some convienent shorter types +typedef unsigned char uchar; // add some convienent shorter types typedef unsigned int uint; - /****************************************************************************** * AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use ******************************************************************************/ void aes_init_keygen_tables(void); - /****************************************************************************** * AES_CONTEXT : cipher context / holds inter-call data ******************************************************************************/ -typedef struct { - int mode; // 1 for Encryption, 0 for Decryption - int rounds; // keysize-based rounds count - uint32_t *rk; // pointer to current round key - uint32_t buf[68]; // key expansion buffer +typedef struct +{ + int mode; // 1 for Encryption, 0 for Decryption + int rounds; // keysize-based rounds count + uint32_t *rk; // pointer to current round key + uint32_t buf[68]; // key expansion buffer } aes_context; - /****************************************************************************** * AES_SETKEY : called to expand the key for encryption or decryption ******************************************************************************/ -int aes_setkey(aes_context *ctx, // pointer to context - int mode, // 1 or 0 for Encrypt/Decrypt - const uchar *key, // AES input key - uint keysize); // size in bytes (must be 16, 24, 32 for - // 128, 192 or 256-bit keys respectively) - // returns 0 for success +int aes_setkey(aes_context *ctx, // pointer to context + int mode, // 1 or 0 for Encrypt/Decrypt + const uchar *key, // AES input key + uint keysize); // size in bytes (must be 16, 24, 32 for + // 128, 192 or 256-bit keys respectively) + // returns 0 for success /****************************************************************************** * AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data ******************************************************************************/ -int aes_cipher(aes_context *ctx, // pointer to context - const uchar input[16], // 128-bit block to en/decipher - uchar output[16]); // 128-bit output result block - // returns 0 for success +int aes_cipher(aes_context *ctx, // pointer to context + const uchar input[16], // 128-bit block to en/decipher + uchar output[16]); // 128-bit output result block + // returns 0 for success diff --git a/nfq/crypto/gcm.c b/nfq/crypto/gcm.c index 92a6e8f..d4fe3b0 100644 --- a/nfq/crypto/gcm.c +++ b/nfq/crypto/gcm.c @@ -1,26 +1,26 @@ /****************************************************************************** -* -* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL -* -* This is a simple and straightforward implementation of AES-GCM authenticated -* encryption. The focus of this work was correctness & accuracy. It is written -* in straight 'C' without any particular focus upon optimization or speed. It -* should be endian (memory byte order) neutral since the few places that care -* are handled explicitly. -* -* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com. -* -* It is intended for general purpose use, but was written in support of GRC's -* reference implementation of the SQRL (Secure Quick Reliable Login) client. -* -* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf -* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ -* gcm/gcm-revised-spec.pdf -* -* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE -* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. -* -*******************************************************************************/ + * + * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL + * + * This is a simple and straightforward implementation of AES-GCM authenticated + * encryption. The focus of this work was correctness & accuracy. It is written + * in straight 'C' without any particular focus upon optimization or speed. It + * should be endian (memory byte order) neutral since the few places that care + * are handled explicitly. + * + * This implementation of AES-GCM was created by Steven M. Gibson of GRC.com. + * + * It is intended for general purpose use, but was written in support of GRC's + * reference implementation of the SQRL (Secure Quick Reliable Login) client. + * + * See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ + * gcm/gcm-revised-spec.pdf + * + * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE + * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. + * + *******************************************************************************/ #include "gcm.h" #include "aes.h" @@ -41,80 +41,79 @@ * ******************************************************************************/ - /* Calculating the "GHASH" - * - * There are many ways of calculating the so-called GHASH in software, each with - * a traditional size vs performance tradeoff. The GHASH (Galois field hash) is - * an intriguing construction which takes two 128-bit strings (also the cipher's - * block size and the fundamental operation size for the system) and hashes them - * into a third 128-bit result. - * - * Many implementation solutions have been worked out that use large precomputed - * table lookups in place of more time consuming bit fiddling, and this approach - * can be scaled easily upward or downward as needed to change the time/space - * tradeoff. It's been studied extensively and there's a solid body of theory and - * practice. For example, without using any lookup tables an implementation - * might obtain 119 cycles per byte throughput, whereas using a simple, though - * large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13 - * cycles per byte. - * - * And Intel's processors have, since 2010, included an instruction which does - * the entire 128x128->128 bit job in just several 64x64->128 bit pieces. - * - * Since SQRL is interactive, and only processing a few 128-bit blocks, I've - * settled upon a relatively slower but appealing small-table compromise which - * folds a bunch of not only time consuming but also bit twiddling into a simple - * 16-entry table which is attributed to Victor Shoup's 1996 work while at - * Bellcore: "On Fast and Provably Secure MessageAuthentication Based on - * Universal Hashing." See: http://www.shoup.net/papers/macs.pdf - * See, also section 4.1 of the "gcm-revised-spec" cited above. - */ +/* Calculating the "GHASH" + * + * There are many ways of calculating the so-called GHASH in software, each with + * a traditional size vs performance tradeoff. The GHASH (Galois field hash) is + * an intriguing construction which takes two 128-bit strings (also the cipher's + * block size and the fundamental operation size for the system) and hashes them + * into a third 128-bit result. + * + * Many implementation solutions have been worked out that use large precomputed + * table lookups in place of more time consuming bit fiddling, and this approach + * can be scaled easily upward or downward as needed to change the time/space + * tradeoff. It's been studied extensively and there's a solid body of theory and + * practice. For example, without using any lookup tables an implementation + * might obtain 119 cycles per byte throughput, whereas using a simple, though + * large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13 + * cycles per byte. + * + * And Intel's processors have, since 2010, included an instruction which does + * the entire 128x128->128 bit job in just several 64x64->128 bit pieces. + * + * Since SQRL is interactive, and only processing a few 128-bit blocks, I've + * settled upon a relatively slower but appealing small-table compromise which + * folds a bunch of not only time consuming but also bit twiddling into a simple + * 16-entry table which is attributed to Victor Shoup's 1996 work while at + * Bellcore: "On Fast and Provably Secure MessageAuthentication Based on + * Universal Hashing." See: http://www.shoup.net/papers/macs.pdf + * See, also section 4.1 of the "gcm-revised-spec" cited above. + */ - /* - * This 16-entry table of pre-computed constants is used by the - * GHASH multiplier to improve over a strictly table-free but - * significantly slower 128x128 bit multiple within GF(2^128). - */ +/* + * This 16-entry table of pre-computed constants is used by the + * GHASH multiplier to improve over a strictly table-free but + * significantly slower 128x128 bit multiple within GF(2^128). + */ static const uint64_t last4[16] = { 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0, - 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0 }; + 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0}; /* * Platform Endianness Neutralizing Load and Store Macro definitions * GCM wants platform-neutral Big Endian (BE) byte ordering */ -#define GET_UINT32_BE(n,b,i) { \ - (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ - | ( (uint32_t) (b)[(i) + 1] << 16 ) \ - | ( (uint32_t) (b)[(i) + 2] << 8 ) \ - | ( (uint32_t) (b)[(i) + 3] ); } +#define GET_UINT32_BE(n, b, i) \ + { \ + (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); \ + } -#define PUT_UINT32_BE(n,b,i) { \ - (b)[(i) ] = (uchar) ( (n) >> 24 ); \ - (b)[(i) + 1] = (uchar) ( (n) >> 16 ); \ - (b)[(i) + 2] = (uchar) ( (n) >> 8 ); \ - (b)[(i) + 3] = (uchar) ( (n) ); } +#define PUT_UINT32_BE(n, b, i) \ + { \ + (b)[(i)] = (uchar)((n) >> 24); \ + (b)[(i) + 1] = (uchar)((n) >> 16); \ + (b)[(i) + 2] = (uchar)((n) >> 8); \ + (b)[(i) + 3] = (uchar)((n)); \ + } - - /****************************************************************************** - * - * GCM_INITIALIZE - * - * Must be called once to initialize the GCM library. - * - * At present, this only calls the AES keygen table generator, which expands - * the AES keying tables for use. This is NOT A THREAD-SAFE function, so it - * MUST be called during system initialization before a multi-threading - * environment is running. - * - ******************************************************************************/ +/****************************************************************************** + * + * GCM_INITIALIZE + * + * Must be called once to initialize the GCM library. + * + * At present, this only calls the AES keygen table generator, which expands + * the AES keying tables for use. This is NOT A THREAD-SAFE function, so it + * MUST be called during system initialization before a multi-threading + * environment is running. + * + ******************************************************************************/ int gcm_initialize(void) { aes_init_keygen_tables(); - return(0); + return (0); } - /****************************************************************************** * * GCM_MULT @@ -124,9 +123,9 @@ int gcm_initialize(void) * 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field. * ******************************************************************************/ -static void gcm_mult(gcm_context *ctx, // pointer to established context - const uchar x[16], // pointer to 128-bit input vector - uchar output[16]) // pointer to 128-bit output vector +static void gcm_mult(gcm_context *ctx, // pointer to established context + const uchar x[16], // pointer to 128-bit input vector + uchar output[16]) // pointer to 128-bit output vector { int i; uchar lo, hi, rem; @@ -137,11 +136,13 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context zh = ctx->HH[lo]; zl = ctx->HL[lo]; - for (i = 15; i >= 0; i--) { + for (i = 15; i >= 0; i--) + { lo = (uchar)(x[i] & 0x0f); hi = (uchar)(x[i] >> 4); - if (i != 15) { + if (i != 15) + { rem = (uchar)(zl & 0x0f); zl = (zh << 60) | (zl >> 4); zh = (zh >> 4); @@ -162,7 +163,6 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context PUT_UINT32_BE(zl, output, 12); } - /****************************************************************************** * * GCM_SETKEY @@ -172,26 +172,26 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context * ******************************************************************************/ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context - const uchar *key, // pointer to the AES encryption key - const uint keysize) // size in bytes (must be 16, 24, 32 for - // 128, 192 or 256-bit keys respectively) + const uchar *key, // pointer to the AES encryption key + const uint keysize) // size in bytes (must be 16, 24, 32 for + // 128, 192 or 256-bit keys respectively) { int ret, i, j; uint64_t hi, lo; uint64_t vl, vh; unsigned char h[16]; - memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context - memset(h, 0, 16); // initialize the block to encrypt + memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context + memset(h, 0, 16); // initialize the block to encrypt // encrypt the null 128-bit block to generate a key-based value // which is then used to initialize our GHASH lookup tables if ((ret = aes_setkey(&ctx->aes_ctx, AES_ENCRYPT, key, keysize)) != 0) - return(ret); + return (ret); if ((ret = aes_cipher(&ctx->aes_ctx, h, h)) != 0) - return(ret); + return (ret); - GET_UINT32_BE(hi, h, 0); // pack h as two 64-bit ints, big-endian + GET_UINT32_BE(hi, h, 0); // pack h as two 64-bit ints, big-endian GET_UINT32_BE(lo, h, 4); vh = (uint64_t)hi << 32 | lo; @@ -199,31 +199,33 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context GET_UINT32_BE(lo, h, 12); vl = (uint64_t)hi << 32 | lo; - ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128) + ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128) ctx->HH[8] = vh; - ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128) + ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128) ctx->HL[0] = 0; - for (i = 4; i > 0; i >>= 1) { + for (i = 4; i > 0; i >>= 1) + { uint32_t T = (uint32_t)(vl & 1) * 0xe1000000U; vl = (vh << 63) | (vl >> 1); vh = (vh >> 1) ^ ((uint64_t)T << 32); ctx->HL[i] = vl; ctx->HH[i] = vh; } - for (i = 2; i < 16; i <<= 1) { + for (i = 2; i < 16; i <<= 1) + { uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; vh = *HiH; vl = *HiL; - for (j = 1; j < i; j++) { + for (j = 1; j < i; j++) + { HiH[j] = vh ^ ctx->HH[j]; HiL[j] = vl ^ ctx->HL[j]; } } - return(0); + return (0); } - /****************************************************************************** * * GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH. @@ -245,18 +247,18 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context * mode, and preprocesses the initialization vector and additional AEAD data. * ******************************************************************************/ -int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context - int mode, // GCM_ENCRYPT or GCM_DECRYPT - const uchar *iv, // pointer to initialization vector - size_t iv_len, // IV length in bytes (should == 12) - const uchar *add, // ptr to additional AEAD data (NULL if none) - size_t add_len) // length of additional AEAD data (bytes) +int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context + int mode, // GCM_ENCRYPT or GCM_DECRYPT + const uchar *iv, // pointer to initialization vector + size_t iv_len, // IV length in bytes (should == 12) + const uchar *add, // ptr to additional AEAD data (NULL if none) + size_t add_len) // length of additional AEAD data (bytes) { - int ret; // our error return if the AES encrypt fails + int ret; // our error return if the AES encrypt fails uchar work_buf[16]; // XOR source built from provided IV if len != 16 - const uchar *p; // general purpose array pointer - size_t use_len; // byte count to process, up to 16 bytes - size_t i; // local loop iterator + const uchar *p; // general purpose array pointer + size_t use_len; // byte count to process, up to 16 bytes + size_t i; // local loop iterator // since the context might be reused under the same key // we zero the working buffers for this next new process @@ -265,42 +267,48 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context ctx->len = 0; ctx->add_len = 0; - ctx->mode = mode; // set the GCM encryption/decryption mode - ctx->aes_ctx.mode = AES_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode + ctx->mode = mode; // set the GCM encryption/decryption mode + ctx->aes_ctx.mode = AES_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode - if (iv_len == 12) { // GCM natively uses a 12-byte, 96-bit IV - memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff - ctx->y[15] = 1; // start "counting" from 1 (not 0) + if (iv_len == 12) + { // GCM natively uses a 12-byte, 96-bit IV + memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff + ctx->y[15] = 1; // start "counting" from 1 (not 0) } - else // if we don't have a 12-byte IV, we GHASH whatever we've been given + else // if we don't have a 12-byte IV, we GHASH whatever we've been given { - memset(work_buf, 0x00, 16); // clear the working buffer - PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer + memset(work_buf, 0x00, 16); // clear the working buffer + PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer p = iv; - while (iv_len > 0) { + while (iv_len > 0) + { use_len = (iv_len < 16) ? iv_len : 16; - for (i = 0; i < use_len; i++) ctx->y[i] ^= p[i]; + for (i = 0; i < use_len; i++) + ctx->y[i] ^= p[i]; gcm_mult(ctx, ctx->y, ctx->y); iv_len -= use_len; p += use_len; } - for (i = 0; i < 16; i++) ctx->y[i] ^= work_buf[i]; + for (i = 0; i < 16; i++) + ctx->y[i] ^= work_buf[i]; gcm_mult(ctx, ctx->y, ctx->y); } if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0) - return(ret); + return (ret); ctx->add_len = add_len; p = add; - while (add_len > 0) { + while (add_len > 0) + { use_len = (add_len < 16) ? add_len : 16; - for (i = 0; i < use_len; i++) ctx->buf[i] ^= p[i]; + for (i = 0; i < use_len; i++) + ctx->buf[i] ^= p[i]; gcm_mult(ctx, ctx->buf, ctx->buf); add_len -= use_len; p += use_len; } - return(0); + return (0); } /****************************************************************************** @@ -314,48 +322,53 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context * have a partial block length of < 128 bits.) * ******************************************************************************/ -int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context - size_t length, // length, in bytes, of data to process - const uchar *input, // pointer to source data - uchar *output) // pointer to destination data +int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context + size_t length, // length, in bytes, of data to process + const uchar *input, // pointer to source data + uchar *output) // pointer to destination data { - int ret; // our error return if the AES encrypt fails - uchar ectr[16]; // counter-mode cipher output for XORing - size_t use_len; // byte count to process, up to 16 bytes - size_t i; // local loop iterator + int ret; // our error return if the AES encrypt fails + uchar ectr[16]; // counter-mode cipher output for XORing + size_t use_len; // byte count to process, up to 16 bytes + size_t i; // local loop iterator ctx->len += length; // bump the GCM context's running length count - while (length > 0) { + while (length > 0) + { // clamp the length to process at 16 bytes use_len = (length < 16) ? length : 16; // increment the context's 128-bit IV||Counter 'y' vector - for (i = 16; i > 12; i--) if (++ctx->y[i - 1] != 0) break; + for (i = 16; i > 12; i--) + if (++ctx->y[i - 1] != 0) + break; // encrypt the context's 'y' vector under the established key if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ectr)) != 0) - return(ret); + return (ret); // encrypt or decrypt the input to the output if (ctx->mode == AES_ENCRYPT) { - for (i = 0; i < use_len; i++) { + for (i = 0; i < use_len; i++) + { // XOR the cipher's ouptut vector (ectr) with our input output[i] = (uchar)(ectr[i] ^ input[i]); // now we mix in our data into the authentication hash. - // if we're ENcrypting we XOR in the post-XOR (output) - // results, but if we're DEcrypting we XOR in the input + // if we're ENcrypting we XOR in the post-XOR (output) + // results, but if we're DEcrypting we XOR in the input // data ctx->buf[i] ^= output[i]; } } else { - for (i = 0; i < use_len; i++) { - // but if we're DEcrypting we XOR in the input data first, - // i.e. before saving to ouput data, otherwise if the input - // and output buffer are the same (inplace decryption) we + for (i = 0; i < use_len; i++) + { + // but if we're DEcrypting we XOR in the input data first, + // i.e. before saving to ouput data, otherwise if the input + // and output buffer are the same (inplace decryption) we // would not get the correct auth tag ctx->buf[i] ^= input[i]; @@ -364,13 +377,13 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context output[i] = (uchar)(ectr[i] ^ input[i]); } } - gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation + gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation - length -= use_len; // drop the remaining byte count to process + length -= use_len; // drop the remaining byte count to process input += use_len; // bump our input pointer forward - output += use_len; // bump our output pointer forward + output += use_len; // bump our output pointer forward } - return(0); + return (0); } /****************************************************************************** @@ -381,18 +394,20 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context * It performs the final GHASH to produce the resulting authentication TAG. * ******************************************************************************/ -int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context - uchar *tag, // pointer to buffer which receives the tag - size_t tag_len) // length, in bytes, of the tag-receiving buf +int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context + uchar *tag, // pointer to buffer which receives the tag + size_t tag_len) // length, in bytes, of the tag-receiving buf { uchar work_buf[16]; uint64_t orig_len = ctx->len * 8; uint64_t orig_add_len = ctx->add_len * 8; size_t i; - if (tag_len != 0) memcpy(tag, ctx->base_ectr, tag_len); + if (tag_len != 0) + memcpy(tag, ctx->base_ectr, tag_len); - if (orig_len || orig_add_len) { + if (orig_len || orig_add_len) + { memset(work_buf, 0x00, 16); PUT_UINT32_BE((orig_add_len >> 32), work_buf, 0); @@ -400,14 +415,15 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context PUT_UINT32_BE((orig_len >> 32), work_buf, 8); PUT_UINT32_BE((orig_len), work_buf, 12); - for (i = 0; i < 16; i++) ctx->buf[i] ^= work_buf[i]; + for (i = 0; i < 16; i++) + ctx->buf[i] ^= work_buf[i]; gcm_mult(ctx, ctx->buf, ctx->buf); - for (i = 0; i < tag_len; i++) tag[i] ^= ctx->buf[i]; + for (i = 0; i < tag_len; i++) + tag[i] ^= ctx->buf[i]; } - return(0); + return (0); } - /****************************************************************************** * * GCM_CRYPT_AND_TAG @@ -426,29 +442,28 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context * ******************************************************************************/ int gcm_crypt_and_tag( - gcm_context *ctx, // gcm context with key already setup - int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT - const uchar *iv, // pointer to the 12-byte initialization vector - size_t iv_len, // byte length if the IV. should always be 12 - const uchar *add, // pointer to the non-ciphered additional data - size_t add_len, // byte length of the additional AEAD data - const uchar *input, // pointer to the cipher data source - uchar *output, // pointer to the cipher data destination - size_t length, // byte length of the cipher data - uchar *tag, // pointer to the tag to be generated - size_t tag_len) // byte length of the tag to be generated -{ /* - assuming that the caller has already invoked gcm_setkey to - prepare the gcm context with the keying material, we simply - invoke each of the three GCM sub-functions in turn... - */ + gcm_context *ctx, // gcm context with key already setup + int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT + const uchar *iv, // pointer to the 12-byte initialization vector + size_t iv_len, // byte length if the IV. should always be 12 + const uchar *add, // pointer to the non-ciphered additional data + size_t add_len, // byte length of the additional AEAD data + const uchar *input, // pointer to the cipher data source + uchar *output, // pointer to the cipher data destination + size_t length, // byte length of the cipher data + uchar *tag, // pointer to the tag to be generated + size_t tag_len) // byte length of the tag to be generated +{ /* + assuming that the caller has already invoked gcm_setkey to + prepare the gcm context with the keying material, we simply + invoke each of the three GCM sub-functions in turn... + */ gcm_start(ctx, mode, iv, iv_len, add, add_len); gcm_update(ctx, length, input, output); gcm_finish(ctx, tag, tag_len); - return(0); + return (0); } - /****************************************************************************** * * GCM_AUTH_DECRYPT @@ -462,37 +477,38 @@ int gcm_crypt_and_tag( * ******************************************************************************/ int gcm_auth_decrypt( - gcm_context *ctx, // gcm context with key already setup - const uchar *iv, // pointer to the 12-byte initialization vector - size_t iv_len, // byte length if the IV. should always be 12 - const uchar *add, // pointer to the non-ciphered additional data - size_t add_len, // byte length of the additional AEAD data - const uchar *input, // pointer to the cipher data source - uchar *output, // pointer to the cipher data destination - size_t length, // byte length of the cipher data - const uchar *tag, // pointer to the tag to be authenticated - size_t tag_len) // byte length of the tag <= 16 + gcm_context *ctx, // gcm context with key already setup + const uchar *iv, // pointer to the 12-byte initialization vector + size_t iv_len, // byte length if the IV. should always be 12 + const uchar *add, // pointer to the non-ciphered additional data + size_t add_len, // byte length of the additional AEAD data + const uchar *input, // pointer to the cipher data source + uchar *output, // pointer to the cipher data destination + size_t length, // byte length of the cipher data + const uchar *tag, // pointer to the tag to be authenticated + size_t tag_len) // byte length of the tag <= 16 { - uchar check_tag[16]; // the tag generated and returned by decryption - int diff; // an ORed flag to detect authentication errors - size_t i; // our local iterator + uchar check_tag[16]; // the tag generated and returned by decryption + int diff; // an ORed flag to detect authentication errors + size_t i; // our local iterator /* we use GCM_DECRYPT_AND_TAG (above) to perform our decryption (which is an identical XORing to reverse the previous one) and also to re-generate the matching authentication tag */ gcm_crypt_and_tag(ctx, AES_DECRYPT, iv, iv_len, add, add_len, - input, output, length, check_tag, tag_len); + input, output, length, check_tag, tag_len); // now we verify the authentication tag in 'constant time' for (diff = 0, i = 0; i < tag_len; i++) diff |= tag[i] ^ check_tag[i]; - if (diff != 0) { // see whether any bits differed? - memset(output, 0, length); // if so... wipe the output data - return(GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE + if (diff != 0) + { // see whether any bits differed? + memset(output, 0, length); // if so... wipe the output data + return (GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE } - return(0); + return (0); } /****************************************************************************** diff --git a/nfq/crypto/gcm.h b/nfq/crypto/gcm.h index 42adad9..bd18f89 100644 --- a/nfq/crypto/gcm.h +++ b/nfq/crypto/gcm.h @@ -1,73 +1,70 @@ /****************************************************************************** -* -* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL -* -* This is a simple and straightforward implementation of AES-GCM authenticated -* encryption. The focus of this work was correctness & accuracy. It is written -* in straight 'C' without any particular focus upon optimization or speed. It -* should be endian (memory byte order) neutral since the few places that care -* are handled explicitly. -* -* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com. -* -* It is intended for general purpose use, but was written in support of GRC's -* reference implementation of the SQRL (Secure Quick Reliable Login) client. -* -* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf -* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \ -* gcm/gcm-revised-spec.pdf -* -* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE -* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. -* -*******************************************************************************/ + * + * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL + * + * This is a simple and straightforward implementation of AES-GCM authenticated + * encryption. The focus of this work was correctness & accuracy. It is written + * in straight 'C' without any particular focus upon optimization or speed. It + * should be endian (memory byte order) neutral since the few places that care + * are handled explicitly. + * + * This implementation of AES-GCM was created by Steven M. Gibson of GRC.com. + * + * It is intended for general purpose use, but was written in support of GRC's + * reference implementation of the SQRL (Secure Quick Reliable Login) client. + * + * See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \ + * gcm/gcm-revised-spec.pdf + * + * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE + * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. + * + *******************************************************************************/ #pragma once -#define GCM_AUTH_FAILURE 0x55555555 // authentication failure +#define GCM_AUTH_FAILURE 0x55555555 // authentication failure -#include "aes.h" // gcm_context includes aes_context +#include "aes.h" // gcm_context includes aes_context #if defined(_MSC_VER) #include -typedef unsigned int size_t;// use the right type for length declarations +typedef unsigned int size_t; // use the right type for length declarations typedef UINT32 uint32_t; typedef UINT64 uint64_t; #else #include #endif - /****************************************************************************** * GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx ******************************************************************************/ -typedef struct { - int mode; // cipher direction: encrypt/decrypt - uint64_t len; // cipher data length processed so far - uint64_t add_len; // total add data length - uint64_t HL[16]; // precalculated lo-half HTable - uint64_t HH[16]; // precalculated hi-half HTable - uchar base_ectr[16]; // first counter-mode cipher output for tag - uchar y[16]; // the current cipher-input IV|Counter value - uchar buf[16]; // buf working value - aes_context aes_ctx; // cipher context used +typedef struct +{ + int mode; // cipher direction: encrypt/decrypt + uint64_t len; // cipher data length processed so far + uint64_t add_len; // total add data length + uint64_t HL[16]; // precalculated lo-half HTable + uint64_t HH[16]; // precalculated hi-half HTable + uchar base_ectr[16]; // first counter-mode cipher output for tag + uchar y[16]; // the current cipher-input IV|Counter value + uchar buf[16]; // buf working value + aes_context aes_ctx; // cipher context used } gcm_context; - /****************************************************************************** * GCM_CONTEXT : MUST be called once before ANY use of this library ******************************************************************************/ int gcm_initialize(void); - /****************************************************************************** * GCM_SETKEY : sets the GCM (and AES) keying material for use ******************************************************************************/ -int gcm_setkey(gcm_context *ctx, // caller-provided context ptr - const uchar *key, // pointer to cipher key - const uint keysize // size in bytes (must be 16, 24, 32 for - // 128, 192 or 256-bit keys respectively) -); // returns 0 for success - +int gcm_setkey(gcm_context *ctx, // caller-provided context ptr + const uchar *key, // pointer to cipher key + const uint keysize // size in bytes (must be 16, 24, 32 for + // 128, 192 or 256-bit keys respectively) +); // returns 0 for success /****************************************************************************** * @@ -87,18 +84,17 @@ int gcm_setkey(gcm_context *ctx, // caller-provided context ptr * ******************************************************************************/ int gcm_crypt_and_tag( - gcm_context *ctx, // gcm context with key already setup - int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0) - const uchar *iv, // pointer to the 12-byte initialization vector - size_t iv_len, // byte length if the IV. should always be 12 - const uchar *add, // pointer to the non-ciphered additional data - size_t add_len, // byte length of the additional AEAD data - const uchar *input, // pointer to the cipher data source - uchar *output, // pointer to the cipher data destination - size_t length, // byte length of the cipher data - uchar *tag, // pointer to the tag to be generated - size_t tag_len); // byte length of the tag to be generated - + gcm_context *ctx, // gcm context with key already setup + int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0) + const uchar *iv, // pointer to the 12-byte initialization vector + size_t iv_len, // byte length if the IV. should always be 12 + const uchar *add, // pointer to the non-ciphered additional data + size_t add_len, // byte length of the additional AEAD data + const uchar *input, // pointer to the cipher data source + uchar *output, // pointer to the cipher data destination + size_t length, // byte length of the cipher data + uchar *tag, // pointer to the tag to be generated + size_t tag_len); // byte length of the tag to be generated /****************************************************************************** * @@ -113,17 +109,16 @@ int gcm_crypt_and_tag( * ******************************************************************************/ int gcm_auth_decrypt( - gcm_context *ctx, // gcm context with key already setup - const uchar *iv, // pointer to the 12-byte initialization vector - size_t iv_len, // byte length if the IV. should always be 12 - const uchar *add, // pointer to the non-ciphered additional data - size_t add_len, // byte length of the additional AEAD data - const uchar *input, // pointer to the cipher data source - uchar *output, // pointer to the cipher data destination - size_t length, // byte length of the cipher data - const uchar *tag, // pointer to the tag to be authenticated - size_t tag_len); // byte length of the tag <= 16 - + gcm_context *ctx, // gcm context with key already setup + const uchar *iv, // pointer to the 12-byte initialization vector + size_t iv_len, // byte length if the IV. should always be 12 + const uchar *add, // pointer to the non-ciphered additional data + size_t add_len, // byte length of the additional AEAD data + const uchar *input, // pointer to the cipher data source + uchar *output, // pointer to the cipher data destination + size_t length, // byte length of the cipher data + const uchar *tag, // pointer to the tag to be authenticated + size_t tag_len); // byte length of the tag <= 16 /****************************************************************************** * @@ -133,13 +128,12 @@ int gcm_auth_decrypt( * mode, and preprocesses the initialization vector and additional AEAD data. * ******************************************************************************/ -int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context - int mode, // ENCRYPT (1) or DECRYPT (0) - const uchar *iv, // pointer to initialization vector - size_t iv_len, // IV length in bytes (should == 12) - const uchar *add, // pointer to additional AEAD data (NULL if none) - size_t add_len); // length of additional AEAD data (bytes) - +int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context + int mode, // ENCRYPT (1) or DECRYPT (0) + const uchar *iv, // pointer to initialization vector + size_t iv_len, // IV length in bytes (should == 12) + const uchar *add, // pointer to additional AEAD data (NULL if none) + size_t add_len); // length of additional AEAD data (bytes) /****************************************************************************** * @@ -152,11 +146,10 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context * have a partial block length of < 128 bits.) * ******************************************************************************/ -int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context - size_t length, // length, in bytes, of data to process - const uchar *input, // pointer to source data - uchar *output); // pointer to destination data - +int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context + size_t length, // length, in bytes, of data to process + const uchar *input, // pointer to source data + uchar *output); // pointer to destination data /****************************************************************************** * @@ -166,10 +159,9 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context * It performs the final GHASH to produce the resulting authentication TAG. * ******************************************************************************/ -int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context - uchar *tag, // ptr to tag buffer - NULL if tag_len = 0 - size_t tag_len); // length, in bytes, of the tag-receiving buf - +int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context + uchar *tag, // ptr to tag buffer - NULL if tag_len = 0 + size_t tag_len); // length, in bytes, of the tag-receiving buf /****************************************************************************** * diff --git a/nfq/crypto/hkdf.c b/nfq/crypto/hkdf.c index 266cb37..b35e95d 100644 --- a/nfq/crypto/hkdf.c +++ b/nfq/crypto/hkdf.c @@ -15,54 +15,54 @@ #include #include - /* - * hkdf - * - * Description: - * This function will generate keying material using HKDF. - * - * Parameters: - * whichSha: [in] - * One of SHA1, SHA224, SHA256, SHA384, SHA512 - * salt[ ]: [in] - * The optional salt value (a non-secret random value); - * if not provided (salt == NULL), it is set internally - * to a string of HashLen(whichSha) zeros. - * salt_len: [in] - * The length of the salt value. (Ignored if salt == NULL.) - * ikm[ ]: [in] - * Input keying material. - * ikm_len: [in] - * The length of the input keying material. - * info[ ]: [in] - * The optional context and application specific information. - * If info == NULL or a zero-length string, it is ignored. - * info_len: [in] - * The length of the optional context and application specific - * information. (Ignored if info == NULL.) - * okm[ ]: [out] - * Where the HKDF is to be stored. - * okm_len: [in] - * The length of the buffer to hold okm. - * okm_len must be <= 255 * USHABlockSize(whichSha) - * - * Notes: - * Calls hkdfExtract() and hkdfExpand(). - * - * Returns: - * sha Error Code. - * - */ +/* + * hkdf + * + * Description: + * This function will generate keying material using HKDF. + * + * Parameters: + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * salt[ ]: [in] + * The optional salt value (a non-secret random value); + * if not provided (salt == NULL), it is set internally + * to a string of HashLen(whichSha) zeros. + * salt_len: [in] + * The length of the salt value. (Ignored if salt == NULL.) + * ikm[ ]: [in] + * Input keying material. + * ikm_len: [in] + * The length of the input keying material. + * info[ ]: [in] + * The optional context and application specific information. + * If info == NULL or a zero-length string, it is ignored. + * info_len: [in] + * The length of the optional context and application specific + * information. (Ignored if info == NULL.) + * okm[ ]: [out] + * Where the HKDF is to be stored. + * okm_len: [in] + * The length of the buffer to hold okm. + * okm_len must be <= 255 * USHABlockSize(whichSha) + * + * Notes: + * Calls hkdfExtract() and hkdfExpand(). + * + * Returns: + * sha Error Code. + * + */ int hkdf(SHAversion whichSha, - const unsigned char *salt, size_t salt_len, - const unsigned char *ikm, size_t ikm_len, - const unsigned char *info, size_t info_len, - uint8_t okm[], size_t okm_len) + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + const unsigned char *info, size_t info_len, + uint8_t okm[], size_t okm_len) { uint8_t prk[USHAMaxHashSize]; return hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) || - hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info, - info_len, okm, okm_len); + hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info, + info_len, okm, okm_len); } /* @@ -93,17 +93,19 @@ int hkdf(SHAversion whichSha, * */ int hkdfExtract(SHAversion whichSha, - const unsigned char *salt, size_t salt_len, - const unsigned char *ikm, size_t ikm_len, - uint8_t prk[USHAMaxHashSize]) + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + uint8_t prk[USHAMaxHashSize]) { unsigned char nullSalt[USHAMaxHashSize]; - if (salt == 0) { + if (salt == 0) + { salt = nullSalt; salt_len = USHAHashSize(whichSha); memset(nullSalt, '\0', salt_len); } - else if (salt_len < 0) { + else if (salt_len < 0) + { return shaBadParam; } return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk); @@ -143,42 +145,51 @@ int hkdfExtract(SHAversion whichSha, * */ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len, - const unsigned char *info, size_t info_len, - uint8_t okm[], size_t okm_len) + const unsigned char *info, size_t info_len, + uint8_t okm[], size_t okm_len) { size_t hash_len, N; unsigned char T[USHAMaxHashSize]; size_t Tlen, where, i; - if (info == 0) { + if (info == 0) + { info = (const unsigned char *)""; info_len = 0; } - else if (info_len < 0) { + else if (info_len < 0) + { return shaBadParam; } - if (okm_len <= 0) return shaBadParam; - if (!okm) return shaBadParam; + if (okm_len <= 0) + return shaBadParam; + if (!okm) + return shaBadParam; hash_len = USHAHashSize(whichSha); - if (prk_len < hash_len) return shaBadParam; + if (prk_len < hash_len) + return shaBadParam; N = okm_len / hash_len; - if ((okm_len % hash_len) != 0) N++; - if (N > 255) return shaBadParam; + if ((okm_len % hash_len) != 0) + N++; + if (N > 255) + return shaBadParam; Tlen = 0; where = 0; - for (i = 1; i <= N; i++) { + for (i = 1; i <= N; i++) + { HMACContext context; unsigned char c = i; int ret = hmacReset(&context, whichSha, prk, prk_len) || - hmacInput(&context, T, Tlen) || - hmacInput(&context, info, info_len) || - hmacInput(&context, &c, 1) || - hmacResult(&context, T); - if (ret != shaSuccess) return ret; + hmacInput(&context, T, Tlen) || + hmacInput(&context, info, info_len) || + hmacInput(&context, &c, 1) || + hmacResult(&context, T); + if (ret != shaSuccess) + return ret; memcpy(okm + where, T, - (i != N) ? hash_len : (okm_len - where)); + (i != N) ? hash_len : (okm_len - where)); where += hash_len; Tlen = hash_len; } @@ -210,14 +221,16 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len, * */ int hkdfReset(HKDFContext *context, enum SHAversion whichSha, - const unsigned char *salt, size_t salt_len) + const unsigned char *salt, size_t salt_len) { unsigned char nullSalt[USHAMaxHashSize]; - if (!context) return shaNull; + if (!context) + return shaNull; context->whichSha = whichSha; context->hashSize = USHAHashSize(whichSha); - if (salt == 0) { + if (salt == 0) + { salt = nullSalt; salt_len = context->hashSize; memset(nullSalt, '\0', salt_len); @@ -247,11 +260,14 @@ int hkdfReset(HKDFContext *context, enum SHAversion whichSha, * */ int hkdfInput(HKDFContext *context, const unsigned char *ikm, - size_t ikm_len) + size_t ikm_len) { - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; + if (!context) + return shaNull; + if (context->Corrupted) + return context->Corrupted; + if (context->Computed) + return context->Corrupted = shaStateError; return hmacInput(&context->hmacContext, ikm, ikm_len); } @@ -276,11 +292,14 @@ int hkdfInput(HKDFContext *context, const unsigned char *ikm, * sha Error Code. */ int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, - unsigned int ikm_bit_count) + unsigned int ikm_bit_count) { - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; + if (!context) + return shaNull; + if (context->Corrupted) + return context->Corrupted; + if (context->Computed) + return context->Corrupted = shaStateError; return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count); } @@ -315,23 +334,27 @@ int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, * */ int hkdfResult(HKDFContext *context, - uint8_t prk[USHAMaxHashSize], - const unsigned char *info, size_t info_len, - uint8_t okm[], size_t okm_len) + uint8_t prk[USHAMaxHashSize], + const unsigned char *info, size_t info_len, + uint8_t okm[], size_t okm_len) { uint8_t prkbuf[USHAMaxHashSize]; int ret; - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - if (!okm) return context->Corrupted = shaBadParam; - if (!prk) prk = prkbuf; + if (!context) + return shaNull; + if (context->Corrupted) + return context->Corrupted; + if (context->Computed) + return context->Corrupted = shaStateError; + if (!okm) + return context->Corrupted = shaBadParam; + if (!prk) + prk = prkbuf; ret = hmacResult(&context->hmacContext, prk) || - hkdfExpand(context->whichSha, prk, context->hashSize, info, - info_len, okm, okm_len); + hkdfExpand(context->whichSha, prk, context->hashSize, info, + info_len, okm, okm_len); context->Computed = 1; return context->Corrupted = ret; } - diff --git a/nfq/crypto/hmac.c b/nfq/crypto/hmac.c index 9e05325..7d34d44 100644 --- a/nfq/crypto/hmac.c +++ b/nfq/crypto/hmac.c @@ -14,44 +14,44 @@ #include "sha.h" #include - /* - * hmac - * - * Description: - * This function will compute an HMAC message digest. - * - * Parameters: - * whichSha: [in] - * One of SHA1, SHA224, SHA256, SHA384, SHA512 - * message_array[ ]: [in] - * An array of octets representing the message. - * Note: in RFC 2104, this parameter is known - * as 'text'. - * length: [in] - * The length of the message in message_array. - * key[ ]: [in] - * The secret shared key. - * key_len: [in] - * The length of the secret shared key. - * digest[ ]: [out] - * Where the digest is to be returned. - * NOTE: The length of the digest is determined by - * the value of whichSha. - * - * Returns: - * sha Error Code. - * - */ +/* + * hmac + * + * Description: + * This function will compute an HMAC message digest. + * + * Parameters: + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * message_array[ ]: [in] + * An array of octets representing the message. + * Note: in RFC 2104, this parameter is known + * as 'text'. + * length: [in] + * The length of the message in message_array. + * key[ ]: [in] + * The secret shared key. + * key_len: [in] + * The length of the secret shared key. + * digest[ ]: [out] + * Where the digest is to be returned. + * NOTE: The length of the digest is determined by + * the value of whichSha. + * + * Returns: + * sha Error Code. + * + */ int hmac(SHAversion whichSha, - const unsigned char *message_array, size_t length, - const unsigned char *key, size_t key_len, - uint8_t digest[USHAMaxHashSize]) + const unsigned char *message_array, size_t length, + const unsigned char *key, size_t key_len, + uint8_t digest[USHAMaxHashSize]) { HMACContext context; return hmacReset(&context, whichSha, key, key_len) || - hmacInput(&context, message_array, length) || - hmacResult(&context, digest); + hmacInput(&context, message_array, length) || + hmacResult(&context, digest); } /* @@ -76,7 +76,7 @@ int hmac(SHAversion whichSha, * */ int hmacReset(HMACContext *context, enum SHAversion whichSha, - const unsigned char *key, size_t key_len) + const unsigned char *key, size_t key_len) { size_t i, blocksize, hashsize; int ret; @@ -87,7 +87,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha, /* temporary buffer when keylen > blocksize */ unsigned char tempkey[USHAMaxHashSize]; - if (!context) return shaNull; + if (!context) + return shaNull; context->Computed = 0; context->Corrupted = shaSuccess; @@ -99,12 +100,14 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha, * If key is longer than the hash blocksize, * reset it to key = HASH(key). */ - if (key_len > blocksize) { + if (key_len > blocksize) + { USHAContext tcontext; int err = USHAReset(&tcontext, whichSha) || - USHAInput(&tcontext, key, key_len) || - USHAResult(&tcontext, tempkey); - if (err != shaSuccess) return err; + USHAInput(&tcontext, key, key_len) || + USHAResult(&tcontext, tempkey); + if (err != shaSuccess) + return err; key = tempkey; key_len = hashsize; @@ -121,13 +124,15 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha, * and text is the data being protected. */ - /* store key into the pads, XOR'd with ipad and opad values */ - for (i = 0; i < key_len; i++) { + /* store key into the pads, XOR'd with ipad and opad values */ + for (i = 0; i < key_len; i++) + { k_ipad[i] = key[i] ^ 0x36; context->k_opad[i] = key[i] ^ 0x5c; } /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ - for (; i < blocksize; i++) { + for (; i < blocksize; i++) + { k_ipad[i] = 0x36; context->k_opad[i] = 0x5c; } @@ -135,8 +140,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha, /* perform inner hash */ /* init context for 1st pass */ ret = USHAReset(&context->shaContext, whichSha) || - /* and start with inner pad */ - USHAInput(&context->shaContext, k_ipad, blocksize); + /* and start with inner pad */ + USHAInput(&context->shaContext, k_ipad, blocksize); return context->Corrupted = ret; } @@ -161,14 +166,17 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha, * */ int hmacInput(HMACContext *context, const unsigned char *text, - size_t text_len) + size_t text_len) { - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; + if (!context) + return shaNull; + if (context->Corrupted) + return context->Corrupted; + if (context->Computed) + return context->Corrupted = shaStateError; /* then text of datagram */ return context->Corrupted = - USHAInput(&context->shaContext, text, text_len); + USHAInput(&context->shaContext, text, text_len); } /* @@ -191,14 +199,17 @@ int hmacInput(HMACContext *context, const unsigned char *text, * sha Error Code. */ int hmacFinalBits(HMACContext *context, - uint8_t bits, unsigned int bit_count) + uint8_t bits, unsigned int bit_count) { - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; + if (!context) + return shaNull; + if (context->Corrupted) + return context->Corrupted; + if (context->Computed) + return context->Corrupted = shaStateError; /* then final bits of datagram */ return context->Corrupted = - USHAFinalBits(&context->shaContext, bits, bit_count); + USHAFinalBits(&context->shaContext, bits, bit_count); } /* @@ -223,9 +234,12 @@ int hmacFinalBits(HMACContext *context, int hmacResult(HMACContext *context, uint8_t *digest) { int ret; - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; + if (!context) + return shaNull; + if (context->Corrupted) + return context->Corrupted; + if (context->Computed) + return context->Corrupted = shaStateError; /* finish up 1st pass */ /* (Use digest here as a temporary buffer.) */ @@ -238,7 +252,7 @@ int hmacResult(HMACContext *context, uint8_t *digest) /* start with outer pad */ USHAInput(&context->shaContext, context->k_opad, - context->blockSize) || + context->blockSize) || /* then results of 1st hash */ USHAInput(&context->shaContext, digest, context->hashSize) || diff --git a/nfq/crypto/sha-private.h b/nfq/crypto/sha-private.h index 4ceba0d..41c0d28 100644 --- a/nfq/crypto/sha-private.h +++ b/nfq/crypto/sha-private.h @@ -10,16 +10,16 @@ */ #ifndef USE_MODIFIED_MACROS -#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) -#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define SHA_Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) +#define SHA_Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) #else /* USE_MODIFIED_MACROS */ /* * The following definitions are equivalent and potentially faster. */ -#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) -#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) +#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) #endif /* USE_MODIFIED_MACROS */ -#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) +#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) diff --git a/nfq/crypto/sha.h b/nfq/crypto/sha.h index 8b3a63b..ca21e6b 100644 --- a/nfq/crypto/sha.h +++ b/nfq/crypto/sha.h @@ -85,12 +85,13 @@ /* * All SHA functions return one of these values. */ -enum { +enum +{ shaSuccess = 0, - shaNull, /* Null pointer parameter */ - shaInputTooLong, /* input data too long */ - shaStateError, /* called Input after FinalBits or Result */ - shaBadParam /* passed a bad parameter */ + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError, /* called Input after FinalBits or Result */ + shaBadParam /* passed a bad parameter */ }; #endif /* _SHA_enum_ */ @@ -98,41 +99,50 @@ enum { * These constants hold size information for each of the SHA * hashing operations */ -enum { - SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64, +enum +{ + SHA1_Message_Block_Size = 64, + SHA224_Message_Block_Size = 64, SHA256_Message_Block_Size = 64, USHA_Max_Message_Block_Size = SHA256_Message_Block_Size, - SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32, + SHA1HashSize = 20, + SHA224HashSize = 28, + SHA256HashSize = 32, USHAMaxHashSize = SHA256HashSize, - SHA1HashSizeBits = 160, SHA224HashSizeBits = 224, - SHA256HashSizeBits = 256, USHAMaxHashSizeBits = SHA256HashSizeBits + SHA1HashSizeBits = 160, + SHA224HashSizeBits = 224, + SHA256HashSizeBits = 256, + USHAMaxHashSizeBits = SHA256HashSizeBits }; /* * These constants are used in the USHA (Unified SHA) functions. */ -typedef enum SHAversion { - SHA224, SHA256 +typedef enum SHAversion +{ + SHA224, + SHA256 } SHAversion; /* * This structure will hold context information for the SHA-256 * hashing operation. */ -typedef struct SHA256Context { - uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */ +typedef struct SHA256Context +{ + uint32_t Intermediate_Hash[SHA256HashSize / 4]; /* Message Digest */ - uint32_t Length_High; /* Message length in bits */ - uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + uint32_t Length_Low; /* Message length in bits */ - int_least16_t Message_Block_Index; /* Message_Block array index */ - /* 512-bit message blocks */ + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 512-bit message blocks */ uint8_t Message_Block[SHA256_Message_Block_Size]; - int Computed; /* Is the hash computed? */ - int Corrupted; /* Cumulative corruption code */ + int Computed; /* Is the hash computed? */ + int Corrupted; /* Cumulative corruption code */ } SHA256Context; /* @@ -145,10 +155,13 @@ typedef struct SHA256Context SHA224Context; * This structure holds context information for all SHA * hashing operations. */ -typedef struct USHAContext { - int whichSha; /* which SHA is being used */ - union { - SHA224Context sha224Context; SHA256Context sha256Context; +typedef struct USHAContext +{ + int whichSha; /* which SHA is being used */ + union + { + SHA224Context sha224Context; + SHA256Context sha256Context; } ctx; } USHAContext; @@ -157,15 +170,16 @@ typedef struct USHAContext { * This structure will hold context information for the HMAC * keyed-hashing operation. */ -typedef struct HMACContext { - int whichSha; /* which SHA is being used */ - int hashSize; /* hash size of SHA being used */ - int blockSize; /* block size of SHA being used */ - USHAContext shaContext; /* SHA context */ +typedef struct HMACContext +{ + int whichSha; /* which SHA is being used */ + int hashSize; /* hash size of SHA being used */ + int blockSize; /* block size of SHA being used */ + USHAContext shaContext; /* SHA context */ unsigned char k_opad[USHA_Max_Message_Block_Size]; - /* outer padding - key XORd with opad */ - int Computed; /* Is the MAC computed? */ - int Corrupted; /* Cumulative corruption code */ + /* outer padding - key XORd with opad */ + int Computed; /* Is the MAC computed? */ + int Corrupted; /* Cumulative corruption code */ } HMACContext; @@ -173,47 +187,47 @@ typedef struct HMACContext { * This structure will hold context information for the HKDF * extract-and-expand Key Derivation Functions. */ -typedef struct HKDFContext { - int whichSha; /* which SHA is being used */ +typedef struct HKDFContext +{ + int whichSha; /* which SHA is being used */ HMACContext hmacContext; - int hashSize; /* hash size of SHA being used */ + int hashSize; /* hash size of SHA being used */ unsigned char prk[USHAMaxHashSize]; - /* pseudo-random key - output of hkdfInput */ - int Computed; /* Is the key material computed? */ - int Corrupted; /* Cumulative corruption code */ + /* pseudo-random key - output of hkdfInput */ + int Computed; /* Is the key material computed? */ + int Corrupted; /* Cumulative corruption code */ } HKDFContext; /* * Function Prototypes */ - /* SHA-224 */ int SHA224Reset(SHA224Context *); int SHA224Input(SHA224Context *, const uint8_t *bytes, - unsigned int bytecount); + unsigned int bytecount); int SHA224FinalBits(SHA224Context *, uint8_t bits, - unsigned int bit_count); + unsigned int bit_count); int SHA224Result(SHA224Context *, - uint8_t Message_Digest[SHA224HashSize]); + uint8_t Message_Digest[SHA224HashSize]); /* SHA-256 */ int SHA256Reset(SHA256Context *); int SHA256Input(SHA256Context *, const uint8_t *bytes, - unsigned int bytecount); + unsigned int bytecount); int SHA256FinalBits(SHA256Context *, uint8_t bits, - unsigned int bit_count); + unsigned int bit_count); int SHA256Result(SHA256Context *, - uint8_t Message_Digest[SHA256HashSize]); + uint8_t Message_Digest[SHA256HashSize]); /* Unified SHA functions, chosen by whichSha */ int USHAReset(USHAContext *context, SHAversion whichSha); int USHAInput(USHAContext *context, - const uint8_t *bytes, unsigned int bytecount); + const uint8_t *bytes, unsigned int bytecount); int USHAFinalBits(USHAContext *context, - uint8_t bits, unsigned int bit_count); + uint8_t bits, unsigned int bit_count); int USHAResult(USHAContext *context, - uint8_t Message_Digest[USHAMaxHashSize]); + uint8_t Message_Digest[USHAMaxHashSize]); int USHABlockSize(enum SHAversion whichSha); int USHAHashSize(enum SHAversion whichSha); @@ -222,12 +236,12 @@ int USHAHashSize(enum SHAversion whichSha); * for all SHAs. * This interface allows a fixed-length text input to be used. */ -int hmac(SHAversion whichSha, /* which SHA algorithm to use */ - const unsigned char *text, /* pointer to data stream */ - size_t text_len, /* length of data stream */ - const unsigned char *key, /* pointer to authentication key */ - size_t key_len, /* length of authentication key */ - uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ +int hmac(SHAversion whichSha, /* which SHA algorithm to use */ + const unsigned char *text, /* pointer to data stream */ + size_t text_len, /* length of data stream */ + const unsigned char *key, /* pointer to authentication key */ + size_t key_len, /* length of authentication key */ + uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ /* * HMAC Keyed-Hashing for Message Authentication, RFC 2104, @@ -235,31 +249,30 @@ int hmac(SHAversion whichSha, /* which SHA algorithm to use */ * This interface allows any length of text input to be used. */ int hmacReset(HMACContext *context, enum SHAversion whichSha, - const unsigned char *key, size_t key_len); + const unsigned char *key, size_t key_len); int hmacInput(HMACContext *context, const unsigned char *text, - size_t text_len); + size_t text_len); int hmacFinalBits(HMACContext *context, uint8_t bits, - unsigned int bit_count); + unsigned int bit_count); int hmacResult(HMACContext *context, - uint8_t digest[USHAMaxHashSize]); - + uint8_t digest[USHAMaxHashSize]); /* * HKDF HMAC-based Extract-and-Expand Key Derivation Function, * RFC 5869, for all SHAs. */ int hkdf(SHAversion whichSha, - const unsigned char *salt, size_t salt_len, - const unsigned char *ikm, size_t ikm_len, - const unsigned char *info, size_t info_len, - uint8_t okm[ ], size_t okm_len); + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + const unsigned char *info, size_t info_len, + uint8_t okm[], size_t okm_len); int hkdfExtract(SHAversion whichSha, const unsigned char *salt, - size_t salt_len, const unsigned char *ikm, - size_t ikm_len, uint8_t prk[USHAMaxHashSize]); -int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], - size_t prk_len, const unsigned char *info, - size_t info_len, uint8_t okm[ ], size_t okm_len); + size_t salt_len, const unsigned char *ikm, + size_t ikm_len, uint8_t prk[USHAMaxHashSize]); +int hkdfExpand(SHAversion whichSha, const uint8_t prk[], + size_t prk_len, const unsigned char *info, + size_t info_len, uint8_t okm[], size_t okm_len); /* * HKDF HMAC-based Extract-and-Expand Key Derivation Function, @@ -267,12 +280,12 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], * This interface allows any length of text input to be used. */ int hkdfReset(HKDFContext *context, enum SHAversion whichSha, - const unsigned char *salt, size_t salt_len); + const unsigned char *salt, size_t salt_len); int hkdfInput(HKDFContext *context, const unsigned char *ikm, - size_t ikm_len); + size_t ikm_len); int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, - unsigned int ikm_bit_count); + unsigned int ikm_bit_count); int hkdfResult(HKDFContext *context, - uint8_t prk[USHAMaxHashSize], - const unsigned char *info, size_t info_len, - uint8_t okm[USHAMaxHashSize], size_t okm_len); + uint8_t prk[USHAMaxHashSize], + const unsigned char *info, size_t info_len, + uint8_t okm[USHAMaxHashSize], size_t okm_len); diff --git a/nfq/crypto/sha224-256.c b/nfq/crypto/sha224-256.c index 2c9bc9c..cb319b7 100644 --- a/nfq/crypto/sha224-256.c +++ b/nfq/crypto/sha224-256.c @@ -44,54 +44,53 @@ #include "sha-private.h" /* Define the SHA shift, rotate left, and rotate right macros */ -#define SHA256_SHR(bits,word) ((word) >> (bits)) -#define SHA256_ROTL(bits,word) \ - (((word) << (bits)) | ((word) >> (32-(bits)))) -#define SHA256_ROTR(bits,word) \ - (((word) >> (bits)) | ((word) << (32-(bits)))) +#define SHA256_SHR(bits, word) ((word) >> (bits)) +#define SHA256_ROTL(bits, word) \ + (((word) << (bits)) | ((word) >> (32 - (bits)))) +#define SHA256_ROTR(bits, word) \ + (((word) >> (bits)) | ((word) << (32 - (bits)))) /* Define the SHA SIGMA and sigma macros */ -#define SHA256_SIGMA0(word) \ - (SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word)) -#define SHA256_SIGMA1(word) \ - (SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word)) -#define SHA256_sigma0(word) \ - (SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word)) -#define SHA256_sigma1(word) \ - (SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word)) +#define SHA256_SIGMA0(word) \ + (SHA256_ROTR(2, word) ^ SHA256_ROTR(13, word) ^ SHA256_ROTR(22, word)) +#define SHA256_SIGMA1(word) \ + (SHA256_ROTR(6, word) ^ SHA256_ROTR(11, word) ^ SHA256_ROTR(25, word)) +#define SHA256_sigma0(word) \ + (SHA256_ROTR(7, word) ^ SHA256_ROTR(18, word) ^ SHA256_SHR(3, word)) +#define SHA256_sigma1(word) \ + (SHA256_ROTR(17, word) ^ SHA256_ROTR(19, word) ^ SHA256_SHR(10, word)) /* * Add "length" to the length. * Set Corrupted when overflow has occurred. */ static uint32_t addTemp; -#define SHA224_256AddLength(context, length) \ - (addTemp = (context)->Length_Low, (context)->Corrupted = \ - (((context)->Length_Low += (length)) < addTemp) && \ - (++(context)->Length_High == 0) ? shaInputTooLong : \ - (context)->Corrupted ) +#define SHA224_256AddLength(context, length) \ + (addTemp = (context)->Length_Low, (context)->Corrupted = \ + (((context)->Length_Low += (length)) < addTemp) && \ + (++(context)->Length_High == 0) \ + ? shaInputTooLong \ + : (context)->Corrupted) /* Local Function Prototypes */ static int SHA224_256Reset(SHA256Context *context, uint32_t *H0); static void SHA224_256ProcessMessageBlock(SHA256Context *context); static void SHA224_256Finalize(SHA256Context *context, - uint8_t Pad_Byte); + uint8_t Pad_Byte); static void SHA224_256PadMessage(SHA256Context *context, - uint8_t Pad_Byte); + uint8_t Pad_Byte); static int SHA224_256ResultN(SHA256Context *context, - uint8_t Message_Digest[ ], int HashSize); + uint8_t Message_Digest[], int HashSize); /* Initial Hash Values: FIPS 180-3 section 5.3.2 */ -static uint32_t SHA224_H0[SHA256HashSize/4] = { +static uint32_t SHA224_H0[SHA256HashSize / 4] = { 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, - 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4 -}; + 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4}; /* Initial Hash Values: FIPS 180-3 section 5.3.3 */ -static uint32_t SHA256_H0[SHA256HashSize/4] = { - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 -}; +static uint32_t SHA256_H0[SHA256HashSize / 4] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19}; /* * SHA224Reset @@ -133,7 +132,7 @@ int SHA224Reset(SHA224Context *context) * */ int SHA224Input(SHA224Context *context, const uint8_t *message_array, - unsigned int length) + unsigned int length) { return SHA256Input(context, message_array, length); } @@ -183,7 +182,7 @@ int SHA224FinalBits(SHA224Context *context, * sha Error Code. */ int SHA224Result(SHA224Context *context, - uint8_t Message_Digest[SHA224HashSize]) + uint8_t Message_Digest[SHA224HashSize]) { return SHA224_256ResultN(context, Message_Digest, SHA224HashSize); } @@ -227,27 +226,32 @@ int SHA256Reset(SHA256Context *context) * sha Error Code. */ int SHA256Input(SHA256Context *context, const uint8_t *message_array, - unsigned int length) + unsigned int length) { - if (!context) return shaNull; - if (!length) return shaSuccess; - if (!message_array) return shaNull; - if (context->Computed) return context->Corrupted = shaStateError; - if (context->Corrupted) return context->Corrupted; + if (!context) + return shaNull; + if (!length) + return shaSuccess; + if (!message_array) + return shaNull; + if (context->Computed) + return context->Corrupted = shaStateError; + if (context->Corrupted) + return context->Corrupted; - while (length--) { + while (length--) + { context->Message_Block[context->Message_Block_Index++] = - *message_array; + *message_array; if ((SHA224_256AddLength(context, 8) == shaSuccess) && - (context->Message_Block_Index == SHA256_Message_Block_Size)) + (context->Message_Block_Index == SHA256_Message_Block_Size)) SHA224_256ProcessMessageBlock(context); message_array++; } return context->Corrupted; - } /* @@ -276,24 +280,26 @@ int SHA256FinalBits(SHA256Context *context, /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, - /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE - }; + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE}; static uint8_t markbit[8] = { /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, - /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 - }; + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01}; - if (!context) return shaNull; - if (!length) return shaSuccess; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - if (length >= 8) return context->Corrupted = shaBadParam; + if (!context) + return shaNull; + if (!length) + return shaSuccess; + if (context->Corrupted) + return context->Corrupted; + if (context->Computed) + return context->Corrupted = shaStateError; + if (length >= 8) + return context->Corrupted = shaBadParam; SHA224_256AddLength(context, length); - SHA224_256Finalize(context, (uint8_t) - ((message_bits & masks[length]) | markbit[length])); + SHA224_256Finalize(context, (uint8_t)((message_bits & masks[length]) | markbit[length])); return context->Corrupted; } @@ -341,10 +347,11 @@ int SHA256Result(SHA256Context *context, */ static int SHA224_256Reset(SHA256Context *context, uint32_t *H0) { - if (!context) return shaNull; + if (!context) + return shaNull; context->Length_High = context->Length_Low = 0; - context->Message_Block_Index = 0; + context->Message_Block_Index = 0; context->Intermediate_Hash[0] = H0[0]; context->Intermediate_Hash[1] = H0[1]; @@ -355,7 +362,7 @@ static int SHA224_256Reset(SHA256Context *context, uint32_t *H0) context->Intermediate_Hash[6] = H0[6]; context->Intermediate_Hash[7] = H0[7]; - context->Computed = 0; + context->Computed = 0; context->Corrupted = shaSuccess; return shaSuccess; @@ -396,12 +403,11 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context) 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - }; - int t, t4; /* Loop counter */ - uint32_t temp1, temp2; /* Temporary word value */ - uint32_t W[64]; /* Word sequence */ - uint32_t A, B, C, D, E, F, G, H; /* Word buffers */ + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + int t, t4; /* Loop counter */ + uint32_t temp1, temp2; /* Temporary word value */ + uint32_t W[64]; /* Word sequence */ + uint32_t A, B, C, D, E, F, G, H; /* Word buffers */ /* * Initialize the first 16 words in the array W @@ -412,8 +418,8 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context) (((uint32_t)context->Message_Block[t4 + 2]) << 8) | (((uint32_t)context->Message_Block[t4 + 3])); for (t = 16; t < 64; t++) - W[t] = SHA256_sigma1(W[t-2]) + W[t-7] + - SHA256_sigma0(W[t-15]) + W[t-16]; + W[t] = SHA256_sigma1(W[t - 2]) + W[t - 7] + + SHA256_sigma0(W[t - 15]) + W[t - 16]; A = context->Intermediate_Hash[0]; B = context->Intermediate_Hash[1]; @@ -424,9 +430,10 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context) G = context->Intermediate_Hash[6]; H = context->Intermediate_Hash[7]; - for (t = 0; t < 64; t++) { - temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; - temp2 = SHA256_SIGMA0(A) + SHA_Maj(A,B,C); + for (t = 0; t < 64; t++) + { + temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E, F, G) + K[t] + W[t]; + temp2 = SHA256_SIGMA0(A) + SHA_Maj(A, B, C); H = G; G = F; F = E; @@ -468,14 +475,14 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context) * sha Error Code. */ static void SHA224_256Finalize(SHA256Context *context, - uint8_t Pad_Byte) + uint8_t Pad_Byte) { int i; SHA224_256PadMessage(context, Pad_Byte); /* message may be sensitive, so clear it out */ for (i = 0; i < SHA256_Message_Block_Size; ++i) context->Message_Block[i] = 0; - context->Length_High = 0; /* and clear length */ + context->Length_High = 0; /* and clear length */ context->Length_Low = 0; context->Computed = 1; } @@ -505,7 +512,7 @@ static void SHA224_256Finalize(SHA256Context *context, * Nothing. */ static void SHA224_256PadMessage(SHA256Context *context, - uint8_t Pad_Byte) + uint8_t Pad_Byte) { /* * Check to see if the current message block is too small to hold @@ -513,15 +520,17 @@ static void SHA224_256PadMessage(SHA256Context *context, * block, process it, and then continue padding into a second * block. */ - if (context->Message_Block_Index >= (SHA256_Message_Block_Size-8)) { + if (context->Message_Block_Index >= (SHA256_Message_Block_Size - 8)) + { context->Message_Block[context->Message_Block_Index++] = Pad_Byte; while (context->Message_Block_Index < SHA256_Message_Block_Size) context->Message_Block[context->Message_Block_Index++] = 0; SHA224_256ProcessMessageBlock(context); - } else + } + else context->Message_Block[context->Message_Block_Index++] = Pad_Byte; - while (context->Message_Block_Index < (SHA256_Message_Block_Size-8)) + while (context->Message_Block_Index < (SHA256_Message_Block_Size - 8)) context->Message_Block[context->Message_Block_Index++] = 0; /* @@ -561,21 +570,22 @@ static void SHA224_256PadMessage(SHA256Context *context, * sha Error Code. */ static int SHA224_256ResultN(SHA256Context *context, - uint8_t Message_Digest[ ], int HashSize) + uint8_t Message_Digest[], int HashSize) { int i; - if (!context) return shaNull; - if (!Message_Digest) return shaNull; - if (context->Corrupted) return context->Corrupted; + if (!context) + return shaNull; + if (!Message_Digest) + return shaNull; + if (context->Corrupted) + return context->Corrupted; if (!context->Computed) SHA224_256Finalize(context, 0x80); for (i = 0; i < HashSize; ++i) - Message_Digest[i] = (uint8_t) - (context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) )); + Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03))); return shaSuccess; } - diff --git a/nfq/crypto/usha.c b/nfq/crypto/usha.c index 861b4d0..d8b4683 100644 --- a/nfq/crypto/usha.c +++ b/nfq/crypto/usha.c @@ -30,12 +30,17 @@ */ int USHAReset(USHAContext *context, enum SHAversion whichSha) { - if (!context) return shaNull; + if (!context) + return shaNull; context->whichSha = whichSha; - switch (whichSha) { - case SHA224: return SHA224Reset((SHA224Context*)&context->ctx); - case SHA256: return SHA256Reset((SHA256Context*)&context->ctx); - default: return shaBadParam; + switch (whichSha) + { + case SHA224: + return SHA224Reset((SHA224Context *)&context->ctx); + case SHA256: + return SHA256Reset((SHA256Context *)&context->ctx); + default: + return shaBadParam; } } @@ -62,15 +67,18 @@ int USHAReset(USHAContext *context, enum SHAversion whichSha) int USHAInput(USHAContext *context, const uint8_t *bytes, unsigned int bytecount) { - if (!context) return shaNull; - switch (context->whichSha) { - case SHA224: - return SHA224Input((SHA224Context*)&context->ctx, bytes, - bytecount); - case SHA256: - return SHA256Input((SHA256Context*)&context->ctx, bytes, - bytecount); - default: return shaBadParam; + if (!context) + return shaNull; + switch (context->whichSha) + { + case SHA224: + return SHA224Input((SHA224Context *)&context->ctx, bytes, + bytecount); + case SHA256: + return SHA256Input((SHA256Context *)&context->ctx, bytes, + bytecount); + default: + return shaBadParam; } } @@ -96,15 +104,18 @@ int USHAInput(USHAContext *context, int USHAFinalBits(USHAContext *context, uint8_t bits, unsigned int bit_count) { - if (!context) return shaNull; - switch (context->whichSha) { - case SHA224: - return SHA224FinalBits((SHA224Context*)&context->ctx, bits, - bit_count); - case SHA256: - return SHA256FinalBits((SHA256Context*)&context->ctx, bits, - bit_count); - default: return shaBadParam; + if (!context) + return shaNull; + switch (context->whichSha) + { + case SHA224: + return SHA224FinalBits((SHA224Context *)&context->ctx, bits, + bit_count); + case SHA256: + return SHA256FinalBits((SHA256Context *)&context->ctx, bits, + bit_count); + default: + return shaBadParam; } } @@ -130,15 +141,18 @@ int USHAFinalBits(USHAContext *context, int USHAResult(USHAContext *context, uint8_t Message_Digest[USHAMaxHashSize]) { - if (!context) return shaNull; - switch (context->whichSha) { - case SHA224: - return SHA224Result((SHA224Context*)&context->ctx, - Message_Digest); - case SHA256: - return SHA256Result((SHA256Context*)&context->ctx, - Message_Digest); - default: return shaBadParam; + if (!context) + return shaNull; + switch (context->whichSha) + { + case SHA224: + return SHA224Result((SHA224Context *)&context->ctx, + Message_Digest); + case SHA256: + return SHA256Result((SHA256Context *)&context->ctx, + Message_Digest); + default: + return shaBadParam; } } @@ -159,10 +173,13 @@ int USHAResult(USHAContext *context, */ int USHABlockSize(enum SHAversion whichSha) { - switch (whichSha) { - case SHA224: return SHA224_Message_Block_Size; - default: - case SHA256: return SHA256_Message_Block_Size; + switch (whichSha) + { + case SHA224: + return SHA224_Message_Block_Size; + default: + case SHA256: + return SHA256_Message_Block_Size; } } @@ -183,9 +200,12 @@ int USHABlockSize(enum SHAversion whichSha) */ int USHAHashSize(enum SHAversion whichSha) { - switch (whichSha) { - case SHA224: return SHA224HashSize; - default: - case SHA256: return SHA256HashSize; + switch (whichSha) + { + case SHA224: + return SHA224HashSize; + default: + case SHA256: + return SHA256HashSize; } } diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index f008d02..302788a 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -11,7 +11,7 @@ #ifndef IP_NODEFRAG // for very old toolchains -#define IP_NODEFRAG 22 +#define IP_NODEFRAG 22 #endif #include "darkmagic.h" @@ -26,57 +26,59 @@ uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment) { - return htonl(ntohl(netorder_value)+cpuorder_increment); + return htonl(ntohl(netorder_value) + cpuorder_increment); } uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment) { - return htons(ntohs(netorder_value)+cpuorder_increment); + return htons(ntohs(netorder_value) + cpuorder_increment); } uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind) { - uint8_t *t = (uint8_t*)(tcp+1); - uint8_t *end = (uint8_t*)tcp + (tcp->th_off<<2); - while(tth_off << 2); + while (t < end) { - switch(*t) + switch (*t) { - case 0: // end + case 0: // end + return NULL; + case 1: // noop + t++; + break; + default: // kind,len,data + if ((t + 1) >= end || t[1] < 2 || (t + t[1]) > end) return NULL; - case 1: // noop - t++; - break; - default: // kind,len,data - if ((t+1)>=end || t[1]<2 || (t+t[1])>end) - return NULL; - if (*t==kind) - return t; - t+=t[1]; - break; + if (*t == kind) + return t; + t += t[1]; + break; } } return NULL; } uint32_t *tcp_find_timestamps(struct tcphdr *tcp) { - uint8_t *t = tcp_find_option(tcp,8); - return (t && t[1]==10) ? (uint32_t*)(t+2) : NULL; + uint8_t *t = tcp_find_option(tcp, 8); + return (t && t[1] == 10) ? (uint32_t *)(t + 2) : NULL; } uint8_t tcp_find_scale_factor(const struct tcphdr *tcp) { - uint8_t *scale = tcp_find_option((struct tcphdr*)tcp,3); // tcp option 3 - scale factor - if (scale && scale[1]==3) return scale[2]; + uint8_t *scale = tcp_find_option((struct tcphdr *)tcp, 3); // tcp option 3 - scale factor + if (scale && scale[1] == 3) + return scale[2]; return SCALE_NONE; } bool tcp_has_fastopen(const struct tcphdr *tcp) { uint8_t *opt; // new style RFC7413 - opt = tcp_find_option((struct tcphdr*)tcp, 34); - if (opt) return true; + opt = tcp_find_option((struct tcphdr *)tcp, 34); + if (opt) + return true; // old style RFC6994 - opt = tcp_find_option((struct tcphdr*)tcp, 254); - return opt && opt[1]>=4 && opt[2]==0xF9 && opt[3]==0x89; + opt = tcp_find_option((struct tcphdr *)tcp, 254); + return opt && opt[1] >= 4 && opt[2] == 0xF9 && opt[3] == 0x89; } // n prefix (nsport, nwsize) means network byte order @@ -90,63 +92,67 @@ static void fill_tcphdr( uint32_t badseq_ack_increment, uint16_t data_len) { - char *tcpopt = (char*)(tcp+1); - uint8_t t=0; + char *tcpopt = (char *)(tcp + 1); + uint8_t t = 0; - memset(tcp,0,sizeof(*tcp)); + memset(tcp, 0, sizeof(*tcp)); tcp->th_sport = nsport; tcp->th_dport = ndport; if (fooling & FOOL_BADSEQ) { - tcp->th_seq = net32_add(nseq,badseq_increment); - tcp->th_ack = net32_add(nack_seq,badseq_ack_increment); + tcp->th_seq = net32_add(nseq, badseq_increment); + tcp->th_ack = net32_add(nack_seq, badseq_ack_increment); } else { tcp->th_seq = nseq; tcp->th_ack = nack_seq; } - tcp->th_off = 5; - if ((fooling & FOOL_DATANOACK) && !(tcp_flags & (TH_SYN|TH_RST)) && data_len) + tcp->th_off = 5; + if ((fooling & FOOL_DATANOACK) && !(tcp_flags & (TH_SYN | TH_RST)) && data_len) tcp_flags &= ~TH_ACK; - *((uint8_t*)tcp+13)= tcp_flags; - tcp->th_win = nwsize; + *((uint8_t *)tcp + 13) = tcp_flags; + tcp->th_win = nwsize; if (fooling & FOOL_MD5SIG) { tcpopt[0] = 19; // kind tcpopt[1] = 18; // len - *(uint32_t*)(tcpopt+2)=random(); - *(uint32_t*)(tcpopt+6)=random(); - *(uint32_t*)(tcpopt+10)=random(); - *(uint32_t*)(tcpopt+14)=random(); - t=18; + *(uint32_t *)(tcpopt + 2) = random(); + *(uint32_t *)(tcpopt + 6) = random(); + *(uint32_t *)(tcpopt + 10) = random(); + *(uint32_t *)(tcpopt + 14) = random(); + t = 18; } if (timestamps || (fooling & FOOL_TS)) { - tcpopt[t] = 8; // kind - tcpopt[t+1] = 10; // len + tcpopt[t] = 8; // kind + tcpopt[t + 1] = 10; // len // forge only TSecr if orig timestamp is present - *(uint32_t*)(tcpopt+t+2) = timestamps ? timestamps[0] : -1; - *(uint32_t*)(tcpopt+t+6) = (timestamps && !(fooling & FOOL_TS)) ? timestamps[1] : -1; - t+=10; + *(uint32_t *)(tcpopt + t + 2) = timestamps ? timestamps[0] : -1; + *(uint32_t *)(tcpopt + t + 6) = (timestamps && !(fooling & FOOL_TS)) ? timestamps[1] : -1; + t += 10; } - if (scale_factor!=SCALE_NONE) + if (scale_factor != SCALE_NONE) { - tcpopt[t++]=3; - tcpopt[t++]=3; - tcpopt[t++]=scale_factor; + tcpopt[t++] = 3; + tcpopt[t++] = 3; + tcpopt[t++] = scale_factor; } - while (t&3) tcpopt[t++]=1; // noop - tcp->th_off += t>>2; + while (t & 3) + tcpopt[t++] = 1; // noop + tcp->th_off += t >> 2; tcp->th_sum = 0; } static uint16_t tcpopt_len(uint32_t fooling, const uint32_t *timestamps, uint8_t scale_factor) { - uint16_t t=0; - if (fooling & FOOL_MD5SIG) t=18; - if ((fooling & FOOL_TS) || timestamps) t+=10; - if (scale_factor!=SCALE_NONE) t+=3; - return (t+3)&~3; + uint16_t t = 0; + if (fooling & FOOL_MD5SIG) + t = 18; + if ((fooling & FOOL_TS) || timestamps) + t += 10; + if (scale_factor != SCALE_NONE) + t += 3; + return (t + 3) & ~3; } // n prefix (nsport, nwsize) means network byte order @@ -154,7 +160,7 @@ static void fill_udphdr(struct udphdr *udp, uint16_t nsport, uint16_t ndport, ui { udp->uh_sport = nsport; udp->uh_dport = ndport; - udp->uh_ulen = htons(len_payload+sizeof(struct udphdr)); + udp->uh_ulen = htons(len_payload + sizeof(struct udphdr)); udp->uh_sum = 0; } @@ -196,21 +202,23 @@ bool prepare_tcp_segment4( const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor); + uint16_t tcpoptlen = tcpopt_len(fooling, timestamps, scale_factor); uint16_t ip_payload_len = sizeof(struct tcphdr) + tcpoptlen + len; uint16_t pktlen = sizeof(struct ip) + ip_payload_len; - if (pktlen>*buflen) return false; + if (pktlen > *buflen) + return false; - struct ip *ip = (struct ip*)buf; - struct tcphdr *tcp = (struct tcphdr*)(ip+1); - uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen; + struct ip *ip = (struct ip *)buf; + struct tcphdr *tcp = (struct tcphdr *)(ip + 1); + uint8_t *payload = (uint8_t *)(tcp + 1) + tcpoptlen; fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, ttl); - fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len); + fill_tcphdr(tcp, fooling, tcp_flags, nseq, nack_seq, src->sin_port, dst->sin_port, nwsize, scale_factor, timestamps, badseq_increment, badseq_ack_increment, len); - memcpy(payload,data,len); - tcp4_fix_checksum(tcp,ip_payload_len,&ip->ip_src,&ip->ip_dst); - if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF); + memcpy(payload, data, len); + tcp4_fix_checksum(tcp, ip_payload_len, &ip->ip_src, &ip->ip_dst); + if (fooling & FOOL_BADSUM) + tcp->th_sum ^= htons(0xBEAF); *buflen = pktlen; return true; @@ -230,31 +238,32 @@ bool prepare_tcp_segment6( const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor); + uint16_t tcpoptlen = tcpopt_len(fooling, timestamps, scale_factor); uint16_t transport_payload_len = sizeof(struct tcphdr) + tcpoptlen + len; uint16_t ip_payload_len = transport_payload_len + - 8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) + - 16*!!(fooling & FOOL_HOPBYHOP2) + - 8*!!(fooling & FOOL_DESTOPT) + - 8*!!(fooling & FOOL_IPFRAG1); + 8 * !!((fooling & (FOOL_HOPBYHOP | FOOL_HOPBYHOP2)) == FOOL_HOPBYHOP) + + 16 * !!(fooling & FOOL_HOPBYHOP2) + + 8 * !!(fooling & FOOL_DESTOPT) + + 8 * !!(fooling & FOOL_IPFRAG1); uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len; - if (pktlen>*buflen) return false; + if (pktlen > *buflen) + return false; - struct ip6_hdr *ip6 = (struct ip6_hdr*)buf; - struct tcphdr *tcp = (struct tcphdr*)(ip6+1); + struct ip6_hdr *ip6 = (struct ip6_hdr *)buf; + struct tcphdr *tcp = (struct tcphdr *)(ip6 + 1); uint8_t proto = IPPROTO_TCP, *nexttype = NULL; - if (fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2)) + if (fooling & (FOOL_HOPBYHOP | FOOL_HOPBYHOP2)) { - struct ip6_hbh *hbh = (struct ip6_hbh*)tcp; - tcp = (struct tcphdr*)((uint8_t*)tcp+8); - memset(hbh,0,8); + struct ip6_hbh *hbh = (struct ip6_hbh *)tcp; + tcp = (struct tcphdr *)((uint8_t *)tcp + 8); + memset(hbh, 0, 8); // extra HOPBYHOP header. standard violation if (fooling & FOOL_HOPBYHOP2) { - hbh = (struct ip6_hbh*)tcp; - tcp = (struct tcphdr*)((uint8_t*)tcp+8); - memset(hbh,0,8); + hbh = (struct ip6_hbh *)tcp; + tcp = (struct tcphdr *)((uint8_t *)tcp + 8); + memset(hbh, 0, 8); } hbh->ip6h_nxt = IPPROTO_TCP; nexttype = &hbh->ip6h_nxt; @@ -262,9 +271,9 @@ bool prepare_tcp_segment6( } if (fooling & FOOL_DESTOPT) { - struct ip6_dest *dest = (struct ip6_dest*)tcp; - tcp = (struct tcphdr*)((uint8_t*)tcp+8); - memset(dest,0,8); + struct ip6_dest *dest = (struct ip6_dest *)tcp; + tcp = (struct tcphdr *)((uint8_t *)tcp + 8); + memset(dest, 0, 8); dest->ip6d_nxt = IPPROTO_TCP; if (nexttype) *nexttype = IPPROTO_DSTOPTS; @@ -274,10 +283,10 @@ bool prepare_tcp_segment6( } if (fooling & FOOL_IPFRAG1) { - struct ip6_frag *frag = (struct ip6_frag*)tcp; - tcp = (struct tcphdr*)((uint8_t*)tcp+sizeof(struct ip6_frag)); + struct ip6_frag *frag = (struct ip6_frag *)tcp; + tcp = (struct tcphdr *)((uint8_t *)tcp + sizeof(struct ip6_frag)); frag->ip6f_nxt = IPPROTO_TCP; - frag->ip6f_ident = htonl(1+random()%0xFFFFFFFF); + frag->ip6f_ident = htonl(1 + random() % 0xFFFFFFFF); frag->ip6f_reserved = 0; frag->ip6f_offlg = 0; if (nexttype) @@ -286,14 +295,15 @@ bool prepare_tcp_segment6( proto = IPPROTO_FRAGMENT; } - uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen; + uint8_t *payload = (uint8_t *)(tcp + 1) + tcpoptlen; fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl); - fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len); + fill_tcphdr(tcp, fooling, tcp_flags, nseq, nack_seq, src->sin6_port, dst->sin6_port, nwsize, scale_factor, timestamps, badseq_increment, badseq_ack_increment, len); - memcpy(payload,data,len); - tcp6_fix_checksum(tcp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst); - if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF); + memcpy(payload, data, len); + tcp6_fix_checksum(tcp, transport_payload_len, &ip6->ip6_src, &ip6->ip6_dst); + if (fooling & FOOL_BADSUM) + tcp->th_sum ^= htons(0xBEAF); *buflen = pktlen; return true; @@ -313,14 +323,10 @@ bool prepare_tcp_segment( const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ? - prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) : - (src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ? - prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) : - false; + return (src->sa_family == AF_INET && dst->sa_family == AF_INET) ? prepare_tcp_segment4((struct sockaddr_in *)src, (struct sockaddr_in *)dst, tcp_flags, nseq, nack_seq, nwsize, scale_factor, timestamps, ttl, fooling, badseq_increment, badseq_ack_increment, data, len, buf, buflen) : (src->sa_family == AF_INET6 && dst->sa_family == AF_INET6) ? prepare_tcp_segment6((struct sockaddr_in6 *)src, (struct sockaddr_in6 *)dst, tcp_flags, nseq, nack_seq, nwsize, scale_factor, timestamps, ttl, fooling, badseq_increment, badseq_ack_increment, data, len, buf, buflen) + : false; } - // padlen<0 means payload shrinking bool prepare_udp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, @@ -331,33 +337,36 @@ bool prepare_udp_segment4( const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - if ((len+padlen)<=0) padlen=-(int)len+1; // do not allow payload to be less that 1 byte - if ((len+padlen)>0xFFFF) padlen=0xFFFF-len; // do not allow payload size to exceed u16 range - if (padlen<0) + if ((len + padlen) <= 0) + padlen = -(int)len + 1; // do not allow payload to be less that 1 byte + if ((len + padlen) > 0xFFFF) + padlen = 0xFFFF - len; // do not allow payload size to exceed u16 range + if (padlen < 0) { - len+=padlen; - padlen=0; + len += padlen; + padlen = 0; } uint16_t datalen = (uint16_t)(len + padlen); uint16_t ip_payload_len = sizeof(struct udphdr) + datalen; uint16_t pktlen = sizeof(struct ip) + ip_payload_len; - if (pktlen>*buflen) return false; - - struct ip *ip = (struct ip*)buf; - struct udphdr *udp = (struct udphdr*)(ip+1); - uint8_t *payload = (uint8_t*)(udp+1); + if (pktlen > *buflen) + return false; + struct ip *ip = (struct ip *)buf; + struct udphdr *udp = (struct udphdr *)(ip + 1); + uint8_t *payload = (uint8_t *)(udp + 1); fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, ttl); fill_udphdr(udp, src->sin_port, dst->sin_port, datalen); - memcpy(payload,data,len); + memcpy(payload, data, len); if (padding) - fill_pattern(payload+len,padlen,padding,padding_size); + fill_pattern(payload + len, padlen, padding, padding_size); else - memset(payload+len,0,padlen); - udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst); - if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF); + memset(payload + len, 0, padlen); + udp4_fix_checksum(udp, ip_payload_len, &ip->ip_src, &ip->ip_dst); + if (fooling & FOOL_BADSUM) + udp->uh_sum ^= htons(0xBEAF); *buflen = pktlen; return true; @@ -371,38 +380,41 @@ bool prepare_udp_segment6( const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - if ((len+padlen)<=0) padlen=-(int)len+1; // do not allow payload to be less that 1 byte - if ((len+padlen)>0xFFFF) padlen=0xFFFF-len; // do not allow payload size to exceed u16 range - if (padlen<0) + if ((len + padlen) <= 0) + padlen = -(int)len + 1; // do not allow payload to be less that 1 byte + if ((len + padlen) > 0xFFFF) + padlen = 0xFFFF - len; // do not allow payload size to exceed u16 range + if (padlen < 0) { - len+=padlen; - padlen=0; + len += padlen; + padlen = 0; } uint16_t datalen = (uint16_t)(len + padlen); uint16_t transport_payload_len = sizeof(struct udphdr) + datalen; uint16_t ip_payload_len = transport_payload_len + - 8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) + - 16*!!(fooling & FOOL_HOPBYHOP2) + - 8*!!(fooling & FOOL_DESTOPT) + - 8*!!(fooling & FOOL_IPFRAG1); + 8 * !!((fooling & (FOOL_HOPBYHOP | FOOL_HOPBYHOP2)) == FOOL_HOPBYHOP) + + 16 * !!(fooling & FOOL_HOPBYHOP2) + + 8 * !!(fooling & FOOL_DESTOPT) + + 8 * !!(fooling & FOOL_IPFRAG1); uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len; - if (pktlen>*buflen) return false; + if (pktlen > *buflen) + return false; - struct ip6_hdr *ip6 = (struct ip6_hdr*)buf; - struct udphdr *udp = (struct udphdr*)(ip6+1); + struct ip6_hdr *ip6 = (struct ip6_hdr *)buf; + struct udphdr *udp = (struct udphdr *)(ip6 + 1); uint8_t proto = IPPROTO_UDP, *nexttype = NULL; - if (fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2)) + if (fooling & (FOOL_HOPBYHOP | FOOL_HOPBYHOP2)) { - struct ip6_hbh *hbh = (struct ip6_hbh*)udp; - udp = (struct udphdr*)((uint8_t*)udp+8); - memset(hbh,0,8); + struct ip6_hbh *hbh = (struct ip6_hbh *)udp; + udp = (struct udphdr *)((uint8_t *)udp + 8); + memset(hbh, 0, 8); // extra HOPBYHOP header. standard violation if (fooling & FOOL_HOPBYHOP2) { - hbh = (struct ip6_hbh*)udp; - udp = (struct udphdr*)((uint8_t*)udp+8); - memset(hbh,0,8); + hbh = (struct ip6_hbh *)udp; + udp = (struct udphdr *)((uint8_t *)udp + 8); + memset(hbh, 0, 8); } hbh->ip6h_nxt = IPPROTO_UDP; nexttype = &hbh->ip6h_nxt; @@ -410,9 +422,9 @@ bool prepare_udp_segment6( } if (fooling & FOOL_DESTOPT) { - struct ip6_dest *dest = (struct ip6_dest*)udp; - udp = (struct udphdr*)((uint8_t*)udp+8); - memset(dest,0,8); + struct ip6_dest *dest = (struct ip6_dest *)udp; + udp = (struct udphdr *)((uint8_t *)udp + 8); + memset(dest, 0, 8); dest->ip6d_nxt = IPPROTO_UDP; if (nexttype) *nexttype = IPPROTO_DSTOPTS; @@ -422,10 +434,10 @@ bool prepare_udp_segment6( } if (fooling & FOOL_IPFRAG1) { - struct ip6_frag *frag = (struct ip6_frag*)udp; - udp = (struct udphdr*)((uint8_t*)udp+sizeof(struct ip6_frag)); + struct ip6_frag *frag = (struct ip6_frag *)udp; + udp = (struct udphdr *)((uint8_t *)udp + sizeof(struct ip6_frag)); frag->ip6f_nxt = IPPROTO_UDP; - frag->ip6f_ident = htonl(1+random()%0xFFFFFFFF); + frag->ip6f_ident = htonl(1 + random() % 0xFFFFFFFF); frag->ip6f_reserved = 0; frag->ip6f_offlg = 0; if (nexttype) @@ -434,18 +446,19 @@ bool prepare_udp_segment6( proto = IPPROTO_FRAGMENT; } - uint8_t *payload = (uint8_t*)(udp+1); + uint8_t *payload = (uint8_t *)(udp + 1); fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl); fill_udphdr(udp, src->sin6_port, dst->sin6_port, datalen); - memcpy(payload,data,len); + memcpy(payload, data, len); if (padding) - fill_pattern(payload+len,padlen,padding,padding_size); + fill_pattern(payload + len, padlen, padding, padding_size); else - memset(payload+len,0,padlen); - udp6_fix_checksum(udp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst); - if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF); + memset(payload + len, 0, padlen); + udp6_fix_checksum(udp, transport_payload_len, &ip6->ip6_src, &ip6->ip6_dst); + if (fooling & FOOL_BADSUM) + udp->uh_sum ^= htons(0xBEAF); *buflen = pktlen; return true; @@ -459,22 +472,19 @@ bool prepare_udp_segment( const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ? - prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,ttl,fooling,padding,padding_size,padlen,data,len,buf,buflen) : - (src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ? - prepare_udp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,ttl,fooling,padding,padding_size,padlen,data,len,buf,buflen) : - false; + return (src->sa_family == AF_INET && dst->sa_family == AF_INET) ? prepare_udp_segment4((struct sockaddr_in *)src, (struct sockaddr_in *)dst, ttl, fooling, padding, padding_size, padlen, data, len, buf, buflen) : (src->sa_family == AF_INET6 && dst->sa_family == AF_INET6) ? prepare_udp_segment6((struct sockaddr_in6 *)src, (struct sockaddr_in6 *)dst, ttl, fooling, padding, padding_size, padlen, data, len, buf, buflen) + : false; } bool ip6_insert_simple_hdr(uint8_t type, uint8_t *data_pkt, size_t len_pkt, uint8_t *buf, size_t *buflen) { - if ((len_pkt+8)<=*buflen && len_pkt>=sizeof(struct ip6_hdr)) + if ((len_pkt + 8) <= *buflen && len_pkt >= sizeof(struct ip6_hdr)) { struct ip6_hdr *ip6 = (struct ip6_hdr *)buf; - struct ip6_ext *hdr = (struct ip6_ext*)(ip6+1); - *ip6 = *(struct ip6_hdr*)data_pkt; - memset(hdr,0,8); - memcpy((uint8_t*)hdr+8, data_pkt+sizeof(struct ip6_hdr), len_pkt-sizeof(struct ip6_hdr)); + struct ip6_ext *hdr = (struct ip6_ext *)(ip6 + 1); + *ip6 = *(struct ip6_hdr *)data_pkt; + memset(hdr, 0, 8); + memcpy((uint8_t *)hdr + 8, data_pkt + sizeof(struct ip6_hdr), len_pkt - sizeof(struct ip6_hdr)); hdr->ip6e_nxt = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt; ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = type; ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = net16_add(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen, 8); @@ -493,26 +503,31 @@ bool ip_frag4( { uint16_t hdrlen, payload_len; // frag_pos must be 8-byte aligned - if (frag_pos & 7 || pkt_size < sizeof(struct ip)) return false; + if (frag_pos & 7 || pkt_size < sizeof(struct ip)) + return false; payload_len = htons(((struct ip *)pkt)->ip_len); - hdrlen = ((struct ip *)pkt)->ip_hl<<2; - if (payload_len>pkt_size || hdrlen>pkt_size || hdrlen>payload_len) return false; + hdrlen = ((struct ip *)pkt)->ip_hl << 2; + if (payload_len > pkt_size || hdrlen > pkt_size || hdrlen > payload_len) + return false; payload_len -= hdrlen; - if (frag_pos>=payload_len || *pkt1_size<(hdrlen+frag_pos) || *pkt2_size<(hdrlen+payload_len-frag_pos)) return false; + if (frag_pos >= payload_len || *pkt1_size < (hdrlen + frag_pos) || *pkt2_size < (hdrlen + payload_len - frag_pos)) + return false; - memcpy(pkt1, pkt, hdrlen+frag_pos); - ((struct ip*)pkt1)->ip_off = htons(IP_MF); - ((struct ip*)pkt1)->ip_len = htons(hdrlen+frag_pos); - if (ident!=(uint32_t)-1) ((struct ip*)pkt1)->ip_id = (uint16_t)ident; - *pkt1_size=hdrlen+frag_pos; + memcpy(pkt1, pkt, hdrlen + frag_pos); + ((struct ip *)pkt1)->ip_off = htons(IP_MF); + ((struct ip *)pkt1)->ip_len = htons(hdrlen + frag_pos); + if (ident != (uint32_t)-1) + ((struct ip *)pkt1)->ip_id = (uint16_t)ident; + *pkt1_size = hdrlen + frag_pos; ip4_fix_checksum((struct ip *)pkt1); memcpy(pkt2, pkt, hdrlen); - memcpy(pkt2+hdrlen, pkt+hdrlen+frag_pos, payload_len-frag_pos); - ((struct ip*)pkt2)->ip_off = htons((uint16_t)frag_pos>>3 & IP_OFFMASK); - ((struct ip*)pkt2)->ip_len = htons(hdrlen+payload_len-frag_pos); - if (ident!=(uint32_t)-1) ((struct ip*)pkt2)->ip_id = (uint16_t)ident; - *pkt2_size=hdrlen+payload_len-frag_pos; + memcpy(pkt2 + hdrlen, pkt + hdrlen + frag_pos, payload_len - frag_pos); + ((struct ip *)pkt2)->ip_off = htons((uint16_t)frag_pos >> 3 & IP_OFFMASK); + ((struct ip *)pkt2)->ip_len = htons(hdrlen + payload_len - frag_pos); + if (ident != (uint32_t)-1) + ((struct ip *)pkt2)->ip_id = (uint16_t)ident; + *pkt2_size = hdrlen + payload_len - frag_pos; ip4_fix_checksum((struct ip *)pkt2); return true; @@ -529,43 +544,45 @@ bool ip_frag6( struct ip6_frag *frag; const uint8_t *payload; - if (frag_pos & 7 || pkt_size < sizeof(struct ip6_hdr)) return false; - payload_len = sizeof(struct ip6_hdr) + htons(((struct ip6_hdr*)pkt)->ip6_ctlun.ip6_un1.ip6_un1_plen); - if (pkt_size < payload_len) return false; + if (frag_pos & 7 || pkt_size < sizeof(struct ip6_hdr)) + return false; + payload_len = sizeof(struct ip6_hdr) + htons(((struct ip6_hdr *)pkt)->ip6_ctlun.ip6_un1.ip6_un1_plen); + if (pkt_size < payload_len) + return false; payload = pkt; - proto_skip_ipv6((uint8_t**)&payload, &payload_len, &proto, &last_header_type); + proto_skip_ipv6((uint8_t **)&payload, &payload_len, &proto, &last_header_type); unfragmentable = payload - pkt; - //printf("pkt_size=%zu FRAG_POS=%zu payload_len=%zu unfragmentable=%zu dh=%zu\n",pkt_size,frag_pos,payload_len,unfragmentable,last_header_type - pkt); + // printf("pkt_size=%zu FRAG_POS=%zu payload_len=%zu unfragmentable=%zu dh=%zu\n",pkt_size,frag_pos,payload_len,unfragmentable,last_header_type - pkt); - if (frag_pos>=payload_len || - *pkt1_size<(unfragmentable + sizeof(struct ip6_frag) + frag_pos) || - *pkt2_size<(unfragmentable + sizeof(struct ip6_frag) + payload_len - frag_pos)) + if (frag_pos >= payload_len || + *pkt1_size < (unfragmentable + sizeof(struct ip6_frag) + frag_pos) || + *pkt2_size < (unfragmentable + sizeof(struct ip6_frag) + payload_len - frag_pos)) { return false; } memcpy(pkt1, pkt, unfragmentable); - ((struct ip6_hdr*)pkt1)->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(unfragmentable - sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + frag_pos); + ((struct ip6_hdr *)pkt1)->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(unfragmentable - sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + frag_pos); pkt1[last_header_type - pkt] = IPPROTO_FRAGMENT; - frag = (struct ip6_frag*)(pkt1 + unfragmentable); + frag = (struct ip6_frag *)(pkt1 + unfragmentable); frag->ip6f_nxt = proto; frag->ip6f_reserved = 0; frag->ip6f_offlg = IP6F_MORE_FRAG; frag->ip6f_ident = ident; - memcpy(frag+1, pkt + unfragmentable, frag_pos); + memcpy(frag + 1, pkt + unfragmentable, frag_pos); *pkt1_size = unfragmentable + sizeof(struct ip6_frag) + frag_pos; memcpy(pkt2, pkt, sizeof(struct ip6_hdr)); - ((struct ip6_hdr*)pkt2)->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(unfragmentable - sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + payload_len - frag_pos); + ((struct ip6_hdr *)pkt2)->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(unfragmentable - sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + payload_len - frag_pos); pkt2[last_header_type - pkt] = IPPROTO_FRAGMENT; - frag = (struct ip6_frag*)(pkt2 + unfragmentable); + frag = (struct ip6_frag *)(pkt2 + unfragmentable); frag->ip6f_nxt = proto; frag->ip6f_reserved = 0; frag->ip6f_offlg = htons(frag_pos); frag->ip6f_ident = ident; - memcpy(frag+1, pkt + unfragmentable + frag_pos, payload_len - frag_pos); + memcpy(frag + 1, pkt + unfragmentable + frag_pos, payload_len - frag_pos); *pkt2_size = unfragmentable + sizeof(struct ip6_frag) + payload_len - frag_pos; return true; @@ -576,29 +593,36 @@ bool ip_frag( uint8_t *pkt1, size_t *pkt1_size, uint8_t *pkt2, size_t *pkt2_size) { - if (proto_check_ipv4(pkt,pkt_size)) - return ip_frag4(pkt,pkt_size,frag_pos,ident,pkt1,pkt1_size,pkt2,pkt2_size); - else if (proto_check_ipv6(pkt,pkt_size)) - return ip_frag6(pkt,pkt_size,frag_pos,ident,pkt1,pkt1_size,pkt2,pkt2_size); + if (proto_check_ipv4(pkt, pkt_size)) + return ip_frag4(pkt, pkt_size, frag_pos, ident, pkt1, pkt1_size, pkt2, pkt2_size); + else if (proto_check_ipv6(pkt, pkt_size)) + return ip_frag6(pkt, pkt_size, frag_pos, ident, pkt1, pkt1_size, pkt2, pkt2_size); else return false; } void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl) { - if (ip) ip->ip_ttl = ttl; - if (ip6) ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl; + if (ip) + ip->ip_ttl = ttl; + if (ip6) + ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl; } - void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport) { - if (sport) *sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0); - if (dport) *dport = htons(tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0); - if (proto) *proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP : -1; + if (sport) + *sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport + : 0); + if (dport) + *dport = htons(tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport + : 0); + if (proto) + *proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP + : -1; } -void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst) +void extract_endpoints(const struct ip *ip, const struct ip6_hdr *ip6hdr, const struct tcphdr *tcphdr, const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst) { if (ip) { @@ -606,17 +630,19 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st if (dst) { - si = (struct sockaddr_in*)dst; + si = (struct sockaddr_in *)dst; si->sin_family = AF_INET; - si->sin_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0; + si->sin_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport + : 0; si->sin_addr = ip->ip_dst; } if (src) { - si = (struct sockaddr_in*)src; + si = (struct sockaddr_in *)src; si->sin_family = AF_INET; - si->sin_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0; + si->sin_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport + : 0; si->sin_addr = ip->ip_src; } } @@ -626,9 +652,10 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st if (dst) { - si = (struct sockaddr_in6*)dst; + si = (struct sockaddr_in6 *)dst; si->sin6_family = AF_INET6; - si->sin6_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0; + si->sin6_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport + : 0; si->sin6_addr = ip6hdr->ip6_dst; si->sin6_flowinfo = 0; si->sin6_scope_id = 0; @@ -636,9 +663,10 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st if (src) { - si = (struct sockaddr_in6*)src; + si = (struct sockaddr_in6 *)src; si->sin6_family = AF_INET6; - si->sin6_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0; + si->sin6_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport + : 0; si->sin6_addr = ip6hdr->ip6_src; si->sin6_flowinfo = 0; si->sin6_scope_id = 0; @@ -648,134 +676,140 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st const char *proto_name(uint8_t proto) { - switch(proto) + switch (proto) { - case IPPROTO_TCP: - return "tcp"; - case IPPROTO_UDP: - return "udp"; - case IPPROTO_ICMP: - return "icmp"; - case IPPROTO_ICMPV6: - return "icmp6"; - case IPPROTO_IGMP: - return "igmp"; - case IPPROTO_ESP: - return "esp"; - case IPPROTO_AH: - return "ah"; - case IPPROTO_IPV6: - return "6in4"; - case IPPROTO_IPIP: - return "4in4"; + case IPPROTO_TCP: + return "tcp"; + case IPPROTO_UDP: + return "udp"; + case IPPROTO_ICMP: + return "icmp"; + case IPPROTO_ICMPV6: + return "icmp6"; + case IPPROTO_IGMP: + return "igmp"; + case IPPROTO_ESP: + return "esp"; + case IPPROTO_AH: + return "ah"; + case IPPROTO_IPV6: + return "6in4"; + case IPPROTO_IPIP: + return "4in4"; #ifdef IPPROTO_GRE - case IPPROTO_GRE: - return "gre"; + case IPPROTO_GRE: + return "gre"; #endif #ifdef IPPROTO_SCTP - case IPPROTO_SCTP: - return "sctp"; + case IPPROTO_SCTP: + return "sctp"; #endif - default: - return NULL; + default: + return NULL; } } static void str_proto_name(char *s, size_t s_len, uint8_t proto) { const char *name = proto_name(proto); if (name) - snprintf(s,s_len,"%s",name); + snprintf(s, s_len, "%s", name); else - snprintf(s,s_len,"%u",proto); + snprintf(s, s_len, "%u", proto); } uint16_t family_from_proto(uint8_t l3proto) { - switch(l3proto) + switch (l3proto) { - case IPPROTO_IP: return AF_INET; - case IPPROTO_IPV6: return AF_INET6; - default: return -1; + case IPPROTO_IP: + return AF_INET; + case IPPROTO_IPV6: + return AF_INET6; + default: + return -1; } } -static void str_srcdst_ip(char *s, size_t s_len, const void *saddr,const void *daddr) +static void str_srcdst_ip(char *s, size_t s_len, const void *saddr, const void *daddr) { - char s_ip[16],d_ip[16]; - *s_ip=*d_ip=0; + char s_ip[16], d_ip[16]; + *s_ip = *d_ip = 0; inet_ntop(AF_INET, saddr, s_ip, sizeof(s_ip)); inet_ntop(AF_INET, daddr, d_ip, sizeof(d_ip)); - snprintf(s,s_len,"%s => %s",s_ip,d_ip); + snprintf(s, s_len, "%s => %s", s_ip, d_ip); } void str_ip(char *s, size_t s_len, const struct ip *ip) { - char ss[35],s_proto[16]; - str_srcdst_ip(ss,sizeof(ss),&ip->ip_src,&ip->ip_dst); - str_proto_name(s_proto,sizeof(s_proto),ip->ip_p); - snprintf(s,s_len,"%s proto=%s ttl=%u",ss,s_proto,ip->ip_ttl); + char ss[35], s_proto[16]; + str_srcdst_ip(ss, sizeof(ss), &ip->ip_src, &ip->ip_dst); + str_proto_name(s_proto, sizeof(s_proto), ip->ip_p); + snprintf(s, s_len, "%s proto=%s ttl=%u", ss, s_proto, ip->ip_ttl); } void print_ip(const struct ip *ip) { char s[66]; - str_ip(s,sizeof(s),ip); - printf("%s",s); + str_ip(s, sizeof(s), ip); + printf("%s", s); } -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) { - char s_ip[40],d_ip[40]; - *s_ip=*d_ip=0; + char s_ip[40], d_ip[40]; + *s_ip = *d_ip = 0; inet_ntop(AF_INET6, saddr, s_ip, sizeof(s_ip)); inet_ntop(AF_INET6, daddr, d_ip, sizeof(d_ip)); - snprintf(s,s_len,"%s => %s",s_ip,d_ip); + snprintf(s, s_len, "%s => %s", s_ip, d_ip); } void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto) { - char ss[83],s_proto[16]; - str_srcdst_ip6(ss,sizeof(ss),&ip6hdr->ip6_src,&ip6hdr->ip6_dst); - str_proto_name(s_proto,sizeof(s_proto),proto); - snprintf(s,s_len,"%s proto=%s ttl=%u",ss,s_proto,ip6hdr->ip6_hlim); + char ss[83], s_proto[16]; + str_srcdst_ip6(ss, sizeof(ss), &ip6hdr->ip6_src, &ip6hdr->ip6_dst); + str_proto_name(s_proto, sizeof(s_proto), proto); + snprintf(s, s_len, "%s proto=%s ttl=%u", ss, s_proto, ip6hdr->ip6_hlim); } void print_ip6hdr(const struct ip6_hdr *ip6hdr, uint8_t proto) { char s[128]; - str_ip6hdr(s,sizeof(s),ip6hdr,proto); - printf("%s",s); + str_ip6hdr(s, sizeof(s), ip6hdr, proto); + printf("%s", s); } void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr) { - char flags[7],*f=flags; - if (tcphdr->th_flags & TH_SYN) *f++='S'; - if (tcphdr->th_flags & TH_ACK) *f++='A'; - if (tcphdr->th_flags & TH_RST) *f++='R'; - if (tcphdr->th_flags & TH_FIN) *f++='F'; - if (tcphdr->th_flags & TH_PUSH) *f++='P'; - if (tcphdr->th_flags & TH_URG) *f++='U'; - *f=0; - snprintf(s,s_len,"sport=%u dport=%u flags=%s seq=%u ack_seq=%u",htons(tcphdr->th_sport),htons(tcphdr->th_dport),flags,htonl(tcphdr->th_seq),htonl(tcphdr->th_ack)); + char flags[7], *f = flags; + if (tcphdr->th_flags & TH_SYN) + *f++ = 'S'; + if (tcphdr->th_flags & TH_ACK) + *f++ = 'A'; + if (tcphdr->th_flags & TH_RST) + *f++ = 'R'; + if (tcphdr->th_flags & TH_FIN) + *f++ = 'F'; + if (tcphdr->th_flags & TH_PUSH) + *f++ = 'P'; + if (tcphdr->th_flags & TH_URG) + *f++ = 'U'; + *f = 0; + snprintf(s, s_len, "sport=%u dport=%u flags=%s seq=%u ack_seq=%u", htons(tcphdr->th_sport), htons(tcphdr->th_dport), flags, htonl(tcphdr->th_seq), htonl(tcphdr->th_ack)); } void print_tcphdr(const struct tcphdr *tcphdr) { char s[80]; - str_tcphdr(s,sizeof(s),tcphdr); - printf("%s",s); + str_tcphdr(s, sizeof(s), tcphdr); + printf("%s", s); } void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr) { - snprintf(s,s_len,"sport=%u dport=%u",htons(udphdr->uh_sport),htons(udphdr->uh_dport)); + snprintf(s, s_len, "sport=%u dport=%u", htons(udphdr->uh_sport), htons(udphdr->uh_dport)); } void print_udphdr(const struct udphdr *udphdr) { char s[30]; - str_udphdr(s,sizeof(s),udphdr); - printf("%s",s); + str_udphdr(s, sizeof(s), udphdr); + printf("%s", s); } - - - bool proto_check_ipv4(const uint8_t *data, size_t len) { - return len >= 20 && (data[0] & 0xF0) == 0x40 && - len >= ((data[0] & 0x0F) << 2); + return len >= 20 && (data[0] & 0xF0) == 0x40 && + len >= ((data[0] & 0x0F) << 2); } // move to transport protocol void proto_skip_ipv4(uint8_t **data, size_t *len) @@ -799,7 +833,7 @@ void proto_skip_tcp(uint8_t **data, size_t *len) } bool proto_check_udp(const uint8_t *data, size_t len) { - return len >= 8 && len>=(data[4]<<8 | data[5]); + return len >= 8 && len >= (data[4] << 8 | data[5]); } void proto_skip_udp(uint8_t **data, size_t *len) { @@ -809,8 +843,8 @@ void proto_skip_udp(uint8_t **data, size_t *len) bool proto_check_ipv6(const uint8_t *data, size_t len) { - return len >= 40 && (data[0] & 0xF0) == 0x60 && - (len - 40) >= htons(*(uint16_t*)(data + 4)); // payload length + return len >= 40 && (data[0] & 0xF0) == 0x60 && + (len - 40) >= htons(*(uint16_t *)(data + 4)); // payload length } // move to transport protocol // proto_type = 0 => error @@ -819,38 +853,45 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type, uint8_t * size_t hdrlen; uint8_t HeaderType; - if (proto_type) *proto_type = 0; // put error in advance + if (proto_type) + *proto_type = 0; // put error in advance HeaderType = (*data)[6]; // NextHeader field - if (last_header_type) *last_header_type = (*data)+6; - *data += 40; *len -= 40; // skip ipv6 base header + if (last_header_type) + *last_header_type = (*data) + 6; + *data += 40; + *len -= 40; // skip IPv6 base header while (*len > 0) // need at least one byte for NextHeader field { switch (HeaderType) { - case 0: // Hop-by-Hop Options - case 43: // routing - case 51: // authentication - case 60: // Destination Options + case 0: // Hop-by-Hop Options + case 43: // routing + case 51: // authentication + case 60: // Destination Options case 135: // mobility case 139: // Host Identity Protocol Version v2 case 140: // Shim6 - if (*len < 2) return; // error + if (*len < 2) + return; // error hdrlen = 8 + ((*data)[1] << 3); break; case 44: // fragment. length fixed to 8, hdrlen field defined as reserved hdrlen = 8; break; - case 59: // no next header + case 59: // no next header return; // error default: - // we found some meaningful payload. it can be tcp, udp, icmp or some another exotic shit - if (proto_type) *proto_type = HeaderType; + // we found some meaningful payload. it can be TCP, UDP, ICMP or some another exotic shit + if (proto_type) + *proto_type = HeaderType; return; } - if (*len < hdrlen) return; // error + if (*len < hdrlen) + return; // error HeaderType = **data; - if (last_header_type) *last_header_type = *data; + if (last_header_type) + *last_header_type = *data; // advance to the next header location *len -= hdrlen; *data += hdrlen; @@ -875,16 +916,16 @@ void proto_dissect_l3l4( *udp = NULL; *data_payload = NULL; *len_payload = 0; - + if (proto_check_ipv4(data, len)) { - *ip = (struct ip *) data; + *ip = (struct ip *)data; *proto = (*ip)->ip_p; proto_skip_ipv4(&data, &len); } else if (proto_check_ipv6(data, len)) { - *ip6 = (struct ip6_hdr *) data; + *ip6 = (struct ip6_hdr *)data; proto_skip_ipv6(&data, &len, proto, NULL); } else @@ -892,22 +933,21 @@ void proto_dissect_l3l4( return; } - if (*proto==IPPROTO_TCP && proto_check_tcp(data, len)) + if (*proto == IPPROTO_TCP && proto_check_tcp(data, len)) { - *tcp = (struct tcphdr *) data; + *tcp = (struct tcphdr *)data; *transport_len = len; proto_skip_tcp(&data, &len); *data_payload = data; *len_payload = len; - } - else if (*proto==IPPROTO_UDP && proto_check_udp(data, len)) + else if (*proto == IPPROTO_UDP && proto_check_udp(data, len)) { - *udp = (struct udphdr *) data; + *udp = (struct udphdr *)data; *transport_len = len; - + proto_skip_udp(&data, &len); *data_payload = data; @@ -915,39 +955,38 @@ void proto_dissect_l3l4( } } - bool tcp_synack_segment(const struct tcphdr *tcphdr) { /* check for set bits in TCP hdr */ - return ((tcphdr->th_flags & (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN)) == (TH_ACK|TH_SYN)); + return ((tcphdr->th_flags & (TH_URG | TH_ACK | TH_PUSH | TH_RST | TH_SYN | TH_FIN)) == (TH_ACK | TH_SYN)); } bool tcp_syn_segment(const struct tcphdr *tcphdr) { /* check for set bits in TCP hdr */ - return ((tcphdr->th_flags & (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN)) == TH_SYN); + return ((tcphdr->th_flags & (TH_URG | TH_ACK | TH_PUSH | TH_RST | TH_SYN | TH_FIN)) == TH_SYN); } bool tcp_ack_segment(const struct tcphdr *tcphdr) { /* check for set bits in TCP hdr */ - return ((tcphdr->th_flags & (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN)) == TH_ACK); + return ((tcphdr->th_flags & (TH_URG | TH_ACK | TH_PUSH | TH_RST | TH_SYN | TH_FIN)) == TH_ACK); } void tcp_rewrite_wscale(struct tcphdr *tcp, uint8_t scale_factor) { - uint8_t *scale,scale_factor_old; + uint8_t *scale, scale_factor_old; - if (scale_factor!=SCALE_NONE) + if (scale_factor != SCALE_NONE) { - scale = tcp_find_option(tcp,3); // tcp option 3 - scale factor - if (scale && scale[1]==3) // length should be 3 + scale = tcp_find_option(tcp, 3); // tcp option 3 - scale factor + if (scale && scale[1] == 3) // length should be 3 { - scale_factor_old=scale[2]; + scale_factor_old = scale[2]; // do not allow increasing scale factor - if (scale_factor>=scale_factor_old) + if (scale_factor >= scale_factor_old) DLOG("Scale factor %u unchanged\n", scale_factor_old); else { - scale[2]=scale_factor; + scale[2] = scale_factor; DLOG("Scale factor change %u => %u\n", scale_factor_old, scale_factor); } } @@ -965,78 +1004,80 @@ void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize, uint8_t scale_fac tcp_rewrite_wscale(tcp, scale_factor); } - #ifdef __CYGWIN__ static HANDLE w_filter = NULL; -static OVERLAPPED ovl = { .hEvent = NULL }; +static OVERLAPPED ovl = {.hEvent = NULL}; static const struct str_list_head *wlan_filter_ssid = NULL, *nlm_filter_net = NULL; -static DWORD logical_net_filter_tick=0; -uint32_t w_win32_error=0; -INetworkListManager* pNetworkListManager=NULL; +static DWORD logical_net_filter_tick = 0; +uint32_t w_win32_error = 0; +INetworkListManager *pNetworkListManager = NULL; static void guid2str(const GUID *guid, char *str) { - snprintf(str,37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + snprintf(str, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); } -static bool str2guid(const char* str, GUID *guid) +static bool str2guid(const char *str, GUID *guid) { - unsigned int u[11],k; + unsigned int u[11], k; - if (36 != strlen(str) || 11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", u+0, u+1, u+2, u+3, u+4, u+5, u+6, u+7, u+8, u+9, u+10)) + if (36 != strlen(str) || 11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", u + 0, u + 1, u + 2, u + 3, u + 4, u + 5, u + 6, u + 7, u + 8, u + 9, u + 10)) return false; guid->Data1 = u[0]; - if ((u[1] & 0xFFFF0000) || (u[2] & 0xFFFF0000)) return false; + if ((u[1] & 0xFFFF0000) || (u[2] & 0xFFFF0000)) + return false; guid->Data2 = (USHORT)u[1]; guid->Data3 = (USHORT)u[2]; for (k = 0; k < 8; k++) { - if (u[k+3] & 0xFFFFFF00) return false; - guid->Data4[k] = (UCHAR)u[k+3]; + if (u[k + 3] & 0xFFFFFF00) + return false; + guid->Data4[k] = (UCHAR)u[k + 3]; } return true; } -static const char *sNetworkCards="SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; +static const char *sNetworkCards = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; // get adapter name from guid string -static bool AdapterID2Name(const GUID *guid,char *name,DWORD name_len) +static bool AdapterID2Name(const GUID *guid, char *name, DWORD name_len) { - char sguid[39],sidx[32],val[256]; - HKEY hkNetworkCards,hkCard; - DWORD dwIndex,dwLen; + char sguid[39], sidx[32], val[256]; + HKEY hkNetworkCards, hkCard; + DWORD dwIndex, dwLen; bool bRet = false; WCHAR namew[128]; DWORD namew_len; - if (name_len<2) return false; + if (name_len < 2) + return false; - if ((w_win32_error = RegOpenKeyExA(HKEY_LOCAL_MACHINE,sNetworkCards,0,KEY_ENUMERATE_SUB_KEYS,&hkNetworkCards)) == ERROR_SUCCESS) + if ((w_win32_error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, sNetworkCards, 0, KEY_ENUMERATE_SUB_KEYS, &hkNetworkCards)) == ERROR_SUCCESS) { - guid2str(guid, sguid+1); - sguid[0]='{'; - sguid[37]='}'; - sguid[38]='\0'; + guid2str(guid, sguid + 1); + sguid[0] = '{'; + sguid[37] = '}'; + sguid[38] = '\0'; - for (dwIndex=0;;dwIndex++) + for (dwIndex = 0;; dwIndex++) { - dwLen=sizeof(sidx)-1; - w_win32_error = RegEnumKeyExA(hkNetworkCards,dwIndex,sidx,&dwLen,NULL,NULL,NULL,NULL); + dwLen = sizeof(sidx) - 1; + w_win32_error = RegEnumKeyExA(hkNetworkCards, dwIndex, sidx, &dwLen, NULL, NULL, NULL, NULL); if (w_win32_error == ERROR_SUCCESS) { - sidx[dwLen]='\0'; + sidx[dwLen] = '\0'; - if ((w_win32_error = RegOpenKeyExA(hkNetworkCards,sidx,0,KEY_QUERY_VALUE,&hkCard)) == ERROR_SUCCESS) + if ((w_win32_error = RegOpenKeyExA(hkNetworkCards, sidx, 0, KEY_QUERY_VALUE, &hkCard)) == ERROR_SUCCESS) { - dwLen=sizeof(val)-1; - if ((w_win32_error = RegQueryValueExA(hkCard,"ServiceName",NULL,NULL,val,&dwLen)) == ERROR_SUCCESS) + dwLen = sizeof(val) - 1; + if ((w_win32_error = RegQueryValueExA(hkCard, "ServiceName", NULL, NULL, val, &dwLen)) == ERROR_SUCCESS) { - val[dwLen]='\0'; - if (!strcmp(val,sguid)) + val[dwLen] = '\0'; + if (!strcmp(val, sguid)) { - namew_len = sizeof(namew)-sizeof(WCHAR); - if ((w_win32_error = RegQueryValueExW(hkCard,L"Description",NULL,NULL,(LPBYTE)namew,&namew_len)) == ERROR_SUCCESS) + namew_len = sizeof(namew) - sizeof(WCHAR); + if ((w_win32_error = RegQueryValueExW(hkCard, L"Description", NULL, NULL, (LPBYTE)namew, &namew_len)) == ERROR_SUCCESS) { - namew[namew_len/sizeof(WCHAR)]=L'\0'; + namew[namew_len / sizeof(WCHAR)] = L'\0'; if (WideCharToMultiByte(CP_UTF8, 0, namew, -1, name, name_len, NULL, NULL)) bRet = true; } @@ -1044,7 +1085,8 @@ static bool AdapterID2Name(const GUID *guid,char *name,DWORD name_len) } RegCloseKey(hkCard); } - if (bRet) break; + if (bRet) + break; } else break; @@ -1058,13 +1100,15 @@ static bool AdapterID2Name(const GUID *guid,char *name,DWORD name_len) bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter) { win_dark_deinit(); - if (LIST_EMPTY(ssid_filter)) ssid_filter=NULL; - if (LIST_EMPTY(nlm_filter)) nlm_filter=NULL; + if (LIST_EMPTY(ssid_filter)) + ssid_filter = NULL; + if (LIST_EMPTY(nlm_filter)) + nlm_filter = NULL; if (nlm_filter) { if (SUCCEEDED(w_win32_error = CoInitialize(NULL))) { - if (FAILED(w_win32_error = CoCreateInstance(&CLSID_NetworkListManager, NULL, CLSCTX_ALL, &IID_INetworkListManager, (LPVOID*)&pNetworkListManager))) + if (FAILED(w_win32_error = CoCreateInstance(&CLSID_NetworkListManager, NULL, CLSCTX_ALL, &IID_INetworkListManager, (LPVOID *)&pNetworkListManager))) { CoUninitialize(); return false; @@ -1084,21 +1128,21 @@ bool win_dark_deinit(void) pNetworkListManager->lpVtbl->Release(pNetworkListManager); pNetworkListManager = NULL; } - if (nlm_filter_net) CoUninitialize(); + if (nlm_filter_net) + CoUninitialize(); wlan_filter_ssid = nlm_filter_net = NULL; } - bool nlm_list(bool bAll) { bool bRet = true; if (SUCCEEDED(w_win32_error = CoInitialize(NULL))) { - INetworkListManager* pNetworkListManager; - if (SUCCEEDED(w_win32_error = CoCreateInstance(&CLSID_NetworkListManager, NULL, CLSCTX_ALL, &IID_INetworkListManager, (LPVOID*)&pNetworkListManager))) + INetworkListManager *pNetworkListManager; + if (SUCCEEDED(w_win32_error = CoCreateInstance(&CLSID_NetworkListManager, NULL, CLSCTX_ALL, &IID_INetworkListManager, (LPVOID *)&pNetworkListManager))) { - IEnumNetworks* pEnumNetworks; + IEnumNetworks *pEnumNetworks; if (SUCCEEDED(w_win32_error = pNetworkListManager->lpVtbl->GetNetworks(pNetworkListManager, NLM_ENUM_NETWORK_ALL, &pEnumNetworks))) { INetwork *pNet; @@ -1108,7 +1152,7 @@ bool nlm_list(bool bAll) NLM_NETWORK_CATEGORY category; GUID idNet, idAdapter; BSTR bstrName; - char Name[128],Name2[128]; + char Name[128], Name2[128]; int connected; for (connected = 1; connected >= !bAll; connected--) { @@ -1119,7 +1163,8 @@ bool nlm_list(bool bAll) bRet = false; break; } - if (w_win32_error != S_OK) break; + if (w_win32_error != S_OK) + break; if (SUCCEEDED(w_win32_error = pNet->lpVtbl->get_IsConnected(pNet, &bIsConnected)) && SUCCEEDED(w_win32_error = pNet->lpVtbl->get_IsConnectedToInternet(pNet, &bIsConnectedInet)) && SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkId(pNet, &idNet)) && @@ -1131,23 +1176,24 @@ bool nlm_list(bool bAll) if (WideCharToMultiByte(CP_UTF8, 0, bstrName, -1, Name, sizeof(Name), NULL, NULL)) { printf("Name : %s", Name); - if (bIsConnected) printf(" (connected)"); - if (bIsConnectedInet) printf(" (inet)"); + if (bIsConnected) + printf(" (connected)"); + if (bIsConnectedInet) + printf(" (inet)"); printf(" (%s)\n", - category==NLM_NETWORK_CATEGORY_PUBLIC ? "public" : - category==NLM_NETWORK_CATEGORY_PRIVATE ? "private" : - category==NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED ? "domain" : - "unknown"); + category == NLM_NETWORK_CATEGORY_PUBLIC ? "public" : category == NLM_NETWORK_CATEGORY_PRIVATE ? "private" + : category == NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED ? "domain" + : "unknown"); guid2str(&idNet, Name); - printf("NetID : %s\n", Name); + printf("NetID : %s\n", Name); if (connected && SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkConnections(pNet, &pEnumConnections))) { - while ((w_win32_error = pEnumConnections->lpVtbl->Next(pEnumConnections, 1, &pConn, NULL))==S_OK) + while ((w_win32_error = pEnumConnections->lpVtbl->Next(pEnumConnections, 1, &pConn, NULL)) == S_OK) { - if (SUCCEEDED(w_win32_error = pConn->lpVtbl->GetAdapterId(pConn,&idAdapter))) + if (SUCCEEDED(w_win32_error = pConn->lpVtbl->GetAdapterId(pConn, &idAdapter))) { guid2str(&idAdapter, Name); - if (AdapterID2Name(&idAdapter,Name2,sizeof(Name2))) + if (AdapterID2Name(&idAdapter, Name2, sizeof(Name2))) printf("Adapter : %s (%s)\n", Name2, Name); else printf("Adapter : %s\n", Name); @@ -1169,9 +1215,11 @@ bool nlm_list(bool bAll) else bRet = false; pNet->lpVtbl->Release(pNet); - if (!bRet) break; + if (!bRet) + break; } - if (!bRet) break; + if (!bRet) + break; pEnumNetworks->lpVtbl->Reset(pEnumNetworks); } pEnumNetworks->lpVtbl->Release(pEnumNetworks); @@ -1200,12 +1248,12 @@ static bool nlm_filter_match(const struct str_list_head *nlm_list) } bool bRet = true, bMatch = false; - IEnumNetworks* pEnum; + IEnumNetworks *pEnum; if (SUCCEEDED(w_win32_error = pNetworkListManager->lpVtbl->GetNetworks(pNetworkListManager, NLM_ENUM_NETWORK_CONNECTED, &pEnum))) { - INetwork* pNet; - GUID idNet,g; + INetwork *pNet; + GUID idNet, g; BSTR bstrName; char Name[128]; struct str_list *nlm; @@ -1216,7 +1264,8 @@ static bool nlm_filter_match(const struct str_list_head *nlm_list) bRet = false; break; } - if (w_win32_error != S_OK) break; + if (w_win32_error != S_OK) + break; if (SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkId(pNet, &idNet)) && SUCCEEDED(w_win32_error = pNet->lpVtbl->GetName(pNet, &bstrName))) { @@ -1224,8 +1273,9 @@ static bool nlm_filter_match(const struct str_list_head *nlm_list) { LIST_FOREACH(nlm, nlm_list, next) { - bMatch = !strcmp(Name,nlm->str) || str2guid(nlm->str,&g) && !memcmp(&idNet,&g,sizeof(GUID)); - if (bMatch) break; + bMatch = !strcmp(Name, nlm->str) || str2guid(nlm->str, &g) && !memcmp(&idNet, &g, sizeof(GUID)); + if (bMatch) + break; } } else @@ -1238,7 +1288,8 @@ static bool nlm_filter_match(const struct str_list_head *nlm_list) else bRet = false; pNet->lpVtbl->Release(pNet); - if (!bRet || bMatch) break; + if (!bRet || bMatch) + break; } pEnum->lpVtbl->Release(pEnum); } @@ -1267,30 +1318,33 @@ static bool wlan_filter_match(const struct str_list_head *ssid_list) } w_win32_error = WlanOpenHandle(2, NULL, &dwCurVersion, &hClient); - if (w_win32_error != ERROR_SUCCESS) goto fail; + if (w_win32_error != ERROR_SUCCESS) + goto fail; w_win32_error = WlanEnumInterfaces(hClient, NULL, &pIfList); - if (w_win32_error != ERROR_SUCCESS) goto fail; + if (w_win32_error != ERROR_SUCCESS) + goto fail; for (k = 0; k < pIfList->dwNumberOfItems; k++) { pIfInfo = pIfList->InterfaceInfo + k; if (pIfInfo->isState == wlan_interface_state_connected) { w_win32_error = WlanQueryInterface(hClient, - &pIfInfo->InterfaceGuid, - wlan_intf_opcode_current_connection, - NULL, - &connectInfoSize, - (PVOID *)&pConnectInfo, - NULL); - if (w_win32_error != ERROR_SUCCESS) goto fail; + &pIfInfo->InterfaceGuid, + wlan_intf_opcode_current_connection, + NULL, + &connectInfoSize, + (PVOID *)&pConnectInfo, + NULL); + if (w_win32_error != ERROR_SUCCESS) + goto fail; -// printf("%s\n", pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID); + // printf("%s\n", pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID); LIST_FOREACH(ssid, ssid_list, next) { len = strlen(ssid->str); - if (len==pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength && !memcmp(ssid->str,pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID,len)) - { + if (len == pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength && !memcmp(ssid->str, pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID, len)) + { WlanFreeMemory(pConnectInfo); goto found; } @@ -1303,8 +1357,10 @@ static bool wlan_filter_match(const struct str_list_head *ssid_list) fail: bRes = false; ex: - if (pIfList) WlanFreeMemory(pIfList); - if (hClient) WlanCloseHandle(hClient, 0); + if (pIfList) + WlanFreeMemory(pIfList); + if (hClient) + WlanCloseHandle(hClient, 0); return bRes; found: w_win32_error = 0; @@ -1320,7 +1376,8 @@ bool logical_net_filter_match(void) static bool logical_net_filter_match_rate_limited(void) { DWORD dwTick = GetTickCount() / 1000; - if (logical_net_filter_tick == dwTick) return true; + if (logical_net_filter_tick == dwTick) + return true; logical_net_filter_tick = dwTick; return logical_net_filter_match(); } @@ -1332,9 +1389,9 @@ static HANDLE windivert_init_filter(const char *filter, UINT64 flags) const char *mutex_name = "Global\\winws_windivert_mutex"; // windivert driver start in windivert.dll has race conditions - hMutex = CreateMutexA(NULL,TRUE,mutex_name); - if (hMutex && GetLastError()==ERROR_ALREADY_EXISTS) - WaitForSingleObject(hMutex,INFINITE); + hMutex = CreateMutexA(NULL, TRUE, mutex_name); + if (hMutex && GetLastError() == ERROR_ALREADY_EXISTS) + WaitForSingleObject(hMutex, INFINITE); h = WinDivertOpen(filter, WINDIVERT_LAYER_NETWORK, 0, flags); w_win32_error = GetLastError(); @@ -1345,10 +1402,11 @@ static HANDLE windivert_init_filter(const char *filter, UINT64 flags) SetLastError(w_win32_error); } - if (h != INVALID_HANDLE_VALUE) return h; + if (h != INVALID_HANDLE_VALUE) + return h; FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, w_win32_error, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPSTR)&errormessage, 0, NULL); + NULL, w_win32_error, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPSTR)&errormessage, 0, NULL); DLOG_ERR("windivert: error opening filter: %s", errormessage); LocalFree(errormessage); if (w_win32_error == ERROR_INVALID_IMAGE_HASH) @@ -1360,14 +1418,14 @@ void rawsend_cleanup(void) { if (w_filter) { - CancelIoEx(w_filter,&ovl); + CancelIoEx(w_filter, &ovl); WinDivertClose(w_filter); - w_filter=NULL; + w_filter = NULL; } if (ovl.hEvent) { CloseHandle(ovl.hEvent); - ovl.hEvent=NULL; + ovl.hEvent = NULL; } } bool windivert_init(const char *filter) @@ -1376,7 +1434,7 @@ bool windivert_init(const char *filter) w_filter = windivert_init_filter(filter, 0); if (w_filter) { - ovl.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL); + ovl.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if (!ovl.hEvent) { w_win32_error = GetLastError(); @@ -1397,12 +1455,12 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, if (bQuit) { - errno=EINTR; + errno = EINTR; return false; } if (!logical_net_filter_match_rate_limited()) { - errno=ENODEV; + errno = ENODEV; return false; } usleep(0); @@ -1411,39 +1469,39 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, *len = recv_len; return true; } - for(;;) + for (;;) { w_win32_error = GetLastError(); - switch(w_win32_error) + switch (w_win32_error) { - case ERROR_IO_PENDING: - // make signals working - while (WaitForSingleObject(ovl.hEvent,50)==WAIT_TIMEOUT) + case ERROR_IO_PENDING: + // make signals working + while (WaitForSingleObject(ovl.hEvent, 50) == WAIT_TIMEOUT) + { + if (bQuit) { - if (bQuit) - { - errno=EINTR; - return false; - } - if (!logical_net_filter_match_rate_limited()) - { - errno=ENODEV; - return false; - } - usleep(0); + errno = EINTR; + return false; } - if (!GetOverlappedResult(hFilter,&ovl,&rd,TRUE)) - continue; - *len = rd; - return true; - case ERROR_INSUFFICIENT_BUFFER: - errno = ENOBUFS; - break; - case ERROR_NO_DATA: - errno = ESHUTDOWN; - break; - default: - errno = EIO; + if (!logical_net_filter_match_rate_limited()) + { + errno = ENODEV; + return false; + } + usleep(0); + } + if (!GetOverlappedResult(hFilter, &ovl, &rd, TRUE)) + continue; + *len = rd; + return true; + case ERROR_INSUFFICIENT_BUFFER: + errno = ENOBUFS; + break; + case ERROR_NO_DATA: + errno = ESHUTDOWN; + break; + default: + errno = EIO; } break; } @@ -1451,50 +1509,50 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, } bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa) { - return windivert_recv_filter(w_filter,packet,len,wa); + return windivert_recv_filter(w_filter, packet, len, wa); } static bool windivert_send_filter(HANDLE hFilter, const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa) { - bool b = WinDivertSend(hFilter,packet,(UINT)len,NULL,wa); + bool b = WinDivertSend(hFilter, packet, (UINT)len, NULL, wa); w_win32_error = GetLastError(); return b; } bool windivert_send(const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa) { - return windivert_send_filter(w_filter,packet,len,wa); + return windivert_send_filter(w_filter, packet, len, wa); } -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) { WINDIVERT_ADDRESS wa; - memset(&wa,0,sizeof(wa)); + memset(&wa, 0, sizeof(wa)); // pseudo interface id IfIdx.SubIfIdx - if (sscanf(ifout,"%u.%u",&wa.Network.IfIdx,&wa.Network.SubIfIdx)!=2) + if (sscanf(ifout, "%u.%u", &wa.Network.IfIdx, &wa.Network.SubIfIdx) != 2) { errno = EINVAL; return false; } - wa.Outbound=1; - wa.IPChecksum=1; - wa.TCPChecksum=1; - wa.UDPChecksum=1; - wa.IPv6 = (dst->sa_family==AF_INET6); + wa.Outbound = 1; + wa.IPChecksum = 1; + wa.TCPChecksum = 1; + wa.UDPChecksum = 1; + wa.IPv6 = (dst->sa_family == AF_INET6); - return windivert_send(data,len,&wa); + return windivert_send(data, len, &wa); } #else // *nix -static int rawsend_sock4=-1, rawsend_sock6=-1; -static bool b_bind_fix4=false, b_bind_fix6=false; +static int rawsend_sock4 = -1, rawsend_sock6 = -1; +static bool b_bind_fix4 = false, b_bind_fix6 = false; static void rawsend_clean_sock(int *sock) { - if (sock && *sock!=-1) + if (sock && *sock != -1) { close(*sock); - *sock=-1; + *sock = -1; } } void rawsend_cleanup(void) @@ -1504,11 +1562,14 @@ void rawsend_cleanup(void) } static int *rawsend_family_sock(sa_family_t family) { - switch(family) + switch (family) { - case AF_INET: return &rawsend_sock4; - case AF_INET6: return &rawsend_sock6; - default: return NULL; + case AF_INET: + return &rawsend_sock4; + case AF_INET6: + return &rawsend_sock6; + default: + return NULL; } } @@ -1516,12 +1577,12 @@ static int *rawsend_family_sock(sa_family_t family) int socket_divert(sa_family_t family) { int fd; - + #ifdef __FreeBSD__ // freebsd14+ way // don't want to use ifdefs with os version to make binaries compatible with all versions fd = socket(PF_DIVERT, SOCK_RAW, 0); - if (fd==-1 && (errno==EPROTONOSUPPORT || errno==EAFNOSUPPORT || errno==EPFNOSUPPORT)) + if (fd == -1 && (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT || errno == EPFNOSUPPORT)) #endif // freebsd13- or openbsd way fd = socket(family, SOCK_RAW, IPPROTO_DIVERT); @@ -1536,7 +1597,7 @@ static int rawsend_socket_divert(sa_family_t family) // from my point of view disabling direct ability to send ip frames is not security. its SHIT int fd = socket_divert(family); - if (fd!=-1 && !set_socket_buffers(fd,4096,RAW_SNDBUF)) + if (fd != -1 && !set_socket_buffers(fd, 4096, RAW_SNDBUF)) { close(fd); return -1; @@ -1554,37 +1615,37 @@ static int rawsend_sendto_divert(sa_family_t family, int sock, const void *buf, slen = sizeof(struct sockaddr_in); #else // OpenBSD requires correct family and size - switch(family) + switch (family) { - case AF_INET: - slen = sizeof(struct sockaddr_in); - break; - case AF_INET6: - slen = sizeof(struct sockaddr_in6); - break; - default: - return -1; + case AF_INET: + slen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + slen = sizeof(struct sockaddr_in6); + break; + default: + return -1; } #endif - memset(&sa,0,slen); + memset(&sa, 0, slen); sa.ss_family = family; - return sendto(sock, buf, len, 0, (struct sockaddr*)&sa, slen); + return sendto(sock, buf, len, 0, (struct sockaddr *)&sa, slen); } #endif static int rawsend_socket_raw(int domain, int proto) { int fd = socket(domain, SOCK_RAW, proto); - if (fd!=-1) + if (fd != -1) { - #ifdef __linux__ - int s=RAW_SNDBUF/2; - int r=2048; - #else - int s=RAW_SNDBUF; - int r=4096; - #endif - if (!set_socket_buffers(fd,r,s)) +#ifdef __linux__ + int s = RAW_SNDBUF / 2; + int r = 2048; +#else + int s = RAW_SNDBUF; + int r = 4096; +#endif + if (!set_socket_buffers(fd, r, s)) { close(fd); return -1; @@ -1617,26 +1678,27 @@ static bool set_socket_fwmark(int sock, uint32_t fwmark) static int rawsend_socket(sa_family_t family) { int *sock = rawsend_family_sock(family); - if (!sock) return -1; - - if (*sock==-1) + if (!sock) + return -1; + + if (*sock == -1) { - int yes=1,pri=6; - //printf("rawsend_socket: family %d",family); + int yes = 1, pri = 6; + // printf("rawsend_socket: family %d",family); #ifdef __FreeBSD__ // IPPROTO_RAW with ipv6 in FreeBSD always returns EACCES on sendto. // must use IPPROTO_TCP for ipv6. IPPROTO_RAW works for ipv4 // divert sockets are always v4 but accept both v4 and v6 *sock = rawsend_socket_divert(AF_INET); -#elif defined(__OpenBSD__) || defined (__APPLE__) +#elif defined(__OpenBSD__) || defined(__APPLE__) // OpenBSD does not allow sending TCP frames through raw sockets // I dont know about macos. They have dropped ipfw in recent versions and their PF does not support divert-packet *sock = rawsend_socket_divert(family); #else *sock = rawsend_socket_raw(family, IPPROTO_RAW); #endif - if (*sock==-1) + if (*sock == -1) { DLOG_PERROR("rawsend: socket()"); return -1; @@ -1647,20 +1709,20 @@ static int rawsend_socket(sa_family_t family) DLOG_PERROR("rawsend: setsockopt(SO_PRIORITY)"); goto exiterr; } - if (family==AF_INET && setsockopt(*sock, IPPROTO_IP, IP_NODEFRAG, &yes, sizeof(yes)) == -1) + if (family == AF_INET && setsockopt(*sock, IPPROTO_IP, IP_NODEFRAG, &yes, sizeof(yes)) == -1) { DLOG_PERROR("rawsend: setsockopt(IP_NODEFRAG)"); goto exiterr; } - if (family==AF_INET && setsockopt(*sock, IPPROTO_IP, IP_FREEBIND, &yes, sizeof(yes)) == -1) + if (family == AF_INET && setsockopt(*sock, IPPROTO_IP, IP_FREEBIND, &yes, sizeof(yes)) == -1) { DLOG_PERROR("rawsend: setsockopt(IP_FREEBIND)"); goto exiterr; } - if (family==AF_INET6 && setsockopt(*sock, SOL_IPV6, IPV6_FREEBIND, &yes, sizeof(yes)) == -1) + if (family == AF_INET6 && setsockopt(*sock, SOL_IPV6, IPV6_FREEBIND, &yes, sizeof(yes)) == -1) { - //DLOG_PERROR("rawsend: setsockopt(IPV6_FREEBIND)"); - // dont error because it's supported only from kernel 4.15 + // DLOG_PERROR("rawsend: setsockopt(IPV6_FREEBIND)"); + // don't error because it's supported only from kernel 4.15 } #endif } @@ -1673,25 +1735,27 @@ bool rawsend_preinit(bool bind_fix4, bool bind_fix6) { b_bind_fix4 = bind_fix4; b_bind_fix6 = bind_fix6; - // allow ipv6 disabled systems - return rawsend_socket(AF_INET)!=-1 && (rawsend_socket(AF_INET6)!=-1 || errno==EAFNOSUPPORT); + // allow IPv6 disabled systems + return rawsend_socket(AF_INET) != -1 && (rawsend_socket(AF_INET6) != -1 || errno == EAFNOSUPPORT); } -bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len) +bool rawsend(const struct sockaddr *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len) { ssize_t bytes; - int sock=rawsend_socket(dst->sa_family); - if (sock==-1) return false; - if (!set_socket_fwmark(sock,fwmark)) return false; + int sock = rawsend_socket(dst->sa_family); + if (sock == -1) + return false; + if (!set_socket_fwmark(sock, fwmark)) + return false; int salen = dst->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); struct sockaddr_storage dst2; - memcpy(&dst2,dst,salen); - if (dst->sa_family==AF_INET6) - ((struct sockaddr_in6 *)&dst2)->sin6_port = 0; // or will be EINVAL in linux + memcpy(&dst2, dst, salen); + if (dst->sa_family == AF_INET6) + ((struct sockaddr_in6 *)&dst2)->sin6_port = 0; // or will be EINVAL in Linux #if defined(BSD) - bytes = rawsend_sendto_divert(dst->sa_family,sock,data,len); - if (bytes==-1) + bytes = rawsend_sendto_divert(dst->sa_family, sock, data, len); + if (bytes == -1) { DLOG_PERROR("rawsend: sendto_divert"); return false; @@ -1702,33 +1766,35 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const #ifdef __linux__ struct sockaddr_storage sa_src; - switch(dst->sa_family) + switch (dst->sa_family) { - case AF_INET: - if (!b_bind_fix4) goto nofix; - extract_endpoints(data,NULL,NULL,NULL, &sa_src, NULL); - break; - case AF_INET6: - if (!b_bind_fix6) goto nofix; - extract_endpoints(NULL,data,NULL,NULL, &sa_src, NULL); - break; - default: - return false; // should not happen + case AF_INET: + if (!b_bind_fix4) + goto nofix; + extract_endpoints(data, NULL, NULL, NULL, &sa_src, NULL); + break; + case AF_INET6: + if (!b_bind_fix6) + goto nofix; + extract_endpoints(NULL, data, NULL, NULL, &sa_src, NULL); + break; + default: + return false; // should not happen } - //printf("family %u dev %s bind : ", dst->sa_family, ifout); print_sockaddr((struct sockaddr *)&sa_src); printf("\n"); - if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifout, ifout ? strlen(ifout)+1 : 0) == -1) + // printf("family %u dev %s bind : ", dst->sa_family, ifout); print_sockaddr((struct sockaddr *)&sa_src); printf("\n"); + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifout, ifout ? strlen(ifout) + 1 : 0) == -1) { DLOG_PERROR("rawsend: setsockopt(SO_BINDTODEVICE)"); return false; } - if (bind(sock, (const struct sockaddr*)&sa_src, dst->sa_family==AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) + if (bind(sock, (const struct sockaddr *)&sa_src, dst->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) { DLOG_PERROR("rawsend: bind (ignoring)"); // do not fail. this can happen regardless of IP_FREEBIND // rebind to any address - memset(&sa_src,0,sizeof(sa_src)); + memset(&sa_src, 0, sizeof(sa_src)); sa_src.ss_family = dst->sa_family; - if (bind(sock, (const struct sockaddr*)&sa_src, dst->sa_family==AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) + if (bind(sock, (const struct sockaddr *)&sa_src, dst->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) { DLOG_PERROR("rawsend: bind to any"); return false; @@ -1738,8 +1804,8 @@ nofix: #endif // normal raw socket sendto - bytes = sendto(sock, data, len, 0, (struct sockaddr*)&dst2, salen); - if (bytes==-1) + bytes = sendto(sock, data, len, 0, (struct sockaddr *)&dst2, salen); + if (bytes == -1) { DLOG_PERROR("rawsend: sendto"); return false; @@ -1752,18 +1818,17 @@ nofix: bool rawsend_rp(const struct rawpacket *rp) { - return rawsend((struct sockaddr*)&rp->dst,rp->fwmark,rp->ifout,rp->packet,rp->len); + return rawsend((struct sockaddr *)&rp->dst, rp->fwmark, rp->ifout, rp->packet, rp->len); } bool rawsend_queue(struct rawpacket_tailhead *q) { struct rawpacket *rp; bool b; - for (b=true; (rp=rawpacket_dequeue(q)) ; rawpacket_free(rp)) + for (b = true; (rp = rawpacket_dequeue(q)); rawpacket_free(rp)) b &= rawsend_rp(rp); return b; } - // return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling // ttl = TTL of incoming packet uint8_t autottl_guess(uint8_t ttl, const autottl *attl) @@ -1774,22 +1839,25 @@ uint8_t autottl_guess(uint8_t ttl, const autottl *attl) // 157.254.246.178 128 // 1.1.1.1 64 // guess original ttl. consider path lengths less than 32 hops - if (ttl>223) - orig=255; - else if (ttl<128 && ttl>96) - orig=128; - else if (ttl<64 && ttl>32) - orig=64; + if (ttl > 223) + orig = 255; + else if (ttl < 128 && ttl > 96) + orig = 128; + else if (ttl < 64 && ttl > 32) + orig = 64; else return 0; path = orig - ttl; fake = path > attl->delta ? path - attl->delta : attl->min; - if (fakemin) fake=attl->min; - else if (fake>attl->max) fake=attl->max; + if (fake < attl->min) + fake = attl->min; + else if (fake > attl->max) + fake = attl->max; - if (fake>=path) return 0; + if (fake >= path) + return 0; return fake; } @@ -1836,38 +1904,37 @@ void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *t } } - void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr) { if (!(verdict & VERDICT_NOCSUM)) { - // always fix csum for windivert. original can be partial or bad - #ifndef __CYGWIN__ - #ifdef __FreeBSD__ - // FreeBSD tend to pass ipv6 frames with wrong checksum - if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr) - #else +// always fix csum for windivert. original can be partial or bad +#ifndef __CYGWIN__ +#ifdef __FreeBSD__ + // FreeBSD tend to pass IPv6 frames with wrong checksum + if ((verdict & VERDICT_MASK) == VERDICT_MODIFY || ip6hdr) +#else // if original packet was tampered earlier it needs checksum fixed - if ((verdict & VERDICT_MASK)==VERDICT_MODIFY) - #endif - #endif - tcp_fix_checksum(tcphdr,transport_len,ip,ip6hdr); + if ((verdict & VERDICT_MASK) == VERDICT_MODIFY) +#endif +#endif + tcp_fix_checksum(tcphdr, transport_len, ip, ip6hdr); } } void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr) { if (!(verdict & VERDICT_NOCSUM)) { - // always fix csum for windivert. original can be partial or bad - #ifndef __CYGWIN__ - #ifdef __FreeBSD__ - // FreeBSD tend to pass ipv6 frames with wrong checksum - if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr) - #else +// always fix csum for windivert. original can be partial or bad +#ifndef __CYGWIN__ +#ifdef __FreeBSD__ + // FreeBSD tend to pass IPv6 frames with wrong checksum + if ((verdict & VERDICT_MASK) == VERDICT_MODIFY || ip6hdr) +#else // if original packet was tampered earlier it needs checksum fixed - if ((verdict & VERDICT_MASK)==VERDICT_MODIFY) - #endif - #endif - udp_fix_checksum(udphdr,transport_len,ip,ip6hdr); + if ((verdict & VERDICT_MASK) == VERDICT_MODIFY) +#endif +#endif + udp_fix_checksum(udphdr, transport_len, ip, ip6hdr); } } diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index f824c75..f38786c 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -18,7 +18,7 @@ #include #ifndef IPV6_FREEBIND -#define IPV6_FREEBIND 78 +#define IPV6_FREEBIND 78 #endif #ifdef __CYGWIN__ @@ -30,7 +30,7 @@ #endif #ifndef AF_DIVERT -#define AF_DIVERT 44 /* divert(4) */ +#define AF_DIVERT 44 /* divert(4) */ #endif #ifndef PF_DIVERT #define PF_DIVERT AF_DIVERT @@ -40,24 +40,24 @@ uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment); uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment); -#define FOOL_NONE 0x00 -#define FOOL_MD5SIG 0x01 -#define FOOL_BADSUM 0x02 -#define FOOL_TS 0x04 -#define FOOL_BADSEQ 0x08 -#define FOOL_HOPBYHOP 0x10 -#define FOOL_HOPBYHOP2 0x20 -#define FOOL_DESTOPT 0x40 -#define FOOL_IPFRAG1 0x80 -#define FOOL_DATANOACK 0x100 +#define FOOL_NONE 0x00 +#define FOOL_MD5SIG 0x01 +#define FOOL_BADSUM 0x02 +#define FOOL_TS 0x04 +#define FOOL_BADSEQ 0x08 +#define FOOL_HOPBYHOP 0x10 +#define FOOL_HOPBYHOP2 0x20 +#define FOOL_DESTOPT 0x40 +#define FOOL_IPFRAG1 0x80 +#define FOOL_DATANOACK 0x100 -#define SCALE_NONE ((uint8_t)-1) +#define SCALE_NONE ((uint8_t) - 1) -#define VERDICT_PASS 0 -#define VERDICT_MODIFY 1 -#define VERDICT_DROP 2 -#define VERDICT_MASK 3 -#define VERDICT_NOCSUM 4 +#define VERDICT_PASS 0 +#define VERDICT_MODIFY 1 +#define VERDICT_DROP 2 +#define VERDICT_MASK 3 +#define VERDICT_NOCSUM 4 // seq and wsize have network byte order bool prepare_tcp_segment4( @@ -100,7 +100,6 @@ bool prepare_tcp_segment( const void *data, uint16_t len, uint8_t *buf, size_t *buflen); - bool prepare_udp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, uint8_t ttl, @@ -144,11 +143,11 @@ bool ip_frag( size_t frag_pos, uint32_t ident, uint8_t *pkt1, size_t *pkt1_size, uint8_t *pkt2, size_t *pkt2_size); - + void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl); void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport); -void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst); +void extract_endpoints(const struct ip *ip, const struct ip6_hdr *ip6hdr, const struct tcphdr *tcphdr, const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst); uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind); uint32_t *tcp_find_timestamps(struct tcphdr *tcp); uint8_t tcp_find_scale_factor(const struct tcphdr *tcp); @@ -170,7 +169,7 @@ bool rawsend_preinit(bool bind_fix4, bool bind_fix6); #endif // auto creates internal socket and uses it for subsequent calls -bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len); +bool rawsend(const struct sockaddr *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len); bool rawsend_rp(const struct rawpacket *rp); // return trues if all packets were send successfully bool rawsend_queue(struct rawpacket_tailhead *q); @@ -189,7 +188,7 @@ void print_tcphdr(const struct tcphdr *tcphdr); void print_udphdr(const struct udphdr *udphdr); void str_ip(char *s, size_t s_len, const struct ip *ip); void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto); -void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr); +void str_srcdst_ip6(char *s, size_t s_len, const void *saddr, const void *daddr); void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr); void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr); @@ -225,7 +224,12 @@ typedef struct #define AUTOTTL_DEFAULT_MIN 3 #define AUTOTTL_DEFAULT_MAX 20 #define AUTOTTL_ENABLED(a) (!!(a).delta) -#define AUTOTTL_SET_DEFAULT(a) {(a).delta=AUTOTTL_DEFAULT_DELTA; (a).min=AUTOTTL_DEFAULT_MIN; (a).max=AUTOTTL_DEFAULT_MAX;} +#define AUTOTTL_SET_DEFAULT(a) \ + { \ + (a).delta = AUTOTTL_DEFAULT_DELTA; \ + (a).min = AUTOTTL_DEFAULT_MIN; \ + (a).max = AUTOTTL_DEFAULT_MAX; \ + } uint8_t autottl_guess(uint8_t ttl, const autottl *attl); void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6); diff --git a/nfq/desync.c b/nfq/desync.c index 43e3c4c..01aae38 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -9,67 +9,65 @@ #include - const char *fake_http_request_default = "GET / HTTP/1.1\r\nHost: www.iana.org\r\n" - "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0\r\n" - "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n" - "Accept-Encoding: gzip, deflate, br\r\n\r\n"; + "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n" + "Accept-Encoding: gzip, deflate, br\r\n\r\n"; // random : +11 size 32 // random : +44 size 32 // sni : gatech.edu +125 size 11 const uint8_t fake_tls_clienthello_default[648] = { -0x16,0x03,0x01,0x02,0x83,0x01,0x00,0x02,0x7f,0x03,0x03,0x98,0xfb,0x69,0x1d,0x31, -0x66,0xc4,0xd8,0x07,0x25,0x2b,0x74,0x47,0x01,0x44,0x09,0x08,0xcf,0x13,0x67,0xe0, -0x46,0x19,0x1f,0xcb,0xee,0xe6,0x8e,0x33,0xb9,0x91,0xa0,0x20,0xf2,0xed,0x56,0x73, -0xa4,0x0a,0xce,0xa6,0xad,0xd2,0xfd,0x71,0xb8,0xb9,0xfd,0x06,0x0e,0xdd,0xf0,0x57, -0x37,0x7d,0x96,0xb5,0x80,0x6e,0x54,0xe2,0x15,0xce,0x5f,0xff,0x00,0x22,0x13,0x01, -0x13,0x03,0x13,0x02,0xc0,0x2b,0xc0,0x2f,0xcc,0xa9,0xcc,0xa8,0xc0,0x2c,0xc0,0x30, -0xc0,0x0a,0xc0,0x09,0xc0,0x13,0xc0,0x14,0x00,0x9c,0x00,0x9d,0x00,0x2f,0x00,0x35, -0x01,0x00,0x02,0x14,0x00,0x00,0x00,0x0f,0x00,0x0d,0x00,0x00,0x0a,0x67,0x61,0x74, -0x65,0x63,0x68,0x2e,0x65,0x64,0x75,0x00,0x17,0x00,0x00,0xff,0x01,0x00,0x01,0x00, -0x00,0x0a,0x00,0x0e,0x00,0x0c,0x00,0x1d,0x00,0x17,0x00,0x18,0x00,0x19,0x01,0x00, -0x01,0x01,0x00,0x0b,0x00,0x02,0x01,0x00,0x00,0x10,0x00,0x0e,0x00,0x0c,0x02,0x68, -0x32,0x08,0x68,0x74,0x74,0x70,0x2f,0x31,0x2e,0x31,0x00,0x05,0x00,0x05,0x01,0x00, -0x00,0x00,0x00,0x00,0x22,0x00,0x0a,0x00,0x08,0x04,0x03,0x05,0x03,0x06,0x03,0x02, -0x03,0x00,0x33,0x00,0x6b,0x00,0x69,0x00,0x1d,0x00,0x20,0x72,0xe5,0xce,0x58,0x31, -0x3c,0x08,0xaa,0x2f,0xa8,0x40,0xe7,0x7a,0xdf,0x46,0x5b,0x63,0x62,0xc7,0xfa,0x49, -0x18,0xac,0xa1,0x00,0x7c,0x42,0xc5,0x02,0x94,0x5c,0x44,0x00,0x17,0x00,0x41,0x04, -0x8f,0x3e,0x5f,0xd4,0x7f,0x37,0x47,0xd3,0x33,0x70,0x38,0x7f,0x11,0x35,0xc1,0x55, -0x8a,0x6c,0xc7,0x5a,0xd4,0xf7,0x31,0xbb,0x9e,0xee,0xd1,0x8f,0x74,0xdd,0x9b,0xbb, -0x91,0xa1,0x72,0xda,0xeb,0xf6,0xc6,0x82,0x84,0xfe,0xb7,0xfd,0x7b,0xe1,0x9f,0xd2, -0xb9,0x3e,0x83,0xa6,0x9c,0xac,0x81,0xe2,0x00,0xd5,0x19,0x55,0x91,0xa7,0x0c,0x29, -0x00,0x2b,0x00,0x05,0x04,0x03,0x04,0x03,0x03,0x00,0x0d,0x00,0x18,0x00,0x16,0x04, -0x03,0x05,0x03,0x06,0x03,0x08,0x04,0x08,0x05,0x08,0x06,0x04,0x01,0x05,0x01,0x06, -0x01,0x02,0x03,0x02,0x01,0x00,0x1c,0x00,0x02,0x40,0x01,0xfe,0x0d,0x01,0x19,0x00, -0x00,0x01,0x00,0x01,0xfe,0x00,0x20,0xae,0x8b,0x30,0x3c,0xf0,0xa9,0x0d,0xa1,0x69, -0x95,0xb8,0xe2,0xed,0x08,0x6d,0x48,0xdf,0xf7,0x5b,0x9d,0x66,0xef,0x15,0x97,0xbc, -0x2c,0x99,0x91,0x12,0x7a,0x35,0xd0,0x00,0xef,0xb1,0x8d,0xff,0x61,0x57,0x52,0xef, -0xd6,0xea,0xbf,0xf3,0x6d,0x78,0x14,0x38,0xff,0xeb,0x58,0xe8,0x9d,0x59,0x4b,0xd5, -0x9f,0x59,0x12,0xf9,0x03,0x9a,0x20,0x37,0x85,0x77,0xb1,0x4c,0xd8,0xef,0xa6,0xc8, -0x54,0x8d,0x07,0x27,0x95,0xce,0xd5,0x37,0x4d,0x69,0x18,0xd4,0xfd,0x5e,0xdf,0x64, -0xcc,0x10,0x2f,0x7f,0x0e,0xc9,0xfd,0xd4,0xd0,0x18,0x61,0x1b,0x57,0x8f,0x41,0x7f, -0x6f,0x4f,0x5c,0xad,0x04,0xc6,0x5e,0x74,0x54,0x87,0xba,0x28,0xe6,0x11,0x0b,0x9d, -0x3f,0x0b,0x6d,0xf4,0x2d,0xfc,0x31,0x4e,0xfd,0x49,0xe7,0x15,0x96,0xaf,0xee,0x9a, -0x48,0x1b,0xae,0x5e,0x7c,0x20,0xbe,0xb4,0xec,0x68,0xb6,0x74,0x22,0xa0,0xec,0xff, -0x19,0x96,0xe4,0x10,0x8f,0x3c,0x91,0x88,0xa1,0xcc,0x78,0xef,0x4e,0x0e,0xe3,0xb6, -0x57,0x8c,0x33,0xef,0xaa,0xb0,0x1d,0x45,0x1c,0x02,0x4c,0xe2,0x80,0x30,0xe8,0x48, -0x7a,0x09,0x71,0x94,0x7c,0xb6,0x75,0x81,0x1c,0xae,0xe3,0x3f,0xde,0xea,0x2b,0x45, -0xcc,0xe3,0x64,0x09,0xf7,0x60,0x26,0x0c,0x7d,0xad,0x55,0x65,0xb6,0xf5,0x85,0x04, -0x64,0x2f,0x97,0xd0,0x6a,0x06,0x36,0xcd,0x25,0xda,0x51,0xab,0xd6,0xf7,0x5e,0xeb, -0xd4,0x03,0x39,0xa4,0xc4,0x2a,0x9c,0x17,0xe8,0xb0,0x9f,0xc0,0xd3,0x8c,0x76,0xdd, -0xa1,0x0b,0x76,0x9f,0x23,0xfa,0xed,0xfb,0xd7,0x78,0x0f,0x00,0xf7,0x45,0x03,0x04, -0x84,0x66,0x6b,0xec,0xc7,0xed,0xbc,0xe4 -}; + 0x16, 0x03, 0x01, 0x02, 0x83, 0x01, 0x00, 0x02, 0x7f, 0x03, 0x03, 0x98, 0xfb, 0x69, 0x1d, 0x31, + 0x66, 0xc4, 0xd8, 0x07, 0x25, 0x2b, 0x74, 0x47, 0x01, 0x44, 0x09, 0x08, 0xcf, 0x13, 0x67, 0xe0, + 0x46, 0x19, 0x1f, 0xcb, 0xee, 0xe6, 0x8e, 0x33, 0xb9, 0x91, 0xa0, 0x20, 0xf2, 0xed, 0x56, 0x73, + 0xa4, 0x0a, 0xce, 0xa6, 0xad, 0xd2, 0xfd, 0x71, 0xb8, 0xb9, 0xfd, 0x06, 0x0e, 0xdd, 0xf0, 0x57, + 0x37, 0x7d, 0x96, 0xb5, 0x80, 0x6e, 0x54, 0xe2, 0x15, 0xce, 0x5f, 0xff, 0x00, 0x22, 0x13, 0x01, + 0x13, 0x03, 0x13, 0x02, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, 0x30, + 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, + 0x01, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0x00, 0x0a, 0x67, 0x61, 0x74, + 0x65, 0x63, 0x68, 0x2e, 0x65, 0x64, 0x75, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01, 0x00, + 0x01, 0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, + 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x00, 0x33, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x1d, 0x00, 0x20, 0x72, 0xe5, 0xce, 0x58, 0x31, + 0x3c, 0x08, 0xaa, 0x2f, 0xa8, 0x40, 0xe7, 0x7a, 0xdf, 0x46, 0x5b, 0x63, 0x62, 0xc7, 0xfa, 0x49, + 0x18, 0xac, 0xa1, 0x00, 0x7c, 0x42, 0xc5, 0x02, 0x94, 0x5c, 0x44, 0x00, 0x17, 0x00, 0x41, 0x04, + 0x8f, 0x3e, 0x5f, 0xd4, 0x7f, 0x37, 0x47, 0xd3, 0x33, 0x70, 0x38, 0x7f, 0x11, 0x35, 0xc1, 0x55, + 0x8a, 0x6c, 0xc7, 0x5a, 0xd4, 0xf7, 0x31, 0xbb, 0x9e, 0xee, 0xd1, 0x8f, 0x74, 0xdd, 0x9b, 0xbb, + 0x91, 0xa1, 0x72, 0xda, 0xeb, 0xf6, 0xc6, 0x82, 0x84, 0xfe, 0xb7, 0xfd, 0x7b, 0xe1, 0x9f, 0xd2, + 0xb9, 0x3e, 0x83, 0xa6, 0x9c, 0xac, 0x81, 0xe2, 0x00, 0xd5, 0x19, 0x55, 0x91, 0xa7, 0x0c, 0x29, + 0x00, 0x2b, 0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x16, 0x04, + 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, + 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x40, 0x01, 0xfe, 0x0d, 0x01, 0x19, 0x00, + 0x00, 0x01, 0x00, 0x01, 0xfe, 0x00, 0x20, 0xae, 0x8b, 0x30, 0x3c, 0xf0, 0xa9, 0x0d, 0xa1, 0x69, + 0x95, 0xb8, 0xe2, 0xed, 0x08, 0x6d, 0x48, 0xdf, 0xf7, 0x5b, 0x9d, 0x66, 0xef, 0x15, 0x97, 0xbc, + 0x2c, 0x99, 0x91, 0x12, 0x7a, 0x35, 0xd0, 0x00, 0xef, 0xb1, 0x8d, 0xff, 0x61, 0x57, 0x52, 0xef, + 0xd6, 0xea, 0xbf, 0xf3, 0x6d, 0x78, 0x14, 0x38, 0xff, 0xeb, 0x58, 0xe8, 0x9d, 0x59, 0x4b, 0xd5, + 0x9f, 0x59, 0x12, 0xf9, 0x03, 0x9a, 0x20, 0x37, 0x85, 0x77, 0xb1, 0x4c, 0xd8, 0xef, 0xa6, 0xc8, + 0x54, 0x8d, 0x07, 0x27, 0x95, 0xce, 0xd5, 0x37, 0x4d, 0x69, 0x18, 0xd4, 0xfd, 0x5e, 0xdf, 0x64, + 0xcc, 0x10, 0x2f, 0x7f, 0x0e, 0xc9, 0xfd, 0xd4, 0xd0, 0x18, 0x61, 0x1b, 0x57, 0x8f, 0x41, 0x7f, + 0x6f, 0x4f, 0x5c, 0xad, 0x04, 0xc6, 0x5e, 0x74, 0x54, 0x87, 0xba, 0x28, 0xe6, 0x11, 0x0b, 0x9d, + 0x3f, 0x0b, 0x6d, 0xf4, 0x2d, 0xfc, 0x31, 0x4e, 0xfd, 0x49, 0xe7, 0x15, 0x96, 0xaf, 0xee, 0x9a, + 0x48, 0x1b, 0xae, 0x5e, 0x7c, 0x20, 0xbe, 0xb4, 0xec, 0x68, 0xb6, 0x74, 0x22, 0xa0, 0xec, 0xff, + 0x19, 0x96, 0xe4, 0x10, 0x8f, 0x3c, 0x91, 0x88, 0xa1, 0xcc, 0x78, 0xef, 0x4e, 0x0e, 0xe3, 0xb6, + 0x57, 0x8c, 0x33, 0xef, 0xaa, 0xb0, 0x1d, 0x45, 0x1c, 0x02, 0x4c, 0xe2, 0x80, 0x30, 0xe8, 0x48, + 0x7a, 0x09, 0x71, 0x94, 0x7c, 0xb6, 0x75, 0x81, 0x1c, 0xae, 0xe3, 0x3f, 0xde, 0xea, 0x2b, 0x45, + 0xcc, 0xe3, 0x64, 0x09, 0xf7, 0x60, 0x26, 0x0c, 0x7d, 0xad, 0x55, 0x65, 0xb6, 0xf5, 0x85, 0x04, + 0x64, 0x2f, 0x97, 0xd0, 0x6a, 0x06, 0x36, 0xcd, 0x25, 0xda, 0x51, 0xab, 0xd6, 0xf7, 0x5e, 0xeb, + 0xd4, 0x03, 0x39, 0xa4, 0xc4, 0x2a, 0x9c, 0x17, 0xe8, 0xb0, 0x9f, 0xc0, 0xd3, 0x8c, 0x76, 0xdd, + 0xa1, 0x0b, 0x76, 0x9f, 0x23, 0xfa, 0xed, 0xfb, 0xd7, 0x78, 0x0f, 0x00, 0xf7, 0x45, 0x03, 0x04, + 0x84, 0x66, 0x6b, 0xec, 0xc7, 0xed, 0xbc, 0xe4}; -static const char * tld[]={"com","org","net","edu","gov","biz"}; +static const char *tld[] = {"com", "org", "net", "edu", "gov", "biz"}; void randomize_default_tls_payload(uint8_t *p) { - fill_random_bytes(p+11,32); - fill_random_bytes(p+44,32); - fill_random_az(p+125,1); - fill_random_az09(p+126,5); - memcpy(p+132,tld[random()%(sizeof(tld)/sizeof(*tld))],3); + fill_random_bytes(p + 11, 32); + fill_random_bytes(p + 44, 32); + fill_random_az(p + 125, 1); + fill_random_az09(p + 126, 5); + memcpy(p + 132, tld[random() % (sizeof(tld) / sizeof(*tld))], 3); } #define PKTDATA_MAXDUMP 32 @@ -84,11 +82,11 @@ void desync_init(void) bool desync_valid_zero_stage(enum dpi_desync_mode mode) { - return mode==DESYNC_SYNACK || mode==DESYNC_SYNDATA; + return mode == DESYNC_SYNACK || mode == DESYNC_SYNDATA; } bool desync_valid_first_stage(enum dpi_desync_mode mode) { - return mode==DESYNC_FAKE || mode==DESYNC_FAKE_KNOWN || mode==DESYNC_RST || mode==DESYNC_RSTACK || mode==DESYNC_HOPBYHOP || mode==DESYNC_DESTOPT || mode==DESYNC_IPFRAG1; + return mode == DESYNC_FAKE || mode == DESYNC_FAKE_KNOWN || mode == DESYNC_RST || mode == DESYNC_RSTACK || mode == DESYNC_HOPBYHOP || mode == DESYNC_DESTOPT || mode == DESYNC_IPFRAG1; } bool desync_only_first_stage(enum dpi_desync_mode mode) { @@ -96,96 +94,98 @@ bool desync_only_first_stage(enum dpi_desync_mode mode) } bool desync_valid_second_stage(enum dpi_desync_mode mode) { - return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER; + return mode == DESYNC_NONE || mode == DESYNC_DISORDER || mode == DESYNC_DISORDER2 || mode == DESYNC_SPLIT || mode == DESYNC_SPLIT2 || mode == DESYNC_IPFRAG2 || mode == DESYNC_UDPLEN || mode == DESYNC_TAMPER; } bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode) { - return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2; + return mode == DESYNC_NONE || mode == DESYNC_DISORDER || mode == DESYNC_DISORDER2 || mode == DESYNC_SPLIT || mode == DESYNC_SPLIT2 || mode == DESYNC_IPFRAG2; } bool desync_valid_second_stage_udp(enum dpi_desync_mode mode) { - return mode==DESYNC_NONE || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER || mode==DESYNC_IPFRAG2; + return mode == DESYNC_NONE || mode == DESYNC_UDPLEN || mode == DESYNC_TAMPER || mode == DESYNC_IPFRAG2; } enum dpi_desync_mode desync_mode_from_string(const char *s) { if (!s) return DESYNC_NONE; - else if (!strcmp(s,"fake")) + else if (!strcmp(s, "fake")) return DESYNC_FAKE; - else if (!strcmp(s,"fakeknown")) + else if (!strcmp(s, "fakeknown")) return DESYNC_FAKE_KNOWN; - else if (!strcmp(s,"rst")) + else if (!strcmp(s, "rst")) return DESYNC_RST; - else if (!strcmp(s,"rstack")) + else if (!strcmp(s, "rstack")) return DESYNC_RSTACK; - else if (!strcmp(s,"synack")) + else if (!strcmp(s, "synack")) return DESYNC_SYNACK; - else if (!strcmp(s,"syndata")) + else if (!strcmp(s, "syndata")) return DESYNC_SYNDATA; - else if (!strcmp(s,"disorder")) + else if (!strcmp(s, "disorder")) return DESYNC_DISORDER; - else if (!strcmp(s,"disorder2")) + else if (!strcmp(s, "disorder2")) return DESYNC_DISORDER2; - else if (!strcmp(s,"split")) + else if (!strcmp(s, "split")) return DESYNC_SPLIT; - else if (!strcmp(s,"split2")) + else if (!strcmp(s, "split2")) return DESYNC_SPLIT2; - else if (!strcmp(s,"ipfrag2")) + else if (!strcmp(s, "ipfrag2")) return DESYNC_IPFRAG2; - else if (!strcmp(s,"hopbyhop")) + else if (!strcmp(s, "hopbyhop")) return DESYNC_HOPBYHOP; - else if (!strcmp(s,"destopt")) + else if (!strcmp(s, "destopt")) return DESYNC_DESTOPT; - else if (!strcmp(s,"ipfrag1")) + else if (!strcmp(s, "ipfrag1")) return DESYNC_IPFRAG1; - else if (!strcmp(s,"udplen")) + else if (!strcmp(s, "udplen")) return DESYNC_UDPLEN; - else if (!strcmp(s,"tamper")) + else if (!strcmp(s, "tamper")) return DESYNC_TAMPER; return DESYNC_INVALID; } - // auto creates internal socket and uses it for subsequent calls -static bool rawsend_rep(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len) +static bool rawsend_rep(const struct sockaddr *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len) { - for (int i=0;ipcounter_orig; - case 'd': return ctrack->pdcounter_orig; - case 's': return ctrack->seq_last - ctrack->seq0; - default: return 0; + case 'n': + return ctrack->pcounter_orig; + case 'd': + return ctrack->pdcounter_orig; + case 's': + return ctrack->seq_last - ctrack->seq0; + default: + return 0; } } static bool cutoff_test(const t_ctrack *ctrack, uint64_t cutoff, char mode) { - return cutoff && cutoff_get_limit(ctrack, mode)>=cutoff; + return cutoff && cutoff_get_limit(ctrack, mode) >= cutoff; } static void maybe_cutoff(t_ctrack *ctrack, uint8_t proto) { if (ctrack) { - if (proto==IPPROTO_TCP) + if (proto == IPPROTO_TCP) ctrack->b_wssize_cutoff |= cutoff_test(ctrack, params.wssize_cutoff, params.wssize_cutoff_mode); ctrack->b_desync_cutoff |= cutoff_test(ctrack, params.desync_cutoff, params.desync_cutoff_mode); // we do not need conntrack entry anymore if all cutoff conditions are either not defined or reached // do not drop udp entry because it will be recreated when next packet arrives - if (proto==IPPROTO_TCP) - ctrack->b_cutoff |= \ - (!params.wssize || ctrack->b_wssize_cutoff) && - (!params.desync_cutoff || ctrack->b_desync_cutoff) && - (!ctrack->hostname_ah_check || ctrack->req_retrans_counter==RETRANS_COUNTER_STOP) && - ReasmIsEmpty(&ctrack->reasm_orig); + if (proto == IPPROTO_TCP) + ctrack->b_cutoff |= + (!params.wssize || ctrack->b_wssize_cutoff) && + (!params.desync_cutoff || ctrack->b_desync_cutoff) && + (!ctrack->hostname_ah_check || ctrack->req_retrans_counter == RETRANS_COUNTER_STOP) && + ReasmIsEmpty(&ctrack->reasm_orig); } } static void wssize_cutoff(t_ctrack *ctrack) @@ -198,7 +198,7 @@ static void wssize_cutoff(t_ctrack *ctrack) } static void forced_wssize_cutoff(t_ctrack *ctrack) { - if (ctrack && params.wssize && !ctrack->b_wssize_cutoff) + if (ctrack && params.wssize && !ctrack->b_wssize_cutoff) { DLOG("forced wssize-cutoff\n"); wssize_cutoff(ctrack); @@ -219,7 +219,7 @@ static void auto_hostlist_reset_fail_counter(const char *hostname) if (hostname) { hostfail_pool *fail_counter; - + fail_counter = HostFailPoolFind(params.hostlist_auto_fail_counters, hostname); if (fail_counter) { @@ -233,9 +233,9 @@ static void auto_hostlist_reset_fail_counter(const char *hostname) // return true if retrans trigger fires static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int threshold) { - if (ctrack && ctrack->hostname_ah_check && ctrack->req_retrans_counter!=RETRANS_COUNTER_STOP) + if (ctrack && ctrack->hostname_ah_check && ctrack->req_retrans_counter != RETRANS_COUNTER_STOP) { - if (l4proto==IPPROTO_TCP) + if (l4proto == IPPROTO_TCP) { if (!ctrack->req_seq_finalized || ctrack->req_seq_abandoned) return false; @@ -250,18 +250,18 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho ctrack->req_retrans_counter++; if (ctrack->req_retrans_counter >= threshold) { - DLOG("req retrans threshold reached : %u/%u\n",ctrack->req_retrans_counter, threshold); + DLOG("req retrans threshold reached : %u/%u\n", ctrack->req_retrans_counter, threshold); ctrack_stop_retrans_counter(ctrack); return true; } - DLOG("req retrans counter : %u/%u\n",ctrack->req_retrans_counter, threshold); + DLOG("req retrans counter : %u/%u\n", ctrack->req_retrans_counter, threshold); } return false; } static void auto_hostlist_failed(const char *hostname) { hostfail_pool *fail_counter; - + fail_counter = HostFailPoolFind(params.hostlist_auto_fail_counters, hostname); if (!fail_counter) { @@ -279,9 +279,9 @@ static void auto_hostlist_failed(const char *hostname) { DLOG("auto hostlist : fail threshold reached. about to add %s to auto hostlist\n", hostname); HostFailPoolDel(¶ms.hostlist_auto_fail_counters, fail_counter); - + DLOG("auto hostlist : rechecking %s to avoid duplicates\n", hostname); - bool bExcluded=false; + bool bExcluded = false; if (!HostlistCheck(hostname, &bExcluded) && !bExcluded) { DLOG("auto hostlist : adding %s\n", hostname); @@ -325,38 +325,37 @@ static bool send_delayed(t_ctrack *ctrack) return true; } - static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload) { ReasmClear(reasm); - if (sz<=szMax) + if (sz <= szMax) { - uint32_t seq = (proto==IPPROTO_TCP) ? ctrack->seq_last : 0; - if (ReasmInit(reasm,sz,seq)) + uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->seq_last : 0; + if (ReasmInit(reasm, sz, seq)) { - ReasmFeed(reasm,seq,data_payload,len_payload); - DLOG("starting reassemble. now we have %zu/%zu\n",reasm->size_present,reasm->size); + ReasmFeed(reasm, seq, data_payload, len_payload); + DLOG("starting reassemble. now we have %zu/%zu\n", reasm->size_present, reasm->size); return true; } else DLOG("reassemble init failed. out of memory\n"); } else - DLOG("unexpected large payload for reassemble: size=%zu\n",sz); + DLOG("unexpected large payload for reassemble: size=%zu\n", sz); return false; } static bool reasm_orig_start(t_ctrack *ctrack, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload) { - return reasm_start(ctrack,&ctrack->reasm_orig,proto,sz,szMax,data_payload,len_payload); + return reasm_start(ctrack, &ctrack->reasm_orig, proto, sz, szMax, data_payload, len_payload); } static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, const uint8_t *data_payload, size_t len_payload) { if (ctrack && !ReasmIsEmpty(reasm)) { - uint32_t seq = (proto==IPPROTO_TCP) ? ctrack->seq_last : (uint32_t)reasm->size_present; + uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->seq_last : (uint32_t)reasm->size_present; if (ReasmFeed(reasm, seq, data_payload, len_payload)) { - DLOG("reassemble : feeding data payload size=%zu. now we have %zu/%zu\n", len_payload,reasm->size_present,reasm->size); + DLOG("reassemble : feeding data payload size=%zu. now we have %zu/%zu\n", len_payload, reasm->size_present, reasm->size); return true; } else @@ -378,7 +377,7 @@ static void reasm_orig_stop(t_ctrack *ctrack, const char *dlog_msg) { if (!ReasmIsEmpty(&ctrack->reasm_orig)) { - DLOG("%s",dlog_msg); + DLOG("%s", dlog_msg); ReasmClear(&ctrack->reasm_orig); } send_delayed(ctrack); @@ -393,7 +392,6 @@ static void reasm_orig_fin(t_ctrack *ctrack) reasm_orig_stop(ctrack, "reassemble session finished\n"); } - static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, struct ip *ip, struct ip6_hdr *ip6, uint8_t proto, struct udphdr *udp, struct tcphdr *tcp, size_t *len_pkt) { #ifdef __linux__ @@ -401,17 +399,17 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, struct ip *ip, struct // so we need to workaround this. // we can't use low ttl because TCP/IP stack listens to ttl expired ICMPs and notify socket // we also can't use fooling because DPI would accept fooled packets - if (ctrack && ctrack->pcounter_orig==1) + if (ctrack && ctrack->pcounter_orig == 1) { - DLOG("applying linux postnat conntrack workaround\n"); - if (proto==IPPROTO_UDP && udp && len_pkt) + DLOG("applying Linux postnat conntrack workaround\n"); + if (proto == IPPROTO_UDP && udp && len_pkt) { // make malformed udp packet with zero length and invalid checksum udp->uh_ulen = 0; // invalid length. must be >=8 - udp_fix_checksum(udp,sizeof(struct udphdr),ip,ip6); + udp_fix_checksum(udp, sizeof(struct udphdr), ip, ip6); udp->uh_sum ^= htons(0xBEAF); // truncate packet - *len_pkt = (uint8_t*)udp - (ip ? (uint8_t*)ip : (uint8_t*)ip6) + sizeof(struct udphdr); + *len_pkt = (uint8_t *)udp - (ip ? (uint8_t *)ip : (uint8_t *)ip6) + sizeof(struct udphdr); if (ip) { ip->ip_len = htons((uint16_t)*len_pkt); @@ -420,13 +418,14 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, struct ip *ip, struct else if (ip6) ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = (uint16_t)htons(sizeof(struct udphdr)); } - else if (proto==IPPROTO_TCP && tcp) + else if (proto == IPPROTO_TCP && tcp) { // only SYN here is expected // make flags invalid and also corrupt checksum tcp->th_flags = 0; } - if (ip) ip->ip_sum ^= htons(0xBEAF); + if (ip) + ip->ip_sum ^= htons(0xBEAF); return VERDICT_MODIFY | VERDICT_NOCSUM; } #endif @@ -435,14 +434,13 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, struct ip *ip, struct static uint8_t ct_new_postnat_fix_tcp(const t_ctrack *ctrack, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr) { - return ct_new_postnat_fix(ctrack,ip,ip6,IPPROTO_TCP,NULL,tcphdr,NULL); + return ct_new_postnat_fix(ctrack, ip, ip6, IPPROTO_TCP, NULL, tcphdr, NULL); } static uint8_t ct_new_postnat_fix_udp(const t_ctrack *ctrack, struct ip *ip, struct ip6_hdr *ip6, struct udphdr *udphdr, size_t *len_pkt) { - return ct_new_postnat_fix(ctrack,ip,ip6,IPPROTO_UDP,udphdr,NULL,len_pkt); + return ct_new_postnat_fix(ctrack, ip, ip6, IPPROTO_UDP, udphdr, NULL, len_pkt); } - static bool check_desync_interval(const t_ctrack *ctrack) { if (params.desync_start) @@ -451,10 +449,10 @@ static bool check_desync_interval(const t_ctrack *ctrack) { if (!cutoff_test(ctrack, params.desync_start, params.desync_start_mode)) { - DLOG("desync-start not reached (mode %c): %llu/%u . not desyncing\n", params.desync_start_mode, (unsigned long long)cutoff_get_limit(ctrack,params.desync_start_mode), params.desync_start); + DLOG("desync-start not reached (mode %c): %llu/%u . not desyncing\n", params.desync_start_mode, (unsigned long long)cutoff_get_limit(ctrack, params.desync_start_mode), params.desync_start); return false; } - DLOG("desync-start reached (mode %c): %llu/%u\n", params.desync_start_mode, (unsigned long long)cutoff_get_limit(ctrack,params.desync_start_mode), params.desync_start); + DLOG("desync-start reached (mode %c): %llu/%u\n", params.desync_start_mode, (unsigned long long)cutoff_get_limit(ctrack, params.desync_start_mode), params.desync_start); } else { @@ -468,10 +466,10 @@ static bool check_desync_interval(const t_ctrack *ctrack) { if (ctrack->b_desync_cutoff) { - DLOG("desync-cutoff reached (mode %c): %llu/%u . not desyncing\n", params.desync_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,params.desync_cutoff_mode), params.desync_cutoff); + DLOG("desync-cutoff reached (mode %c): %llu/%u . not desyncing\n", params.desync_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack, params.desync_cutoff_mode), params.desync_cutoff); return false; } - DLOG("desync-cutoff not reached (mode %c): %llu/%u\n", params.desync_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,params.desync_cutoff_mode), params.desync_cutoff); + DLOG("desync-cutoff not reached (mode %c): %llu/%u\n", params.desync_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack, params.desync_cutoff_mode), params.desync_cutoff); } else { @@ -498,17 +496,17 @@ static size_t pos_normalize(size_t split_pos, size_t reasm_offset, size_t len_pa { size_t rsplit_pos = split_pos; // normalize split pos to current packet - split_pos=(split_pos>reasm_offset && (split_pos-reasm_offset) reasm_offset && (split_pos - reasm_offset) < len_payload) ? split_pos - reasm_offset : 0; if (rsplit_pos) { - if (split_pos==rsplit_pos) - DLOG("split pos %zu\n",split_pos); + if (split_pos == rsplit_pos) + DLOG("split pos %zu\n", split_pos); else { if (split_pos) - DLOG("split pos was normalized to packet data offset : %zu -> %zu\n",rsplit_pos,split_pos); + DLOG("split pos was normalized to packet data offset : %zu -> %zu\n", rsplit_pos, split_pos); else - DLOG("split pos %zu is outside of this packet %zu-%zu\n",rsplit_pos,reasm_offset,reasm_offset+len_payload); + DLOG("split pos %zu is outside of this packet %zu-%zu\n", rsplit_pos, reasm_offset, reasm_offset + len_payload); } } return split_pos; @@ -516,18 +514,19 @@ static size_t pos_normalize(size_t split_pos, size_t reasm_offset, size_t len_pa static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t transport_len, uint8_t *data_payload, size_t len_payload) { - uint8_t verdict=VERDICT_PASS; + uint8_t verdict = VERDICT_PASS; // additional safety check - if (!!ip == !!ip6hdr) return verdict; + if (!!ip == !!ip6hdr) + return verdict; - t_ctrack *ctrack=NULL, *ctrack_replay=NULL; - bool bReverse=false; + t_ctrack *ctrack = NULL, *ctrack_replay = NULL; + bool bReverse = false; struct sockaddr_storage src, dst; - uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100]; + uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN + 100], pkt2[DPI_DESYNC_MAX_FAKE_LEN + 100]; size_t pkt1_len, pkt2_len; - uint8_t ttl_orig,ttl_fake,flags_orig,scale_factor; + uint8_t ttl_orig, ttl_fake, flags_orig, scale_factor; uint32_t *timestamps; ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim; @@ -537,7 +536,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { // in replay mode conntrack_replay is not NULL and ctrack is NULL - //ConntrackPoolDump(¶ms.conntrack); + // ConntrackPoolDump(¶ms.conntrack); if (!ConntrackPoolDoubleSearch(¶ms.conntrack, ip, ip6hdr, tcphdr, NULL, &ctrack_replay, &bReverse) || bReverse) return verdict; } @@ -553,24 +552,24 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters); - //ConntrackPoolDump(¶ms.conntrack); + // ConntrackPoolDump(¶ms.conntrack); if (params.wsize && tcp_synack_segment(tcphdr)) { tcp_rewrite_winsize(tcphdr, params.wsize, params.wscale); - verdict=VERDICT_MODIFY; + verdict = VERDICT_MODIFY; } - + if (bReverse) { - if (ctrack && !ctrack->autottl && ctrack->pcounter_reply==1) + if (ctrack && !ctrack->autottl && ctrack->pcounter_reply == 1) { autottl *attl = ip ? ¶ms.desync_autottl : ¶ms.desync_autottl6; if (AUTOTTL_ENABLED(*attl)) { ctrack->autottl = autottl_guess(ttl_orig, attl); if (ctrack->autottl) - DLOG("autottl: guessed %u\n",ctrack->autottl); + DLOG("autottl: guessed %u\n", ctrack->autottl); else DLOG("autottl: could not guess\n"); } @@ -579,18 +578,18 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint // process reply packets for auto hostlist mode // by looking at RSTs or HTTP replies we decide whether original request looks like DPI blocked // we only process first-sequence replies. do not react to subsequent redirects or RSTs - if (ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->ack_last-ctrack->ack0)==1) + if (ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->ack_last - ctrack->ack0) == 1) { - bool bFail=false; + bool bFail = false; if (tcphdr->th_flags & TH_RST) { DLOG("incoming RST detected for hostname %s\n", ctrack->hostname); HOSTLIST_DEBUGLOG_APPEND("%s : incoming RST", ctrack->hostname); bFail = true; } - else if (len_payload && ctrack->l7proto==HTTP) + else if (len_payload && ctrack->l7proto == HTTP) { - if (IsHttpReply(data_payload,len_payload)) + if (IsHttpReply(data_payload, len_payload)) { DLOG("incoming HTTP reply detected for hostname %s\n", ctrack->hostname); bFail = HttpReplyLooksLikeDPIRedirect(data_payload, len_payload, ctrack->hostname); @@ -610,17 +609,15 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } if (bFail) auto_hostlist_failed(ctrack->hostname); - else - if (len_payload) - auto_hostlist_reset_fail_counter(ctrack->hostname); + else if (len_payload) + auto_hostlist_reset_fail_counter(ctrack->hostname); if (tcphdr->th_flags & TH_RST) ConntrackClearHostname(ctrack); // do not react to further dup RSTs } - + return verdict; // nothing to do. do not waste cpu } - if (params.wssize) { if (ctrack) @@ -631,9 +628,10 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } else { - if (params.wssize_cutoff) DLOG("wssize-cutoff not reached (mode %c): %llu/%u\n", params.wssize_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,params.wssize_cutoff_mode), params.wssize_cutoff); + if (params.wssize_cutoff) + DLOG("wssize-cutoff not reached (mode %c): %llu/%u\n", params.wssize_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack, params.wssize_cutoff_mode), params.wssize_cutoff); tcp_rewrite_winsize(tcphdr, params.wssize, params.wsscale); - verdict=VERDICT_MODIFY; + verdict = VERDICT_MODIFY; } } else @@ -644,7 +642,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } // !replay ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (ip6hdr ? (params.desync_ttl6 ? params.desync_ttl6 : ttl_orig) : (params.desync_ttl ? params.desync_ttl : ttl_orig)); - flags_orig = *((uint8_t*)tcphdr+13); + flags_orig = *((uint8_t *)tcphdr + 13); scale_factor = tcp_find_scale_factor(tcphdr); timestamps = tcp_find_timestamps(tcphdr); @@ -656,61 +654,64 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { switch (params.desync_mode0) { - case DESYNC_SYNACK: - pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, - NULL, 0, pkt1, &pkt1_len)) - { - return verdict; - } - DLOG("sending fake SYNACK\n"); - if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + case DESYNC_SYNACK: + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN | TH_ACK, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_fake, params.desync_fooling_mode, params.desync_badseq_increment, params.desync_badseq_ack_increment, + NULL, 0, pkt1, &pkt1_len)) + { + return verdict; + } + DLOG("sending fake SYNACK\n"); + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + break; + case DESYNC_SYNDATA: + // make sure we are not breaking TCP fast open + if (tcp_has_fastopen(tcphdr)) + { + DLOG("received SYN with TCP fast open option. syndata desync is not applied.\n"); break; - case DESYNC_SYNDATA: - // make sure we are not breaking TCP fast open - if (tcp_has_fastopen(tcphdr)) - { - DLOG("received SYN with TCP fast open option. syndata desync is not applied.\n"); - break; - } - if (len_payload) - { - DLOG("received SYN with data payload. syndata desync is not applied.\n"); - break; - } - pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_orig,0,0,0, params.fake_syndata,params.fake_syndata_size, pkt1,&pkt1_len)) - { - return verdict; - } - DLOG("sending SYN with fake data : "); - hexdump_limited_dlog(params.fake_syndata,params.fake_syndata_size,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - verdict = ct_new_postnat_fix_tcp(ctrack, ip, ip6hdr, tcphdr); - break; - default: + } + if (len_payload) + { + DLOG("received SYN with data payload. syndata desync is not applied.\n"); break; + } + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_orig, 0, 0, 0, params.fake_syndata, params.fake_syndata_size, pkt1, &pkt1_len)) + { + return verdict; + } + DLOG("sending SYN with fake data : "); + hexdump_limited_dlog(params.fake_syndata, params.fake_syndata_size, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + verdict = ct_new_postnat_fix_tcp(ctrack, ip, ip6hdr, tcphdr); + break; + default: + break; } // can do nothing else with SYN packet return verdict; } // start and cutoff limiters - if (!process_desync_interval(ctrack)) return verdict; + if (!process_desync_interval(ctrack)) + return verdict; } // !replay - - if (!params.wssize && params.desync_mode==DESYNC_NONE && !params.hostcase && !params.hostnospace && !params.domcase && !*params.hostlist_auto_filename) return verdict; // nothing to do. do not waste cpu - + + if (!params.wssize && params.desync_mode == DESYNC_NONE && !params.hostcase && !params.hostnospace && !params.domcase && !*params.hostlist_auto_filename) + return verdict; // nothing to do. do not waste cpu + if (!(tcphdr->th_flags & TH_SYN) && len_payload) { const uint8_t *fake; size_t fake_size; char host[256]; - bool bHaveHost=false; + bool bHaveHost = false; bool bIsHttp; bool bKnownProtocol = false; uint8_t *p, *phost; @@ -723,7 +724,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint rdata_payload = ctrack_replay->reasm_orig.packet; rlen_payload = ctrack_replay->reasm_orig.size_present; } - else if (reasm_orig_feed(ctrack,IPPROTO_TCP,data_payload,len_payload)) + else if (reasm_orig_feed(ctrack, IPPROTO_TCP, data_payload, len_payload)) { rdata_payload = ctrack->reasm_orig.packet; rlen_payload = ctrack->reasm_orig.size_present; @@ -731,20 +732,21 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint process_retrans_fail(ctrack, IPPROTO_TCP); - if ((bIsHttp = IsHttp(rdata_payload,rlen_payload))) + if ((bIsHttp = IsHttp(rdata_payload, rlen_payload))) { DLOG("packet contains HTTP request\n"); - if (ctrack && !ctrack->l7proto) ctrack->l7proto = HTTP; + if (ctrack && !ctrack->l7proto) + ctrack->l7proto = HTTP; // we do not reassemble http reasm_orig_cancel(ctrack); - + forced_wssize_cutoff(ctrack); fake = params.fake_http; fake_size = params.fake_http_size; if (params.hostlist || params.hostlist_exclude) { - bHaveHost=HttpExtractHost(rdata_payload,rlen_payload,host,sizeof(host)); + bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, host, sizeof(host)); if (!bHaveHost) { DLOG("not applying tampering to HTTP without Host:\n"); @@ -756,52 +758,53 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint // we do not reassemble http if (!ctrack->req_seq_present) { - ctrack->req_seq_start=ctrack->seq_last; - ctrack->req_seq_end=ctrack->pos_orig-1; - ctrack->req_seq_present=ctrack->req_seq_finalized=true; - DLOG("req retrans : tcp seq interval %u-%u\n",ctrack->req_seq_start,ctrack->req_seq_end); + ctrack->req_seq_start = ctrack->seq_last; + ctrack->req_seq_end = ctrack->pos_orig - 1; + ctrack->req_seq_present = ctrack->req_seq_finalized = true; + DLOG("req retrans : tcp seq interval %u-%u\n", ctrack->req_seq_start, ctrack->req_seq_end); } } split_pos = HttpPos(params.desync_split_http_req, params.desync_split_pos, rdata_payload, rlen_payload); bKnownProtocol = true; } - else if (IsTLSClientHello(rdata_payload,rlen_payload,TLS_PARTIALS_ENABLE)) + else if (IsTLSClientHello(rdata_payload, rlen_payload, TLS_PARTIALS_ENABLE)) { - bool bReqFull = IsTLSRecordFull(rdata_payload,rlen_payload); + bool bReqFull = IsTLSRecordFull(rdata_payload, rlen_payload); DLOG(bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n"); - bHaveHost=TLSHelloExtractHost(rdata_payload,rlen_payload,host,sizeof(host),TLS_PARTIALS_ENABLE); + bHaveHost = TLSHelloExtractHost(rdata_payload, rlen_payload, host, sizeof(host), TLS_PARTIALS_ENABLE); if (ctrack) { - if (!ctrack->l7proto) ctrack->l7proto = TLS; + if (!ctrack->l7proto) + ctrack->l7proto = TLS; // do not reasm retransmissions if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_orig) && !ctrack->req_seq_abandoned && !(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end))) { // do not reconstruct unexpected large payload (they are feeding garbage ?) - if (!reasm_orig_start(ctrack,IPPROTO_TCP,TLSRecordLen(data_payload),16384,data_payload,len_payload)) + if (!reasm_orig_start(ctrack, IPPROTO_TCP, TLSRecordLen(data_payload), 16384, data_payload, len_payload)) { reasm_orig_cancel(ctrack); return verdict; } - } if (!ctrack->req_seq_finalized) { if (!ctrack->req_seq_present) { // lower bound of request seq interval - ctrack->req_seq_start=ctrack->seq_last; - ctrack->req_seq_present=true; + ctrack->req_seq_start = ctrack->seq_last; + ctrack->req_seq_present = true; } // upper bound of request seq interval // it can grow on every packet until request is complete. then interval is finalized and never touched again. - ctrack->req_seq_end=ctrack->pos_orig-1; - DLOG("req retrans : seq interval %u-%u\n",ctrack->req_seq_start,ctrack->req_seq_end); + ctrack->req_seq_end = ctrack->pos_orig - 1; + DLOG("req retrans : seq interval %u-%u\n", ctrack->req_seq_start, ctrack->req_seq_end); ctrack->req_seq_finalized |= bReqFull; } - if (bReqFull || ReasmIsEmpty(&ctrack->reasm_orig)) forced_wssize_cutoff(ctrack); + if (bReqFull || ReasmIsEmpty(&ctrack->reasm_orig)) + forced_wssize_cutoff(ctrack); if (!ReasmIsEmpty(&ctrack->reasm_orig)) { @@ -831,28 +834,29 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint reasm_orig_cancel(ctrack); return verdict; } - + fake = params.fake_tls; fake_size = params.fake_tls_size; split_pos = TLSPos(params.desync_split_tls, params.desync_split_pos, rdata_payload, rlen_payload, 0); bKnownProtocol = true; } else - split_pos=params.desync_split_pos; + split_pos = params.desync_split_pos; reasm_orig_cancel(ctrack); - rdata_payload=NULL; + rdata_payload = NULL; if (ctrack && ctrack->req_seq_finalized) { uint32_t dseq = ctrack->seq_last - ctrack->req_seq_end; // do not react to 32-bit overflowed sequence numbers. allow 16 Mb grace window then cutoff. - if (dseq>=0x1000000 && !(dseq & 0x80000000)) ctrack->req_seq_abandoned=true; + if (dseq >= 0x1000000 && !(dseq & 0x80000000)) + ctrack->req_seq_abandoned = true; } if (bHaveHost) { - DLOG("hostname: %s\n",host); + DLOG("hostname: %s\n", host); if (params.hostlist || params.hostlist_exclude) { bool bBypass; @@ -865,7 +869,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint ctrack_replay->hostname_ah_check = *params.hostlist_auto_filename && !bBypass; if (ctrack_replay->hostname_ah_check) { - if (!ctrack_replay->hostname) ctrack_replay->hostname=strdup(host); + if (!ctrack_replay->hostname) + ctrack_replay->hostname = strdup(host); } else ctrack_stop_retrans_counter(ctrack_replay); @@ -875,34 +880,35 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } } } - + if (!bKnownProtocol) { - if (!params.desync_any_proto) return verdict; + if (!params.desync_any_proto) + return verdict; DLOG("applying tampering to unknown protocol\n"); fake = params.fake_unknown; fake_size = params.fake_unknown_size; } - if (bIsHttp && (params.hostcase || params.hostnospace || params.domcase) && (phost = (uint8_t*)memmem(data_payload, len_payload, "\r\nHost: ", 8))) + if (bIsHttp && (params.hostcase || params.hostnospace || params.domcase) && (phost = (uint8_t *)memmem(data_payload, len_payload, "\r\nHost: ", 8))) { if (params.hostcase) { DLOG("modifying Host: => %c%c%c%c:\n", params.hostspell[0], params.hostspell[1], params.hostspell[2], params.hostspell[3]); memcpy(phost + 2, params.hostspell, 4); - verdict=VERDICT_MODIFY; + verdict = VERDICT_MODIFY; } if (params.domcase) { DLOG("mixing domain case\n"); - for (p = phost+7; p < (data_payload + len_payload) && *p != '\r' && *p != '\n'; p++) + for (p = phost + 7; p < (data_payload + len_payload) && *p != '\r' && *p != '\n'; p++) *p = (((size_t)p) & 1) ? tolower(*p) : toupper(*p); - verdict=VERDICT_MODIFY; + verdict = VERDICT_MODIFY; } uint8_t *pua; if (params.hostnospace && - (pua = (uint8_t*)memmem(data_payload, len_payload, "\r\nUser-Agent: ", 14)) && - (pua = (uint8_t*)memmem(pua + 1, len_payload - (pua - data_payload) - 1, "\r\n", 2))) + (pua = (uint8_t *)memmem(data_payload, len_payload, "\r\nUser-Agent: ", 14)) && + (pua = (uint8_t *)memmem(pua + 1, len_payload - (pua - data_payload) - 1, "\r\n", 2))) { DLOG("removing space after Host: and adding it to User-Agent:\n"); if (pua > phost) @@ -915,22 +921,24 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint memmove(pua + 1, pua, phost - pua + 7); *pua = ' '; } - verdict=VERDICT_MODIFY; + verdict = VERDICT_MODIFY; } } - if (params.desync_mode==DESYNC_NONE) return verdict; + if (params.desync_mode == DESYNC_NONE) + return verdict; if (params.debug) { - char s1[48],s2[48]; + char s1[48], s2[48]; ntop46_port((struct sockaddr *)&src, s1, sizeof(s1)); ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2)); - DLOG("dpi desync src=%s dst=%s\n",s1,s2); + DLOG("dpi desync src=%s dst=%s\n", s1, s2); } - - if (!split_pos || split_pos>rlen_payload) split_pos=1; - split_pos=pos_normalize(split_pos,reasm_offset,len_payload); + + if (!split_pos || split_pos > rlen_payload) + split_pos = 1; + split_pos = pos_normalize(split_pos, reasm_offset, len_payload); enum dpi_desync_mode desync_mode = params.desync_mode; uint32_t fooling_orig = FOOL_NONE; @@ -938,78 +946,82 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); b = false; - switch(desync_mode) + switch (desync_mode) { - case DESYNC_FAKE_KNOWN: - if (reasm_offset) - { - desync_mode = params.desync_mode2; - break; - } - if (!bKnownProtocol) - { - DLOG("not applying fake because of unknown protocol\n"); - desync_mode = params.desync_mode2; - break; - } - case DESYNC_FAKE: - if (reasm_offset) break; - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, - fake, fake_size, pkt1, &pkt1_len)) - { - return verdict; - } - DLOG("sending fake request : "); - hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n"); - b = true; - break; - case DESYNC_RST: - case DESYNC_RSTACK: - if (reasm_offset) break; - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (desync_mode==DESYNC_RSTACK ? TH_ACK:0), tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, - NULL, 0, pkt1, &pkt1_len)) - { - return verdict; - } - DLOG("sending fake RST/RSTACK\n"); - b = true; - break; - case DESYNC_HOPBYHOP: - case DESYNC_DESTOPT: - case DESYNC_IPFRAG1: - fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; + case DESYNC_FAKE_KNOWN: + if (reasm_offset) + { desync_mode = params.desync_mode2; - if (ip6hdr && (desync_mode==DESYNC_NONE || !desync_valid_second_stage_tcp(desync_mode) || - (!split_pos && (desync_mode==DESYNC_SPLIT || desync_mode==DESYNC_SPLIT2 || desync_mode==DESYNC_DISORDER || desync_mode==DESYNC_DISORDER2)))) - { - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_orig,fooling_orig,0,0, - data_payload, len_payload, pkt1, &pkt1_len)) - { - return verdict; - } - DLOG("resending original packet with extension header\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - // this mode is final, no other options available - return VERDICT_DROP; - } - default: - pkt1_len=0; break; + } + if (!bKnownProtocol) + { + DLOG("not applying fake because of unknown protocol\n"); + desync_mode = params.desync_mode2; + break; + } + case DESYNC_FAKE: + if (reasm_offset) + break; + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_fake, params.desync_fooling_mode, params.desync_badseq_increment, params.desync_badseq_ack_increment, + fake, fake_size, pkt1, &pkt1_len)) + { + return verdict; + } + DLOG("sending fake request : "); + hexdump_limited_dlog(fake, fake_size, PKTDATA_MAXDUMP); + DLOG("\n"); + b = true; + break; + case DESYNC_RST: + case DESYNC_RSTACK: + if (reasm_offset) + break; + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (desync_mode == DESYNC_RSTACK ? TH_ACK : 0), tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_fake, params.desync_fooling_mode, params.desync_badseq_increment, params.desync_badseq_ack_increment, + NULL, 0, pkt1, &pkt1_len)) + { + return verdict; + } + DLOG("sending fake RST/RSTACK\n"); + b = true; + break; + case DESYNC_HOPBYHOP: + case DESYNC_DESTOPT: + case DESYNC_IPFRAG1: + fooling_orig = (desync_mode == DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode == DESYNC_DESTOPT) ? FOOL_DESTOPT + : FOOL_IPFRAG1; + desync_mode = params.desync_mode2; + if (ip6hdr && (desync_mode == DESYNC_NONE || !desync_valid_second_stage_tcp(desync_mode) || + (!split_pos && (desync_mode == DESYNC_SPLIT || desync_mode == DESYNC_SPLIT2 || desync_mode == DESYNC_DISORDER || desync_mode == DESYNC_DISORDER2)))) + { + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_orig, fooling_orig, 0, 0, + data_payload, len_payload, pkt1, &pkt1_len)) + { + return verdict; + } + DLOG("resending original packet with extension header\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + // this mode is final, no other options available + return VERDICT_DROP; + } + default: + pkt1_len = 0; + break; } if (b) { - if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) return verdict; - if (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(params.desync_mode2)) + if (params.desync_mode2 == DESYNC_NONE || !desync_valid_second_stage_tcp(params.desync_mode2)) { DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", *len_pkt, len_payload); verdict_tcp_csum_fix(verdict, tcphdr, transport_len, ip, ip6hdr); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , data_pkt, *len_pkt)) + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, data_pkt, *len_pkt)) return verdict; return VERDICT_DROP; } @@ -1017,202 +1029,210 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } pkt1_len = sizeof(pkt1); - switch(desync_mode) + switch (desync_mode) { - case DESYNC_DISORDER: - case DESYNC_DISORDER2: - if (split_pos) + case DESYNC_DISORDER: + case DESYNC_DISORDER2: + if (split_pos) + { + uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN + 100], *seg; + size_t seg_len; + + if (params.desync_seqovl >= split_pos) { - uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg; - size_t seg_len; - - if (params.desync_seqovl>=split_pos) - { - DLOG("seqovl>=split_pos. desync is not possible.\n"); - return verdict; - } - - if (split_possizeof(fakeseg)) - { - DLOG("seqovl is too large\n"); - return verdict; - } - fill_pattern(fakeseg,params.desync_seqovl,params.seqovl_pattern,sizeof(params.seqovl_pattern)); - memcpy(fakeseg+params.desync_seqovl,data_payload+split_pos,len_payload-split_pos); - seg = fakeseg; - } - else - { - seg = data_payload+split_pos; - seg_len = len_payload-split_pos; - } - - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(net32_add(tcphdr->th_seq,split_pos),-params.desync_seqovl), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_orig,fooling_orig,params.desync_badseq_increment,params.desync_badseq_ack_increment, - seg, seg_len, pkt1, &pkt1_len)) - return verdict; - DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ",split_pos,len_payload-1, len_payload-split_pos, params.desync_seqovl); - hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - } - - - if (desync_mode==DESYNC_DISORDER) - { - seg_len = sizeof(fakeseg); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, - zeropkt, split_pos, fakeseg, &seg_len)) - return verdict; - DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); - hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len)) - return verdict; - } - - pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_orig,fooling_orig,params.desync_badseq_increment,params.desync_badseq_ack_increment, - data_payload, split_pos, pkt1, &pkt1_len)) - return verdict; - DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); - hexdump_limited_dlog(data_payload,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - - if (desync_mode==DESYNC_DISORDER) - { - DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); - hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len)) - return verdict; - } - - return VERDICT_DROP; + DLOG("seqovl>=split_pos. desync is not possible.\n"); + return verdict; } - break; - case DESYNC_SPLIT: - case DESYNC_SPLIT2: - if (split_pos) + + if (split_pos < len_payload) { - uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100],ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg; - size_t fakeseg_len,seg_len; - - if (desync_mode==DESYNC_SPLIT) - { - fakeseg_len = sizeof(fakeseg); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, - zeropkt, split_pos, fakeseg, &fakeseg_len)) - return verdict; - DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); - hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len)) - return verdict; - } - if (params.desync_seqovl) { - seg_len = split_pos+params.desync_seqovl; - if (seg_len>sizeof(ovlseg)) + seg_len = len_payload - split_pos + params.desync_seqovl; + if (seg_len > sizeof(fakeseg)) { - DLOG("seqovl is too large"); + DLOG("seqovl is too large\n"); return verdict; } - fill_pattern(ovlseg,params.desync_seqovl,params.seqovl_pattern,sizeof(params.seqovl_pattern)); - memcpy(ovlseg+params.desync_seqovl,data_payload,split_pos); - seg = ovlseg; + fill_pattern(fakeseg, params.desync_seqovl, params.seqovl_pattern, sizeof(params.seqovl_pattern)); + memcpy(fakeseg + params.desync_seqovl, data_payload + split_pos, len_payload - split_pos); + seg = fakeseg; } else { - seg = data_payload; - seg_len = split_pos; + seg = data_payload + split_pos; + seg_len = len_payload - split_pos; } - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->th_seq,-params.desync_seqovl), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_orig,fooling_orig,params.desync_badseq_increment,params.desync_badseq_ack_increment, - seg, seg_len, pkt1, &pkt1_len)) + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(net32_add(tcphdr->th_seq, split_pos), -params.desync_seqovl), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_orig, fooling_orig, params.desync_badseq_increment, params.desync_badseq_ack_increment, + seg, seg_len, pkt1, &pkt1_len)) return verdict; - DLOG("sending 1st tcp segment 0-%zu len=%zu seqovl=%u : ",split_pos-1, split_pos, params.desync_seqovl); - hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ", split_pos, len_payload - 1, len_payload - split_pos, params.desync_seqovl); + hexdump_limited_dlog(seg, seg_len, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) return verdict; - - if (desync_mode==DESYNC_SPLIT) - { - DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); - hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len)) - return verdict; - } - if (split_posth_seq,split_pos), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_orig,fooling_orig,params.desync_badseq_increment,params.desync_badseq_ack_increment, - data_payload+split_pos, len_payload-split_pos, pkt1, &pkt1_len)) - return verdict; - DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ",split_pos,len_payload-1, len_payload-split_pos); - hexdump_limited_dlog(data_payload+split_pos,len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - } - - return VERDICT_DROP; } - break; - case DESYNC_IPFRAG2: - if (!reasm_offset) + + if (desync_mode == DESYNC_DISORDER) { - verdict_tcp_csum_fix(verdict, tcphdr, transport_len, ip, ip6hdr); - - uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN+100], *pkt_orig; - size_t pkt_orig_len; - - size_t ipfrag_pos = (params.desync_ipfrag_pos_tcp && params.desync_ipfrag_pos_tcpip_id ? ip->ip_id : htons(1+random()%0xFFFF) : htonl(1+random()%0xFFFFFFFF); - - pkt1_len = sizeof(pkt1); - pkt2_len = sizeof(pkt2); - - if (ip6hdr && (fooling_orig==FOOL_HOPBYHOP || fooling_orig==FOOL_DESTOPT)) - { - pkt_orig_len = sizeof(pkt3); - if (!ip6_insert_simple_hdr(fooling_orig==FOOL_HOPBYHOP ? IPPROTO_HOPOPTS : IPPROTO_DSTOPTS, data_pkt, *len_pkt, pkt3, &pkt_orig_len)) - return verdict; - pkt_orig = pkt3; - } - else - { - pkt_orig = data_pkt; - pkt_orig_len = *len_pkt; - } - - if (!ip_frag(pkt_orig, pkt_orig_len, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len)) + seg_len = sizeof(fakeseg); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_fake, params.desync_fooling_mode, params.desync_badseq_increment, params.desync_badseq_ack_increment, + zeropkt, split_pos, fakeseg, &seg_len)) return verdict; - - DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos-1, ipfrag_pos); - hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); + hexdump_limited_dlog(zeropkt, split_pos, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len)) return verdict; - - DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, transport_len-1, transport_len-ipfrag_pos); - hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt2, pkt2_len)) - return verdict; - - return VERDICT_DROP; } - default: - break; + + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_orig, fooling_orig, params.desync_badseq_increment, params.desync_badseq_ack_increment, + data_payload, split_pos, pkt1, &pkt1_len)) + return verdict; + DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); + hexdump_limited_dlog(data_payload, split_pos, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + + if (desync_mode == DESYNC_DISORDER) + { + DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); + hexdump_limited_dlog(zeropkt, split_pos, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len)) + return verdict; + } + + return VERDICT_DROP; + } + break; + case DESYNC_SPLIT: + case DESYNC_SPLIT2: + if (split_pos) + { + uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN + 100], ovlseg[DPI_DESYNC_MAX_FAKE_LEN + 100], *seg; + size_t fakeseg_len, seg_len; + + if (desync_mode == DESYNC_SPLIT) + { + fakeseg_len = sizeof(fakeseg); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_fake, params.desync_fooling_mode, params.desync_badseq_increment, params.desync_badseq_ack_increment, + zeropkt, split_pos, fakeseg, &fakeseg_len)) + return verdict; + DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); + hexdump_limited_dlog(zeropkt, split_pos, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len)) + return verdict; + } + + if (params.desync_seqovl) + { + seg_len = split_pos + params.desync_seqovl; + if (seg_len > sizeof(ovlseg)) + { + DLOG("seqovl is too large"); + return verdict; + } + fill_pattern(ovlseg, params.desync_seqovl, params.seqovl_pattern, sizeof(params.seqovl_pattern)); + memcpy(ovlseg + params.desync_seqovl, data_payload, split_pos); + seg = ovlseg; + } + else + { + seg = data_payload; + seg_len = split_pos; + } + + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->th_seq, -params.desync_seqovl), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_orig, fooling_orig, params.desync_badseq_increment, params.desync_badseq_ack_increment, + seg, seg_len, pkt1, &pkt1_len)) + return verdict; + DLOG("sending 1st tcp segment 0-%zu len=%zu seqovl=%u : ", split_pos - 1, split_pos, params.desync_seqovl); + hexdump_limited_dlog(seg, seg_len, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + + if (desync_mode == DESYNC_SPLIT) + { + DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); + hexdump_limited_dlog(zeropkt, split_pos, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len)) + return verdict; + } + if (split_pos < len_payload) + { + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->th_seq, split_pos), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_orig, fooling_orig, params.desync_badseq_increment, params.desync_badseq_ack_increment, + data_payload + split_pos, len_payload - split_pos, pkt1, &pkt1_len)) + return verdict; + DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ", split_pos, len_payload - 1, len_payload - split_pos); + hexdump_limited_dlog(data_payload + split_pos, len_payload - split_pos, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + } + + return VERDICT_DROP; + } + break; + case DESYNC_IPFRAG2: + if (!reasm_offset) + { + verdict_tcp_csum_fix(verdict, tcphdr, transport_len, ip, ip6hdr); + + uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN + 100], *pkt_orig; + size_t pkt_orig_len; + + size_t ipfrag_pos = (params.desync_ipfrag_pos_tcp && params.desync_ipfrag_pos_tcp < transport_len) ? params.desync_ipfrag_pos_tcp : 24; + uint32_t ident = ip ? ip->ip_id ? ip->ip_id : htons(1 + random() % 0xFFFF) : htonl(1 + random() % 0xFFFFFFFF); + + pkt1_len = sizeof(pkt1); + pkt2_len = sizeof(pkt2); + + if (ip6hdr && (fooling_orig == FOOL_HOPBYHOP || fooling_orig == FOOL_DESTOPT)) + { + pkt_orig_len = sizeof(pkt3); + if (!ip6_insert_simple_hdr(fooling_orig == FOOL_HOPBYHOP ? IPPROTO_HOPOPTS : IPPROTO_DSTOPTS, data_pkt, *len_pkt, pkt3, &pkt_orig_len)) + return verdict; + pkt_orig = pkt3; + } + else + { + pkt_orig = data_pkt; + pkt_orig_len = *len_pkt; + } + + if (!ip_frag(pkt_orig, pkt_orig_len, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len)) + return verdict; + + DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos - 1, ipfrag_pos); + hexdump_limited_dlog(pkt1, pkt1_len, IP_MAXDUMP); + DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + + DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, transport_len - 1, transport_len - ipfrag_pos); + hexdump_limited_dlog(pkt2, pkt2_len, IP_MAXDUMP); + DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt2, pkt2_len)) + return verdict; + + return VERDICT_DROP; + } + default: + break; } - } return verdict; @@ -1224,39 +1244,41 @@ static bool quic_reasm_cancel(t_ctrack *ctrack, const char *reason) reasm_orig_cancel(ctrack); if (params.desync_any_proto) { - DLOG("%s. applying tampering because desync_any_proto is set\n",reason); + DLOG("%s. applying tampering because desync_any_proto is set\n", reason); return true; } else { - DLOG("%s. not applying tampering because desync_any_proto is not set\n",reason); + DLOG("%s. not applying tampering because desync_any_proto is not set\n", reason); return false; } } static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct udphdr *udphdr, size_t transport_len, uint8_t *data_payload, size_t len_payload) { - uint8_t verdict=VERDICT_PASS; + uint8_t verdict = VERDICT_PASS; // additional safety check - if (!!ip == !!ip6hdr) return verdict; + if (!!ip == !!ip6hdr) + return verdict; // no need to desync middle packets in reasm session - if (reasm_offset) return verdict; + if (reasm_offset) + return verdict; - t_ctrack *ctrack=NULL, *ctrack_replay=NULL; - bool bReverse=false; + t_ctrack *ctrack = NULL, *ctrack_replay = NULL; + bool bReverse = false; struct sockaddr_storage src, dst; - uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100]; + uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN + 100], pkt2[DPI_DESYNC_MAX_FAKE_LEN + 100]; size_t pkt1_len, pkt2_len; - uint8_t ttl_orig,ttl_fake; - + uint8_t ttl_orig, ttl_fake; + if (replay) { // in replay mode conntrack_replay is not NULL and ctrack is NULL - //ConntrackPoolDump(¶ms.conntrack); + // ConntrackPoolDump(¶ms.conntrack); if (!ConntrackPoolDoubleSearch(¶ms.conntrack, ip, ip6hdr, NULL, udphdr, &ctrack_replay, &bReverse) || bReverse) return verdict; } @@ -1271,35 +1293,41 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint maybe_cutoff(ctrack, IPPROTO_UDP); } HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters); - //ConntrackPoolDump(¶ms.conntrack); + // ConntrackPoolDump(¶ms.conntrack); } - if (bReverse) return verdict; // nothing to do. do not waste cpu + if (bReverse) + return verdict; // nothing to do. do not waste cpu - if (params.desync_mode==DESYNC_NONE && !*params.hostlist_auto_filename) return verdict; // do not waste cpu + if (params.desync_mode == DESYNC_NONE && !*params.hostlist_auto_filename) + return verdict; // do not waste cpu // start and cutoff limiters - if (!replay && !process_desync_interval(ctrack)) return verdict; + if (!replay && !process_desync_interval(ctrack)) + return verdict; uint32_t desync_fwmark = fwmark | params.desync_fwmark; ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim; - if (ip6hdr) ttl_fake = params.desync_ttl6 ? params.desync_ttl6 : ttl_orig; - else ttl_fake = params.desync_ttl ? params.desync_ttl : ttl_orig; + if (ip6hdr) + ttl_fake = params.desync_ttl6 ? params.desync_ttl6 : ttl_orig; + else + ttl_fake = params.desync_ttl ? params.desync_ttl : ttl_orig; extract_endpoints(ip, ip6hdr, NULL, udphdr, &src, &dst); - + if (len_payload) { const uint8_t *fake; size_t fake_size; bool b; char host[256]; - bool bHaveHost=false; - bool bKnownProtocol=false; + bool bHaveHost = false; + bool bKnownProtocol = false; - if (IsQUICInitial(data_payload,len_payload)) + if (IsQUICInitial(data_payload, len_payload)) { DLOG("packet contains QUIC initial\n"); - if (ctrack && !ctrack->l7proto) ctrack->l7proto = QUIC; + if (ctrack && !ctrack->l7proto) + ctrack->l7proto = QUIC; uint8_t clean[16384], *pclean; size_t clean_len; @@ -1312,7 +1340,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint else { clean_len = sizeof(clean); - pclean = QUICDecryptInitial(data_payload,len_payload,clean,&clean_len) ? clean : NULL; + pclean = QUICDecryptInitial(data_payload, len_payload, clean, &clean_len) ? clean : NULL; } if (pclean) { @@ -1320,7 +1348,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint { if (ReasmHasSpace(&ctrack->reasm_orig, clean_len)) { - reasm_orig_feed(ctrack,IPPROTO_UDP,clean,clean_len); + reasm_orig_feed(ctrack, IPPROTO_UDP, clean, clean_len); pclean = ctrack->reasm_orig.packet; clean_len = ctrack->reasm_orig.size_present; } @@ -1334,10 +1362,10 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint uint8_t defrag[16384]; size_t hello_offset, hello_len, defrag_len = sizeof(defrag); - if (QUICDefragCrypto(pclean,clean_len,defrag,&defrag_len)) + if (QUICDefragCrypto(pclean, clean_len, defrag, &defrag_len)) { bool bIsHello = IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len); - bool bReqFull = bIsHello ? IsTLSHandshakeFull(defrag+hello_offset,hello_len) : false; + bool bReqFull = bIsHello ? IsTLSHandshakeFull(defrag + hello_offset, hello_len) : false; DLOG(bIsHello ? bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n" : "packet does not contain TLS ClientHello\n"); @@ -1346,7 +1374,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig)) { // preallocate max buffer to avoid reallocs that cause memory copy - if (!reasm_orig_start(ctrack,IPPROTO_UDP,16384,16384,clean,clean_len)) + if (!reasm_orig_start(ctrack, IPPROTO_UDP, 16384, 16384, clean, clean_len)) { reasm_orig_cancel(ctrack); return verdict; @@ -1373,7 +1401,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint return ct_new_postnat_fix_udp(ctrack, ip, ip6hdr, udphdr, len_pkt); } } - + if (bIsHello) { bHaveHost = TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, sizeof(host), TLS_PARTIALS_ENABLE); @@ -1386,21 +1414,24 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint } else { - if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict; + if (!quic_reasm_cancel(ctrack, "QUIC initial without ClientHello")) + return verdict; } } else { // defrag failed - if (!quic_reasm_cancel(ctrack,"QUIC initial defrag CRYPTO failed")) return verdict; + if (!quic_reasm_cancel(ctrack, "QUIC initial defrag CRYPTO failed")) + return verdict; } } else { // decrypt failed - if (!quic_reasm_cancel(ctrack,"QUIC initial decryption failed")) return verdict; + if (!quic_reasm_cancel(ctrack, "QUIC initial decryption failed")) + return verdict; } - + fake = params.fake_quic; fake_size = params.fake_quic_size; bKnownProtocol = true; @@ -1409,28 +1440,31 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint { // received payload without host. it means we are out of the request retransmission phase. stop counter ctrack_stop_retrans_counter(ctrack); - + reasm_orig_cancel(ctrack); - if (IsWireguardHandshakeInitiation(data_payload,len_payload)) + if (IsWireguardHandshakeInitiation(data_payload, len_payload)) { - DLOG("packet contains wireguard handshake initiation\n"); - if (ctrack && !ctrack->l7proto) ctrack->l7proto = WIREGUARD; + DLOG("packet contains WireGuard handshake initiation\n"); + if (ctrack && !ctrack->l7proto) + ctrack->l7proto = WIREGUARD; fake = params.fake_wg; fake_size = params.fake_wg_size; bKnownProtocol = true; } - else if (IsDhtD1(data_payload,len_payload)) + else if (IsDhtD1(data_payload, len_payload)) { DLOG("packet contains DHT d1...e\n"); - if (ctrack && !ctrack->l7proto) ctrack->l7proto = DHT; + if (ctrack && !ctrack->l7proto) + ctrack->l7proto = DHT; fake = params.fake_dht; fake_size = params.fake_dht_size; bKnownProtocol = true; } else { - if (!params.desync_any_proto) return verdict; + if (!params.desync_any_proto) + return verdict; DLOG("applying tampering to unknown protocol\n"); fake = params.fake_unknown_udp; fake_size = params.fake_unknown_udp_size; @@ -1439,7 +1473,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (bHaveHost) { - DLOG("hostname: %s\n",host); + DLOG("hostname: %s\n", host); if (params.hostlist || params.hostlist_exclude) { bool bBypass; @@ -1454,7 +1488,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (ctrack_replay->hostname) process_retrans_fail(ctrack_replay, IPPROTO_UDP); else - ctrack_replay->hostname=strdup(host); + ctrack_replay->hostname = strdup(host); } } DLOG("not applying tampering to this request\n"); @@ -1468,204 +1502,215 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (params.debug) { - char s1[48],s2[48]; + char s1[48], s2[48]; ntop46_port((struct sockaddr *)&src, s1, sizeof(s1)); ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2)); - DLOG("dpi desync src=%s dst=%s\n",s1,s2); + DLOG("dpi desync src=%s dst=%s\n", s1, s2); } pkt1_len = sizeof(pkt1); b = false; - switch(desync_mode) + switch (desync_mode) { - case DESYNC_FAKE_KNOWN: - if (!bKnownProtocol) - { - DLOG("not applying fake because of unknown protocol\n"); - desync_mode = params.desync_mode2; - break; - } - case DESYNC_FAKE: - if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len)) - return verdict; - DLOG("sending fake request : "); - hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - b = true; - break; - case DESYNC_HOPBYHOP: - case DESYNC_DESTOPT: - case DESYNC_IPFRAG1: - fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; - if (ip6hdr && (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2))) - { - if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, - ttl_orig,fooling_orig,NULL,0,0, - data_payload, len_payload, pkt1, &pkt1_len)) - { - return verdict; - } - DLOG("resending original packet with extension header\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - // this mode is final, no other options available - return ct_new_postnat_fix_udp(ctrack, ip, ip6hdr, udphdr, len_pkt); - } + case DESYNC_FAKE_KNOWN: + if (!bKnownProtocol) + { + DLOG("not applying fake because of unknown protocol\n"); desync_mode = params.desync_mode2; break; - default: - pkt1_len=0; - break; + } + case DESYNC_FAKE: + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len)) + return verdict; + DLOG("sending fake request : "); + hexdump_limited_dlog(fake, fake_size, PKTDATA_MAXDUMP); + DLOG("\n"); + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + b = true; + break; + case DESYNC_HOPBYHOP: + case DESYNC_DESTOPT: + case DESYNC_IPFRAG1: + fooling_orig = (desync_mode == DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode == DESYNC_DESTOPT) ? FOOL_DESTOPT + : FOOL_IPFRAG1; + if (ip6hdr && (params.desync_mode2 == DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2))) + { + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, + ttl_orig, fooling_orig, NULL, 0, 0, + data_payload, len_payload, pkt1, &pkt1_len)) + { + return verdict; + } + DLOG("resending original packet with extension header\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + // this mode is final, no other options available + return ct_new_postnat_fix_udp(ctrack, ip, ip6hdr, udphdr, len_pkt); + } + desync_mode = params.desync_mode2; + break; + default: + pkt1_len = 0; + break; } if (b) { - if (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2)) + if (params.desync_mode2 == DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2)) { DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", *len_pkt, len_payload); verdict_udp_csum_fix(verdict, udphdr, transport_len, ip, ip6hdr); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , data_pkt, *len_pkt)) + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, data_pkt, *len_pkt)) return verdict; return ct_new_postnat_fix_udp(ctrack, ip, ip6hdr, udphdr, len_pkt); } desync_mode = params.desync_mode2; } - switch(desync_mode) + switch (desync_mode) { - case DESYNC_UDPLEN: + case DESYNC_UDPLEN: + pkt1_len = sizeof(pkt1); + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig, fooling_orig, params.udplen_pattern, sizeof(params.udplen_pattern), params.udplen_increment, data_payload, len_payload, pkt1, &pkt1_len)) + { + DLOG("could not construct packet with modified length. too large ?\n"); + return verdict; + } + DLOG("resending original packet with increased by %d length\n", params.udplen_increment); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; + return ct_new_postnat_fix_udp(ctrack, ip, ip6hdr, udphdr, len_pkt); + case DESYNC_TAMPER: + if (IsDhtD1(data_payload, len_payload)) + { + size_t szbuf, szcopy; + memcpy(pkt2, "d2:001:x", 8); + pkt2_len = 8; + szbuf = sizeof(pkt2) - pkt2_len; + szcopy = len_payload - 1; + if (szcopy > szbuf) + { + DLOG("packet is too long to tamper"); + return verdict; + } + memcpy(pkt2 + pkt2_len, data_payload + 1, szcopy); + pkt2_len += szcopy; pkt1_len = sizeof(pkt1); - if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,fooling_orig, params.udplen_pattern, sizeof(params.udplen_pattern), params.udplen_increment, data_payload, len_payload, pkt1, &pkt1_len)) + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig, fooling_orig, NULL, 0, 0, pkt2, pkt2_len, pkt1, &pkt1_len)) { DLOG("could not construct packet with modified length. too large ?\n"); return verdict; } - DLOG("resending original packet with increased by %d length\n", params.udplen_increment); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + DLOG("resending tampered DHT\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) return verdict; return ct_new_postnat_fix_udp(ctrack, ip, ip6hdr, udphdr, len_pkt); - case DESYNC_TAMPER: - if (IsDhtD1(data_payload,len_payload)) - { - size_t szbuf,szcopy; - memcpy(pkt2,"d2:001:x",8); - pkt2_len=8; - szbuf=sizeof(pkt2)-pkt2_len; - szcopy=len_payload-1; - if (szcopy>szbuf) - { - DLOG("packet is too long to tamper"); - return verdict; - } - memcpy(pkt2+pkt2_len,data_payload+1,szcopy); - pkt2_len+=szcopy; - pkt1_len = sizeof(pkt1); - if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,fooling_orig, NULL, 0 , 0, pkt2, pkt2_len, pkt1, &pkt1_len)) - { - DLOG("could not construct packet with modified length. too large ?\n"); - return verdict; - } - DLOG("resending tampered DHT\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - return ct_new_postnat_fix_udp(ctrack, ip, ip6hdr, udphdr, len_pkt); - } - else - { - DLOG("payload is not tamperable\n"); + } + else + { + DLOG("payload is not tamperable\n"); + return verdict; + } + case DESYNC_IPFRAG2: + { + verdict_udp_csum_fix(verdict, udphdr, transport_len, ip, ip6hdr); + + uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN + 100], *pkt_orig; + size_t pkt_orig_len; + + size_t ipfrag_pos = (params.desync_ipfrag_pos_udp && params.desync_ipfrag_pos_udp < transport_len) ? params.desync_ipfrag_pos_udp : sizeof(struct udphdr); + // freebsd do not set ip.id + uint32_t ident = ip ? ip->ip_id ? ip->ip_id : htons(1 + random() % 0xFFFF) : htonl(1 + random() % 0xFFFFFFFF); + + pkt1_len = sizeof(pkt1); + pkt2_len = sizeof(pkt2); + + if (ip6hdr && (fooling_orig == FOOL_HOPBYHOP || fooling_orig == FOOL_DESTOPT)) + { + pkt_orig_len = sizeof(pkt3); + if (!ip6_insert_simple_hdr(fooling_orig == FOOL_HOPBYHOP ? IPPROTO_HOPOPTS : IPPROTO_DSTOPTS, data_pkt, *len_pkt, pkt3, &pkt_orig_len)) return verdict; - } - case DESYNC_IPFRAG2: - { - verdict_udp_csum_fix(verdict, udphdr, transport_len, ip, ip6hdr); - - uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN+100], *pkt_orig; - size_t pkt_orig_len; - - size_t ipfrag_pos = (params.desync_ipfrag_pos_udp && params.desync_ipfrag_pos_udpip_id ? ip->ip_id : htons(1+random()%0xFFFF) : htonl(1+random()%0xFFFFFFFF); + pkt_orig = pkt3; + } + else + { + pkt_orig = data_pkt; + pkt_orig_len = *len_pkt; + } - pkt1_len = sizeof(pkt1); - pkt2_len = sizeof(pkt2); + if (!ip_frag(pkt_orig, pkt_orig_len, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len)) + return verdict; - if (ip6hdr && (fooling_orig==FOOL_HOPBYHOP || fooling_orig==FOOL_DESTOPT)) - { - pkt_orig_len = sizeof(pkt3); - if (!ip6_insert_simple_hdr(fooling_orig==FOOL_HOPBYHOP ? IPPROTO_HOPOPTS : IPPROTO_DSTOPTS, data_pkt, *len_pkt, pkt3, &pkt_orig_len)) - return verdict; - pkt_orig = pkt3; - } - else - { - pkt_orig = data_pkt; - pkt_orig_len = *len_pkt; - } + DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos - 1, ipfrag_pos); + hexdump_limited_dlog(pkt1, pkt1_len, IP_MAXDUMP); + DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) + return verdict; - if (!ip_frag(pkt_orig, pkt_orig_len, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len)) - return verdict; + DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, transport_len - 1, transport_len - ipfrag_pos); + hexdump_limited_dlog(pkt2, pkt2_len, IP_MAXDUMP); + DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt2, pkt2_len)) + return verdict; - DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos-1, ipfrag_pos); - hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - - DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, transport_len-1, transport_len-ipfrag_pos); - hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt2, pkt2_len)) - return verdict; - - return ct_new_postnat_fix_udp(ctrack, ip, ip6hdr, udphdr, len_pkt); - } - default: - break; + return ct_new_postnat_fix_udp(ctrack, ip, ip6hdr, udphdr, len_pkt); + } + default: + break; } - } return verdict; } - static void packet_debug(bool replay, uint8_t proto, const struct ip *ip, const struct ip6_hdr *ip6hdr, const struct tcphdr *tcphdr, const struct udphdr *udphdr, const uint8_t *data_payload, size_t len_payload) { if (params.debug) { - if (replay) DLOG("REPLAY "); + if (replay) + DLOG("REPLAY "); if (ip) { char s[66]; - str_ip(s,sizeof(s),ip); - DLOG("IP4: %s",s); + str_ip(s, sizeof(s), ip); + DLOG("IP4: %s", s); } else if (ip6hdr) { char s[128]; - str_ip6hdr(s,sizeof(s),ip6hdr, proto); - DLOG("IP6: %s",s); + str_ip6hdr(s, sizeof(s), ip6hdr, proto); + DLOG("IP6: %s", s); } if (tcphdr) { char s[80]; - str_tcphdr(s,sizeof(s),tcphdr); - DLOG(" %s\n",s); - if (len_payload) { DLOG("TCP: "); hexdump_limited_dlog(data_payload, len_payload, 32); DLOG("\n"); } - + str_tcphdr(s, sizeof(s), tcphdr); + DLOG(" %s\n", s); + if (len_payload) + { + DLOG("TCP: "); + hexdump_limited_dlog(data_payload, len_payload, 32); + DLOG("\n"); + } } else if (udphdr) { char s[30]; - str_udphdr(s,sizeof(s),udphdr); - DLOG(" %s\n",s); - if (len_payload) { DLOG("UDP: "); hexdump_limited_dlog(data_payload, len_payload, 32); DLOG("\n"); } + str_udphdr(s, sizeof(s), udphdr); + DLOG(" %s\n", s); + if (len_payload) + { + DLOG("UDP: "); + hexdump_limited_dlog(data_payload, len_payload, 32); + DLOG("\n"); + } } else DLOG("\n"); } } - static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) { struct ip *ip; @@ -1673,30 +1718,30 @@ static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t struct tcphdr *tcphdr; struct udphdr *udphdr; size_t transport_len; - uint8_t *data_payload,proto; + uint8_t *data_payload, proto; size_t len_payload; uint8_t verdict = VERDICT_PASS; - - proto_dissect_l3l4(data_pkt,*len_pkt,&ip,&ip6hdr,&proto,&tcphdr,&udphdr,&transport_len,&data_payload,&len_payload); + + proto_dissect_l3l4(data_pkt, *len_pkt, &ip, &ip6hdr, &proto, &tcphdr, &udphdr, &transport_len, &data_payload, &len_payload); if (!!ip != !!ip6hdr) { packet_debug(replay, proto, ip, ip6hdr, tcphdr, udphdr, data_payload, len_payload); - switch(proto) + switch (proto) { - case IPPROTO_TCP: - if (tcphdr) - { - verdict = dpi_desync_tcp_packet_play(replay, reasm_offset, fwmark, ifout, data_pkt, len_pkt, ip, ip6hdr, tcphdr, transport_len, data_payload, len_payload); - verdict_tcp_csum_fix(verdict, tcphdr, transport_len, ip, ip6hdr); - } - break; - case IPPROTO_UDP: - if (udphdr) - { - verdict = dpi_desync_udp_packet_play(replay, reasm_offset, fwmark, ifout, data_pkt, len_pkt, ip, ip6hdr, udphdr, transport_len, data_payload, len_payload); - verdict_udp_csum_fix(verdict, udphdr, transport_len, ip, ip6hdr); - } - break; + case IPPROTO_TCP: + if (tcphdr) + { + verdict = dpi_desync_tcp_packet_play(replay, reasm_offset, fwmark, ifout, data_pkt, len_pkt, ip, ip6hdr, tcphdr, transport_len, data_payload, len_payload); + verdict_tcp_csum_fix(verdict, tcphdr, transport_len, ip, ip6hdr); + } + break; + case IPPROTO_UDP: + if (udphdr) + { + verdict = dpi_desync_udp_packet_play(replay, reasm_offset, fwmark, ifout, data_pkt, len_pkt, ip, ip6hdr, udphdr, transport_len, data_payload, len_payload); + verdict_udp_csum_fix(verdict, udphdr, transport_len, ip, ip6hdr); + } + break; } } return verdict; @@ -1706,31 +1751,29 @@ uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifout, uint8_t *data_pkt, return dpi_desync_packet_play(false, 0, fwmark, ifout, data_pkt, len_pkt); } - - static bool replay_queue(struct rawpacket_tailhead *q) { struct rawpacket *rp; size_t offset; unsigned int i; bool b = true; - for (i=1,offset=0 ; (rp=rawpacket_dequeue(q)) ; offset+=rp->len_payload, rawpacket_free(rp), i++) + for (i = 1, offset = 0; (rp = rawpacket_dequeue(q)); offset += rp->len_payload, rawpacket_free(rp), i++) { - DLOG("REPLAYING delayed packet #%u offset %zu\n",i,offset); + DLOG("REPLAYING delayed packet #%u offset %zu\n", i, offset); uint8_t verdict = dpi_desync_packet_play(true, offset, rp->fwmark, rp->ifout, rp->packet, &rp->len); - switch(verdict & VERDICT_MASK) + switch (verdict & VERDICT_MASK) { - case VERDICT_MODIFY: - DLOG("SENDING delayed packet #%u modified\n", i); - b &= rawsend_rp(rp); - break; - case VERDICT_PASS: - DLOG("SENDING delayed packet #%u unmodified\n", i); - b &= rawsend_rp(rp); - break; - case VERDICT_DROP: - DLOG("DROPPING delayed packet #%u\n", i); - break; + case VERDICT_MODIFY: + DLOG("SENDING delayed packet #%u modified\n", i); + b &= rawsend_rp(rp); + break; + case VERDICT_PASS: + DLOG("SENDING delayed packet #%u unmodified\n", i); + b &= rawsend_rp(rp); + break; + case VERDICT_DROP: + DLOG("DROPPING delayed packet #%u\n", i); + break; } } return b; diff --git a/nfq/desync.h b/nfq/desync.h index 4aa42aa..2bc2d5f 100644 --- a/nfq/desync.h +++ b/nfq/desync.h @@ -19,8 +19,9 @@ #define DPI_DESYNC_MAX_FAKE_LEN 9216 -enum dpi_desync_mode { - DESYNC_NONE=0, +enum dpi_desync_mode +{ + DESYNC_NONE = 0, DESYNC_INVALID, DESYNC_FAKE, DESYNC_FAKE_KNOWN, diff --git a/nfq/gzip.c b/nfq/gzip.c index cb46670..1161b97 100644 --- a/nfq/gzip.c +++ b/nfq/gzip.c @@ -5,7 +5,7 @@ #define ZCHUNK 16384 #define BUFMIN 128 -#define BUFCHUNK (1024*128) +#define BUFCHUNK (1024 * 128) int z_readfile(FILE *F, char **buf, size_t *size) { @@ -21,7 +21,8 @@ int z_readfile(FILE *F, char **buf, size_t *size) bufsize = *size = 0; r = inflateInit2(&zs, 47); - if (r != Z_OK) return r; + if (r != Z_OK) + return r; do { @@ -31,7 +32,8 @@ int z_readfile(FILE *F, char **buf, size_t *size) r = Z_ERRNO; goto zerr; } - if (!zs.avail_in) break; + if (!zs.avail_in) + break; zs.next_in = in; do { @@ -47,9 +49,10 @@ int z_readfile(FILE *F, char **buf, size_t *size) *buf = newbuf; } zs.avail_out = bufsize - *size; - zs.next_out = (unsigned char*)(*buf + *size); + zs.next_out = (unsigned char *)(*buf + *size); r = inflate(&zs, Z_NO_FLUSH); - if (r != Z_OK && r != Z_STREAM_END) goto zerr; + if (r != Z_OK && r != Z_STREAM_END) + goto zerr; *size = bufsize - zs.avail_out; } while (r == Z_OK && zs.avail_in); } while (r == Z_OK); @@ -57,7 +60,8 @@ int z_readfile(FILE *F, char **buf, size_t *size) if (*size < bufsize) { // free extra space - if ((newbuf = realloc(*buf, *size))) *buf = newbuf; + if ((newbuf = realloc(*buf, *size))) + *buf = newbuf; } inflateEnd(&zs); @@ -73,7 +77,7 @@ zerr: return r; } -bool is_gzip(FILE* F) +bool is_gzip(FILE *F) { unsigned char magic[2]; bool b = !fseek(F, 0, SEEK_SET) && fread(magic, 1, 2, F) == 2 && magic[0] == 0x1F && magic[1] == 0x8B; diff --git a/nfq/gzip.h b/nfq/gzip.h index 15e30d2..ffc5c02 100644 --- a/nfq/gzip.h +++ b/nfq/gzip.h @@ -4,5 +4,5 @@ #include #include -int z_readfile(FILE *F,char **buf,size_t *size); -bool is_gzip(FILE* F); +int z_readfile(FILE *F, char **buf, size_t *size); +bool is_gzip(FILE *F); diff --git a/nfq/helpers.c b/nfq/helpers.c index 0ff9b4e..4c5404b 100644 --- a/nfq/helpers.c +++ b/nfq/helpers.c @@ -7,7 +7,6 @@ #include #include - #include "params.h" void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit) @@ -19,11 +18,15 @@ void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit) size = limit; bcut = true; } - if (!size) return; - for (k = 0; k < size; k++) DLOG("%02X ", data[k]); + if (!size) + return; + for (k = 0; k < size; k++) + DLOG("%02X ", data[k]); DLOG(bcut ? "... : " : ": "); - for (k = 0; k < size; k++) DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.'); - if (bcut) DLOG(" ..."); + for (k = 0; k < size; k++) + DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.'); + if (bcut) + DLOG(" ..."); } char *strncasestr(const char *s, const char *find, size_t slen) @@ -38,9 +41,11 @@ char *strncasestr(const char *s, const char *find, size_t slen) { do { - if (slen-- < 1 || (sc = *s++) == '\0') return NULL; + if (slen-- < 1 || (sc = *s++) == '\0') + return NULL; } while (toupper(c) != toupper(sc)); - if (len > slen) return NULL; + if (len > slen) + return NULL; } while (strncasecmp(s, find, len) != 0); s--; } @@ -52,7 +57,8 @@ bool load_file(const char *filename, void *buffer, size_t *buffer_size) FILE *F; F = fopen(filename, "rb"); - if (!F) return false; + if (!F) + return false; *buffer_size = fread(buffer, 1, *buffer_size, F); if (ferror(F)) @@ -74,7 +80,8 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size) FILE *F; F = fopen(filename, "wb"); - if (!F) return false; + if (!F) + return false; fwrite(buffer, 1, buffer_size, F); if (ferror(F)) @@ -88,25 +95,26 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size) } bool append_to_list_file(const char *filename, const char *s) { - FILE *F = fopen(filename,"at"); - if (!F) return false; - bool bOK = fprintf(F,"%s\n",s)>0; + FILE *F = fopen(filename, "at"); + if (!F) + return false; + bool bOK = fprintf(F, "%s\n", s) > 0; fclose(F); return bOK; } - void ntop46(const struct sockaddr *sa, char *str, size_t len) { - if (!len) return; + if (!len) + return; *str = 0; switch (sa->sa_family) { case AF_INET: - inet_ntop(sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr, str, len); + inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, str, len); break; case AF_INET6: - inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, str, len); + inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, str, len); break; default: snprintf(str, len, "UNKNOWN_FAMILY_%d", sa->sa_family); @@ -119,10 +127,10 @@ void ntop46_port(const struct sockaddr *sa, char *str, size_t len) switch (sa->sa_family) { case AF_INET: - snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in*)sa)->sin_port)); + snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in *)sa)->sin_port)); break; case AF_INET6: - snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6*)sa)->sin6_port)); + snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); break; default: snprintf(str, len, "%s", ip); @@ -138,49 +146,55 @@ void print_sockaddr(const struct sockaddr *sa) bool pton4_port(const char *s, struct sockaddr_in *sa) { - char ip[16],*p; + char ip[16], *p; size_t l; unsigned int u; - p = strchr(s,':'); - if (!p) return false; - l = p-s; - if (l<7 || l>15) return false; - memcpy(ip,s,l); - ip[l]=0; + p = strchr(s, ':'); + if (!p) + return false; + l = p - s; + if (l < 7 || l > 15) + return false; + memcpy(ip, s, l); + ip[l] = 0; p++; sa->sin_family = AF_INET; - if (inet_pton(AF_INET,ip,&sa->sin_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false; + if (inet_pton(AF_INET, ip, &sa->sin_addr) != 1 || sscanf(p, "%u", &u) != 1 || !u || u > 0xFFFF) + return false; sa->sin_port = htons((uint16_t)u); - + return true; } bool pton6_port(const char *s, struct sockaddr_in6 *sa) { - char ip[40],*p; + char ip[40], *p; size_t l; unsigned int u; - if (*s++!='[') return false; - p = strchr(s,']'); - if (!p || p[1]!=':') return false; - l = p-s; - if (l<2 || l>39) return false; - p+=2; - memcpy(ip,s,l); - ip[l]=0; + if (*s++ != '[') + return false; + p = strchr(s, ']'); + if (!p || p[1] != ':') + return false; + l = p - s; + if (l < 2 || l > 39) + return false; + p += 2; + memcpy(ip, s, l); + ip[l] = 0; sa->sin6_family = AF_INET6; - if (inet_pton(AF_INET6,ip,&sa->sin6_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false; + if (inet_pton(AF_INET6, ip, &sa->sin6_addr) != 1 || sscanf(p, "%u", &u) != 1 || !u || u > 0xFFFF) + return false; sa->sin6_port = htons((uint16_t)u); sa->sin6_flowinfo = 0; sa->sin6_scope_id = 0; - + return true; } - void dbgprint_socket_buffers(int fd) { if (params.debug) @@ -190,7 +204,7 @@ void dbgprint_socket_buffers(int fd) sz = sizeof(int); if (!getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &v, &sz)) DLOG("fd=%d SO_RCVBUF=%d\n", fd, v); - sz = sizeof(int); + sz = sizeof(int); if (!getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &v, &sz)) DLOG("fd=%d SO_SNDBUF=%d\n", fd, v); } @@ -216,14 +230,14 @@ bool set_socket_buffers(int fd, int rcvbuf, int sndbuf) uint64_t pntoh64(const void *p) { - return (uint64_t)*((const uint8_t *)(p)+0) << 56 | - (uint64_t)*((const uint8_t *)(p)+1) << 48 | - (uint64_t)*((const uint8_t *)(p)+2) << 40 | - (uint64_t)*((const uint8_t *)(p)+3) << 32 | - (uint64_t)*((const uint8_t *)(p)+4) << 24 | - (uint64_t)*((const uint8_t *)(p)+5) << 16 | - (uint64_t)*((const uint8_t *)(p)+6) << 8 | - (uint64_t)*((const uint8_t *)(p)+7) << 0; + return (uint64_t) * ((const uint8_t *)(p) + 0) << 56 | + (uint64_t) * ((const uint8_t *)(p) + 1) << 48 | + (uint64_t) * ((const uint8_t *)(p) + 2) << 40 | + (uint64_t) * ((const uint8_t *)(p) + 3) << 32 | + (uint64_t) * ((const uint8_t *)(p) + 4) << 24 | + (uint64_t) * ((const uint8_t *)(p) + 5) << 16 | + (uint64_t) * ((const uint8_t *)(p) + 6) << 8 | + (uint64_t) * ((const uint8_t *)(p) + 7) << 0; } void phton64(uint8_t *p, uint64_t v) { @@ -239,57 +253,60 @@ void phton64(uint8_t *p, uint64_t v) bool seq_within(uint32_t s, uint32_t s1, uint32_t s2) { - return (s2>=s1 && s>=s1 && s<=s2) || (s2=s1)); + return (s2 >= s1 && s >= s1 && s <= s2) || (s2 < s1 && (s <= s2 || s >= s1)); } bool ipv6_addr_is_zero(const struct in6_addr *a) { - return !memcmp(a,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",16); + return !memcmp(a, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); } - -#define INVALID_HEX_DIGIT ((uint8_t)-1) +#define INVALID_HEX_DIGIT ((uint8_t) - 1) static inline uint8_t parse_hex_digit(char c) { - return (c>='0' && c<='9') ? c-'0' : (c>='a' && c<='f') ? c-'a'+0xA : (c>='A' && c<='F') ? c-'A'+0xA : INVALID_HEX_DIGIT; + return (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 0xA + : (c >= 'A' && c <= 'F') ? c - 'A' + 0xA + : INVALID_HEX_DIGIT; } static inline bool parse_hex_byte(const char *s, uint8_t *pbyte) { - uint8_t u,l; + uint8_t u, l; u = parse_hex_digit(s[0]); l = parse_hex_digit(s[1]); - if (u==INVALID_HEX_DIGIT || l==INVALID_HEX_DIGIT) + if (u == INVALID_HEX_DIGIT || l == INVALID_HEX_DIGIT) { - *pbyte=0; + *pbyte = 0; return false; } else { - *pbyte=(u<<4) | l; + *pbyte = (u << 4) | l; return true; } } bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size) { - uint8_t *pe = pbuf+*size; - *size=0; - while(pbufpatsize ? patsize : bufsize; - memcpy(buf,pattern,size); + size = bufsize > patsize ? patsize : bufsize; + memcpy(buf, pattern, size); buf += size; bufsize -= size; } @@ -301,66 +318,72 @@ int fprint_localtime(FILE *F) time_t now; time(&now); - localtime_r(&now,&t); + localtime_r(&now, &t); return fprintf(F, "%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec); } time_t file_mod_time(const char *filename) { struct stat st; - return stat(filename,&st)==-1 ? 0 : st.st_mtime; + return stat(filename, &st) == -1 ? 0 : st.st_mtime; } bool pf_in_range(uint16_t port, const port_filter *pf) { - return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg); + return port && (((!pf->from && !pf->to) || (port >= pf->from && port <= pf->to)) ^ pf->neg); } bool pf_parse(const char *s, port_filter *pf) { - unsigned int v1,v2; + unsigned int v1, v2; - if (!s) return false; - if (*s=='~') + if (!s) + return false; + if (*s == '~') { - pf->neg=true; + pf->neg = true; s++; } else - pf->neg=false; - if (sscanf(s,"%u-%u",&v1,&v2)==2) + pf->neg = false; + if (sscanf(s, "%u-%u", &v1, &v2) == 2) { - if (!v1 || v1>65535 || v2>65535 || v1>v2) return false; - pf->from=(uint16_t)v1; - pf->to=(uint16_t)v2; + if (!v1 || v1 > 65535 || v2 > 65535 || v1 > v2) + return false; + pf->from = (uint16_t)v1; + pf->to = (uint16_t)v2; } - else if (sscanf(s,"%u",&v1)==1) + else if (sscanf(s, "%u", &v1) == 1) { - if (!v1 || v1>65535) return false; - pf->to=pf->from=(uint16_t)v1; + if (!v1 || v1 > 65535) + return false; + pf->to = pf->from = (uint16_t)v1; } else return false; return true; } -void fill_random_bytes(uint8_t *p,size_t sz) +void fill_random_bytes(uint8_t *p, size_t sz) { - size_t k,sz16 = sz>>1; - for(k=0;k> 1; + for (k = 0; k < sz16; k++) + ((uint16_t *)p)[k] = (uint16_t)random(); + if (sz & 1) + p[sz - 1] = (uint8_t)random(); } -void fill_random_az(uint8_t *p,size_t sz) +void fill_random_az(uint8_t *p, size_t sz) { size_t k; - for(k=0;k void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit); -char *strncasestr(const char *s,const char *find, size_t slen); -bool load_file(const char *filename,void *buffer,size_t *buffer_size); -bool load_file_nonempty(const char *filename,void *buffer,size_t *buffer_size); +char *strncasestr(const char *s, const char *find, size_t slen); +bool load_file(const char *filename, void *buffer, size_t *buffer_size); +bool load_file_nonempty(const char *filename, void *buffer, size_t *buffer_size); bool save_file(const char *filename, const void *buffer, size_t buffer_size); bool append_to_list_file(const char *filename, const char *s); @@ -32,19 +32,22 @@ void phton64(uint8_t *p, uint64_t v); bool ipv6_addr_is_zero(const struct in6_addr *a); -static inline uint16_t pntoh16(const uint8_t *p) { +static inline uint16_t pntoh16(const uint8_t *p) +{ return ((uint16_t)p[0] << 8) | (uint16_t)p[1]; } -static inline void phton16(uint8_t *p, uint16_t v) { +static inline void phton16(uint8_t *p, uint16_t v) +{ p[0] = (uint8_t)(v >> 8); p[1] = v & 0xFF; } -static inline uint32_t pntoh32(const uint8_t *p) { +static inline uint32_t pntoh32(const uint8_t *p) +{ return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3]; } bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size); -void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize); +void fill_pattern(uint8_t *buf, size_t bufsize, const void *pattern, size_t patsize); int fprint_localtime(FILE *F); @@ -52,12 +55,12 @@ time_t file_mod_time(const char *filename); typedef struct { - uint16_t from,to; + uint16_t from, to; bool neg; } port_filter; bool pf_in_range(uint16_t port, const port_filter *pf); bool pf_parse(const char *s, port_filter *pf); -void fill_random_bytes(uint8_t *p,size_t sz); -void fill_random_az(uint8_t *p,size_t sz); -void fill_random_az09(uint8_t *p,size_t sz); \ No newline at end of file +void fill_random_bytes(uint8_t *p, size_t sz); +void fill_random_az(uint8_t *p, size_t sz); +void fill_random_az09(uint8_t *p, size_t sz); \ No newline at end of file diff --git a/nfq/hostlist.c b/nfq/hostlist.c index d1a03b2..5a97e31 100644 --- a/nfq/hostlist.c +++ b/nfq/hostlist.c @@ -8,17 +8,19 @@ static bool addpool(strpool **hostlist, char **s, const char *end) { char *p; - + // advance until eol lowering all chars - for (p = *s; pstr)) return false; + if (!AppendHostList(hostlist, file->str)) + return false; } return true; } @@ -114,7 +119,6 @@ bool NonEmptyHostlist(strpool **hostlist) return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4); } - bool SearchHostList(strpool *hostlist, const char *host) { if (hostlist) @@ -125,9 +129,11 @@ bool SearchHostList(strpool *hostlist, const char *host) { bInHostList = StrPoolCheckStr(hostlist, p); DLOG("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative"); - if (bInHostList) return true; + if (bInHostList) + return true; p = strchr(p, '.'); - if (p) p++; + if (p) + p++; } } return false; @@ -136,13 +142,15 @@ bool SearchHostList(strpool *hostlist, const char *host) // return : true = apply fooling, false = do not apply static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded) { - if (excluded) *excluded = false; + if (excluded) + *excluded = false; if (hostlist_exclude) { DLOG("Checking exclude hostlist\n"); if (SearchHostList(hostlist_exclude, host)) { - if (excluded) *excluded = true; + if (excluded) + *excluded = true; return false; } } @@ -160,7 +168,7 @@ bool HostlistCheck(const char *host, bool *excluded) if (*params.hostlist_auto_filename) { time_t t = file_mod_time(params.hostlist_auto_filename); - if (t!=params.hostlist_auto_mod_time) + if (t != params.hostlist_auto_mod_time) { DLOG_CONDUP("Autohostlist was modified by another process. Reloading include hostslist.\n"); if (!LoadIncludeHostLists()) diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 3d1beef..732e65e 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -40,14 +40,14 @@ #define NF_ACCEPT 1 #endif -#define CTRACK_T_SYN 60 -#define CTRACK_T_FIN 60 -#define CTRACK_T_EST 300 -#define CTRACK_T_UDP 60 +#define CTRACK_T_SYN 60 +#define CTRACK_T_FIN 60 +#define CTRACK_T_EST 300 +#define CTRACK_T_UDP 60 struct params_s params; #ifdef __CYGWIN__ -bool bQuit=false; +bool bQuit = false; #endif static bool bHup = false; @@ -94,7 +94,6 @@ static void pre_desync(void) desync_init(); } - static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) { #ifdef __linux__ @@ -107,7 +106,6 @@ static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *dat return dpi_desync_packet(*mark, ifout, data_pkt, len_pkt); } - #ifdef __linux__ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *cookie) { @@ -116,7 +114,7 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da struct nfqnl_msg_packet_hdr *ph; uint8_t *data; uint32_t ifidx; - char ifout[IFNAMSIZ+1]; + char ifout[IFNAMSIZ + 1]; ph = nfq_get_msg_packet_hdr(nfa); id = ph ? ntohl(ph->packet_id) : 0; @@ -124,17 +122,19 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da uint32_t mark = nfq_get_nfmark(nfa); ilen = nfq_get_payload(nfa, &data); - *ifout=0; + *ifout = 0; if (params.bind_fix4 || params.bind_fix6) { - char ifin[IFNAMSIZ+1]; + char ifin[IFNAMSIZ + 1]; uint32_t ifidx_in; ifidx = nfq_get_outdev(nfa); - if (ifidx) if_indextoname(ifidx,ifout); - *ifin=0; + if (ifidx) + if_indextoname(ifidx, ifout); + *ifin = 0; ifidx_in = nfq_get_indev(nfa); - if (ifidx_in) if_indextoname(ifidx_in,ifin); + if (ifidx_in) + if_indextoname(ifidx_in, ifin); DLOG("packet: id=%d len=%d mark=%08X ifin=%s(%u) ifout=%s(%u)\n", id, ilen, mark, ifin, ifidx_in, ifout, ifidx); } @@ -145,7 +145,7 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da { len = ilen; uint8_t verdict = processPacketData(&mark, ifout, data, &len); - switch(verdict & VERDICT_MASK) + switch (verdict & VERDICT_MASK) { case VERDICT_MODIFY: DLOG("packet: id=%d pass modified. len=%zu\n", id, len); @@ -162,53 +162,59 @@ static int nfq_main(void) { struct nfq_handle *h = NULL; struct nfq_q_handle *qh = NULL; - int fd,rv; + int fd, rv; uint8_t buf[16384] __attribute__((aligned)); DLOG_CONDUP("opening library handle\n"); h = nfq_open(); - if (!h) { + if (!h) + { DLOG_PERROR("nfq_open()"); goto exiterr; } DLOG_CONDUP("unbinding existing nf_queue handler for AF_INET (if any)\n"); - if (nfq_unbind_pf(h, AF_INET) < 0) { + if (nfq_unbind_pf(h, AF_INET) < 0) + { DLOG_PERROR("nfq_unbind_pf()"); goto exiterr; } DLOG_CONDUP("binding nfnetlink_queue as nf_queue handler for AF_INET\n"); - if (nfq_bind_pf(h, AF_INET) < 0) { + if (nfq_bind_pf(h, AF_INET) < 0) + { DLOG_PERROR("nfq_bind_pf()"); goto exiterr; } DLOG_CONDUP("binding this socket to queue '%u'\n", params.qnum); qh = nfq_create_queue(h, params.qnum, &nfq_cb, ¶ms); - if (!qh) { + if (!qh) + { DLOG_PERROR("nfq_create_queue()"); goto exiterr; } DLOG_CONDUP("setting copy_packet mode\n"); - if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { + if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) + { DLOG_PERROR("can't set packet_copy mode"); goto exiterr; } - if (nfq_set_queue_maxlen(qh, Q_MAXLEN) < 0) { + if (nfq_set_queue_maxlen(qh, Q_MAXLEN) < 0) + { DLOG_PERROR("can't set queue maxlen"); goto exiterr; } // accept packets if they cant be handled - if (nfq_set_queue_flags(qh, NFQA_CFG_F_FAIL_OPEN , NFQA_CFG_F_FAIL_OPEN)) + if (nfq_set_queue_flags(qh, NFQA_CFG_F_FAIL_OPEN, NFQA_CFG_F_FAIL_OPEN)) { - DLOG_ERR("can't set queue flags. its OK on linux <3.6\n"); - // dot not fail. not supported on old linuxes <3.6 + DLOG_ERR("can't set queue flags. its OK on Linux <3.6\n"); + // dot not fail. not supported on old linuxes <3.6 } - DLOG_CONDUP("initializing raw sockets bind-fix4=%u bind-fix6=%u\n",params.bind_fix4,params.bind_fix6); - if (!rawsend_preinit(params.bind_fix4,params.bind_fix6)) + DLOG_CONDUP("initializing raw sockets bind-fix4=%u bind-fix6=%u\n", params.bind_fix4, params.bind_fix6); + if (!rawsend_preinit(params.bind_fix4, params.bind_fix6)) goto exiterr; #ifndef __CYGWIN__ @@ -226,7 +232,7 @@ static int nfq_main(void) // increase socket buffer size. on slow systems reloading hostlist can take a while. // if too many unhandled packets are received its possible to get "no buffer space available" error - if (!set_socket_buffers(fd,Q_RCVBUF/2,Q_SNDBUF/2)) + if (!set_socket_buffers(fd, Q_RCVBUF / 2, Q_SNDBUF / 2)) goto exiterr; do { @@ -234,12 +240,13 @@ static int nfq_main(void) { dohup(); int r = nfq_handle_packet(h, (char *)buf, rv); - if (r) DLOG_ERR("nfq_handle_packet error %d\n", r); + if (r) + DLOG_ERR("nfq_handle_packet error %d\n", r); } - DLOG_ERR("recv: errno %d\n",errno); + DLOG_ERR("recv: errno %d\n", errno); DLOG_PERROR("recv"); // do not fail on ENOBUFS - } while(errno==ENOBUFS); + } while (errno == ENOBUFS); DLOG_CONDUP("unbinding from queue %u\n", params.qnum); nfq_destroy_queue(qh); @@ -256,8 +263,10 @@ static int nfq_main(void) return 0; exiterr: - if (qh) nfq_destroy_queue(qh); - if (h) nfq_close(h); + if (qh) + nfq_destroy_queue(qh); + if (h) + nfq_close(h); return 1; } @@ -267,11 +276,11 @@ static int dvt_main(void) { uint8_t buf[16384] __attribute__((aligned)); struct sockaddr_storage sa_from; - int fd[2] = {-1,-1}; // 4,6 - int i,r,res=1,fdct=1,fdmax; - unsigned int id=0; + int fd[2] = {-1, -1}; // 4,6 + int i, r, res = 1, fdct = 1, fdmax; + unsigned int id = 0; socklen_t socklen; - ssize_t rd,wr; + ssize_t rd, wr; fd_set fdset; { @@ -279,53 +288,54 @@ static int dvt_main(void) bp4.sin_family = AF_INET; bp4.sin_port = htons(params.port); bp4.sin_addr.s_addr = INADDR_ANY; - + DLOG_CONDUP("creating divert4 socket\n"); fd[0] = socket_divert(AF_INET); - if (fd[0] == -1) { + if (fd[0] == -1) + { DLOG_PERROR("socket (DIVERT4)"); goto exiterr; } DLOG_CONDUP("binding divert4 socket\n"); - if (bind(fd[0], (struct sockaddr*)&bp4, sizeof(bp4)) < 0) + if (bind(fd[0], (struct sockaddr *)&bp4, sizeof(bp4)) < 0) { DLOG_PERROR("bind (DIVERT4)"); goto exiterr; } - if (!set_socket_buffers(fd[0],Q_RCVBUF,Q_SNDBUF)) + if (!set_socket_buffers(fd[0], Q_RCVBUF, Q_SNDBUF)) goto exiterr; } - #ifdef __OpenBSD__ { // in OpenBSD must use separate divert sockets for ipv4 and ipv6 struct sockaddr_in6 bp6; - memset(&bp6,0,sizeof(bp6)); + memset(&bp6, 0, sizeof(bp6)); bp6.sin6_family = AF_INET6; bp6.sin6_port = htons(params.port); - + DLOG_CONDUP("creating divert6 socket\n"); fd[1] = socket_divert(AF_INET6); - if (fd[1] == -1) { + if (fd[1] == -1) + { DLOG_PERROR("socket (DIVERT6)"); goto exiterr; } DLOG_CONDUP("binding divert6 socket\n"); - if (bind(fd[1], (struct sockaddr*)&bp6, sizeof(bp6)) < 0) + if (bind(fd[1], (struct sockaddr *)&bp6, sizeof(bp6)) < 0) { DLOG_PERROR("bind (DIVERT6)"); goto exiterr; } fdct++; - if (!set_socket_buffers(fd[1],Q_RCVBUF,Q_SNDBUF)) + if (!set_socket_buffers(fd[1], Q_RCVBUF, Q_SNDBUF)) goto exiterr; } #endif - fdmax = (fd[0]>fd[1] ? fd[0] : fd[1]) + 1; + fdmax = (fd[0] > fd[1] ? fd[0] : fd[1]) + 1; DLOG_CONDUP("initializing raw sockets\n"); - if (!rawsend_preinit(false,false)) + if (!rawsend_preinit(false, false)) goto exiterr; if (params.droproot && !droproot(params.uid, params.gid)) @@ -334,14 +344,15 @@ static int dvt_main(void) pre_desync(); - for(;;) + for (;;) { FD_ZERO(&fdset); - for(i=0;i0) + else if (rd > 0) { - uint32_t mark=0; + uint32_t mark = 0; uint8_t verdict; size_t len = rd; @@ -373,14 +384,14 @@ static int dvt_main(void) { case VERDICT_PASS: case VERDICT_MODIFY: - if ((verdict & VERDICT_MASK)==VERDICT_PASS) + if ((verdict & VERDICT_MASK) == VERDICT_PASS) DLOG("packet: id=%u reinject unmodified\n", id); else DLOG("packet: id=%u reinject modified len=%zu\n", id, len); - wr = sendto(fd[i], buf, len, 0, (struct sockaddr*)&sa_from, socklen); - if (wr<0) + wr = sendto(fd[i], buf, len, 0, (struct sockaddr *)&sa_from, socklen); + if (wr < 0) DLOG_PERROR("reinject sendto"); - else if (wr!=len) + else if (wr != len) DLOG_ERR("reinject sendto: not all data was reinjected. received %zu, sent %zd\n", len, wr); break; default: @@ -396,15 +407,16 @@ static int dvt_main(void) } } - res=0; + res = 0; exiterr: - if (fd[0]!=-1) close(fd[0]); - if (fd[1]!=-1) close(fd[1]); + if (fd[0] != -1) + close(fd[0]); + if (fd[1] != -1) + close(fd[1]); return res; } - -#elif defined (__CYGWIN__) +#elif defined(__CYGWIN__) static int win_main(const char *windivert_filter) { @@ -425,7 +437,7 @@ static int win_main(const char *windivert_filter) return w_win32_error; } - for(;;) + for (;;) { if (!logical_net_filter_match()) { @@ -440,8 +452,7 @@ static int win_main(const char *windivert_filter) return 0; } usleep(500000); - } - while (!logical_net_filter_match()); + } while (!logical_net_filter_match()); DLOG_CONDUP("logical network now present\n"); fflush(stdout); } @@ -458,23 +469,23 @@ static int win_main(const char *windivert_filter) fflush(stdout); fflush(stderr); - for (id=0;;id++) + for (id = 0;; id++) { len = sizeof(packet); if (!windivert_recv(packet, &len, &wa)) { - if (errno==ENOBUFS) + if (errno == ENOBUFS) { DLOG("windivert: ignoring too large packet\n"); continue; // too large packet } - else if (errno==ENODEV) + else if (errno == ENODEV) { DLOG_CONDUP("logical network disappeared. deinitializing windivert.\n"); rawsend_cleanup(); break; } - else if (errno==EINTR) + else if (errno == EINTR) { DLOG("QUIT requested\n"); win_dark_deinit(); @@ -484,8 +495,9 @@ static int win_main(const char *windivert_filter) win_dark_deinit(); return w_win32_error; } - *ifout=0; - if (wa.Outbound) snprintf(ifout,sizeof(ifout),"%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx); + *ifout = 0; + if (wa.Outbound) + snprintf(ifout, sizeof(ifout), "%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx); DLOG("packet: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx); if (wa.Impostor) { @@ -499,25 +511,25 @@ static int win_main(const char *windivert_filter) } else { - mark=0; + mark = 0; // pseudo interface id IfIdx.SubIfIdx verdict = processPacketData(&mark, ifout, packet, &len); } switch (verdict & VERDICT_MASK) { - case VERDICT_PASS: - case VERDICT_MODIFY: - if ((verdict & VERDICT_MASK)==VERDICT_PASS) - DLOG("packet: id=%u reinject unmodified\n", id); - else - DLOG("packet: id=%u reinject modified len=%zu\n", id, len); - if (!windivert_send(packet, len, &wa)) - DLOG_ERR("windivert: reinject of packet id=%u failed\n", id); - break; - default: - DLOG("packet: id=%u drop\n", id); + case VERDICT_PASS: + case VERDICT_MODIFY: + if ((verdict & VERDICT_MASK) == VERDICT_PASS) + DLOG("packet: id=%u reinject unmodified\n", id); + else + DLOG("packet: id=%u reinject modified len=%zu\n", id, len); + if (!windivert_send(packet, len, &wa)) + DLOG_ERR("windivert: reinject of packet id=%u failed\n", id); + break; + default: + DLOG("packet: id=%u drop\n", id); } - + // cygwin auto flush fails when piping fflush(stdout); fflush(stderr); @@ -529,25 +541,24 @@ static int win_main(const char *windivert_filter) #endif // multiple OS divert handlers - - static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale) { int v; char *p; - if ((p = strchr(s,':'))) *p++=0; + if ((p = strchr(s, ':'))) + *p++ = 0; v = atoi(s); - if (v < 0 || v>65535) + if (v < 0 || v > 65535) { DLOG_ERR("bad wsize\n"); return false; } - *wsize=(uint16_t)v; + *wsize = (uint16_t)v; if (p && *p) { v = atoi(p); - if (v < 0 || v>255) + if (v < 0 || v > 255) { DLOG_ERR("bad wscale\n"); return false; @@ -557,8 +568,6 @@ static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale) return true; } - - static void cleanup_params(void) { ConntrackPoolDestroy(¶ms.conntrack); @@ -581,64 +590,68 @@ static void exit_clean(int code) static bool parse_cutoff(const char *opt, unsigned int *value, char *mode) { - *mode = (*opt=='n' || *opt=='d' || *opt=='s') ? *opt++ : 'n'; - return sscanf(opt, "%u", value)>0; + *mode = (*opt == 'n' || *opt == 'd' || *opt == 's') ? *opt++ : 'n'; + return sscanf(opt, "%u", value) > 0; } static bool parse_badseq_increment(const char *opt, uint32_t *value) { - if (((opt[0]=='0' && opt[1]=='x') || (opt[0]=='-' && opt[1]=='0' && opt[2]=='x')) && sscanf(opt+2+(opt[0]=='-'), "%X", (int32_t*)value)>0) + if (((opt[0] == '0' && opt[1] == 'x') || (opt[0] == '-' && opt[1] == '0' && opt[2] == 'x')) && sscanf(opt + 2 + (opt[0] == '-'), "%X", (int32_t *)value) > 0) { - if (opt[0]=='-') params.desync_badseq_increment = -params.desync_badseq_increment; + if (opt[0] == '-') + params.desync_badseq_increment = -params.desync_badseq_increment; return true; } else { - return sscanf(opt, "%d", (int32_t*)value)>0; + return sscanf(opt, "%d", (int32_t *)value) > 0; } } static void load_file_or_exit(const char *filename, void *buf, size_t *size) { - if (filename[0]=='0' && filename[1]=='x') + if (filename[0] == '0' && filename[1] == 'x') { - if (!parse_hex_str(filename+2,buf,size) || !*size) + if (!parse_hex_str(filename + 2, buf, size) || !*size) { - DLOG_ERR("invalid hex string: %s\n",filename+2); + DLOG_ERR("invalid hex string: %s\n", filename + 2); exit_clean(1); } - DLOG("read %zu bytes from hex string\n",*size); + DLOG("read %zu bytes from hex string\n", *size); } else { - if (!load_file_nonempty(filename,buf,size)) + if (!load_file_nonempty(filename, buf, size)) { - DLOG_ERR("could not read %s\n",filename); + DLOG_ERR("could not read %s\n", filename); exit_clean(1); } - DLOG("read %zu bytes from %s\n",*size,filename); + DLOG("read %zu bytes from %s\n", *size, filename); } } bool parse_autottl(const char *s, autottl *t) { - unsigned int delta,min,max; + unsigned int delta, min, max; AUTOTTL_SET_DEFAULT(*t); if (s) { max = t->max; - switch (sscanf(s,"%u:%u-%u",&delta,&min,&max)) + switch (sscanf(s, "%u:%u-%u", &delta, &min, &max)) { - case 3: - if ((delta && !max) || max>255) return false; - t->max=(uint8_t)max; - case 2: - if ((delta && !min) || min>255 || min>max) return false; - t->min=(uint8_t)min; - case 1: - if (delta>255) return false; - t->delta=(uint8_t)delta; - break; - default: + case 3: + if ((delta && !max) || max > 255) return false; + t->max = (uint8_t)max; + case 2: + if ((delta && !min) || min > 255 || min > max) + return false; + t->min = (uint8_t)min; + case 1: + if (delta > 255) + return false; + t->delta = (uint8_t)delta; + break; + default: + return false; } } return true; @@ -647,89 +660,93 @@ bool parse_autottl(const char *s, autottl *t) #ifdef __CYGWIN__ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *buf, size_t len) { - char *e,*p,c,s1[64]; + char *e, *p, c, s1[64]; port_filter pf; int n; - if (len<3) return false; + if (len < 3) + return false; - for (n=0,p=opt,*buf='(',buf[1]=0 ; p ; n++) + for (n = 0, p = opt, *buf = '(', buf[1] = 0; p; n++) { - if ((e = strchr(p,','))) + if ((e = strchr(p, ','))) { - c=*e; - *e=0; + c = *e; + *e = 0; } - if (!pf_parse(p,&pf)) return false; + if (!pf_parse(p, &pf)) + return false; - if (pf.from==pf.to) + if (pf.from == pf.to) snprintf(s1, sizeof(s1), "(%s.%s %s %u)", l4, portname, pf.neg ? "!=" : "==", pf.from); else - snprintf(s1, sizeof(s1), "(%s.%s %s %u %s %s.%s %s %u)", l4, portname, pf.neg ? "<" : ">=", pf.from, pf.neg ? "or" : "and" , l4, portname, pf.neg ? ">" : "<=", pf.to); - if (n) strncat(buf," or ",len-strlen(buf)-1); - strncat(buf, s1, len-strlen(buf)-1); + snprintf(s1, sizeof(s1), "(%s.%s %s %u %s %s.%s %s %u)", l4, portname, pf.neg ? "<" : ">=", pf.from, pf.neg ? "or" : "and", l4, portname, pf.neg ? ">" : "<=", pf.to); + if (n) + strncat(buf, " or ", len - strlen(buf) - 1); + strncat(buf, s1, len - strlen(buf) - 1); if (e) { - *e++=c; + *e++ = c; } p = e; } - strncat(buf, ")", len-strlen(buf)-1); + strncat(buf, ")", len - strlen(buf) - 1); return true; } static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6) { - char *e,*p,c; + char *e, *p, c; - for (p=opt,*ipv4=*ipv6=false ; p ; ) + for (p = opt, *ipv4 = *ipv6 = false; p;) { - if ((e = strchr(p,','))) + if ((e = strchr(p, ','))) { - c=*e; - *e=0; + c = *e; + *e = 0; } - if (!strcmp(p,"ipv4")) + if (!strcmp(p, "ipv4")) *ipv4 = true; - else if (!strcmp(p,"ipv6")) + else if (!strcmp(p, "ipv6")) *ipv6 = true; - else return false; + else + return false; if (e) { - *e++=c; + *e++ = c; } p = e; } return true; } -#define DIVERT_NO_LOCALNETSv4_DST "(" \ - "(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \ - "(ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and " \ - "(ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and " \ - "(ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and " \ - "(ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255))" -#define DIVERT_NO_LOCALNETSv4_SRC "(" \ - "(ip.SrcAddr < 127.0.0.1 or ip.SrcAddr > 127.255.255.255) and " \ - "(ip.SrcAddr < 10.0.0.0 or ip.SrcAddr > 10.255.255.255) and " \ - "(ip.SrcAddr < 192.168.0.0 or ip.SrcAddr > 192.168.255.255) and " \ - "(ip.SrcAddr < 172.16.0.0 or ip.SrcAddr > 172.31.255.255) and " \ - "(ip.SrcAddr < 169.254.0.0 or ip.SrcAddr > 169.254.255.255))" +#define DIVERT_NO_LOCALNETSv4_DST "(" \ + "(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \ + "(ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and " \ + "(ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and " \ + "(ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and " \ + "(ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255))" +#define DIVERT_NO_LOCALNETSv4_SRC "(" \ + "(ip.SrcAddr < 127.0.0.1 or ip.SrcAddr > 127.255.255.255) and " \ + "(ip.SrcAddr < 10.0.0.0 or ip.SrcAddr > 10.255.255.255) and " \ + "(ip.SrcAddr < 192.168.0.0 or ip.SrcAddr > 192.168.255.255) and " \ + "(ip.SrcAddr < 172.16.0.0 or ip.SrcAddr > 172.31.255.255) and " \ + "(ip.SrcAddr < 169.254.0.0 or ip.SrcAddr > 169.254.255.255))" -#define DIVERT_NO_LOCALNETSv6_DST "(" \ - "(ipv6.DstAddr > ::1) and " \ - "(ipv6.DstAddr < 2001::0 or ipv6.DstAddr >= 2001:1::0) and " \ - "(ipv6.DstAddr < fc00::0 or ipv6.DstAddr >= fe00::0) and " \ - "(ipv6.DstAddr < fe80::0 or ipv6.DstAddr >= fec0::0) and " \ - "(ipv6.DstAddr < ff00::0 or ipv6.DstAddr >= ffff::0))" -#define DIVERT_NO_LOCALNETSv6_SRC "(" \ - "(ipv6.SrcAddr > ::1) and " \ - "(ipv6.SrcAddr < 2001::0 or ipv6.SrcAddr >= 2001:1::0) and " \ - "(ipv6.SrcAddr < fc00::0 or ipv6.SrcAddr >= fe00::0) and " \ - "(ipv6.SrcAddr < fe80::0 or ipv6.SrcAddr >= fec0::0) and " \ - "(ipv6.SrcAddr < ff00::0 or ipv6.SrcAddr >= ffff::0))" +#define DIVERT_NO_LOCALNETSv6_DST "(" \ + "(ipv6.DstAddr > ::1) and " \ + "(ipv6.DstAddr < 2001::0 or ipv6.DstAddr >= 2001:1::0) and " \ + "(ipv6.DstAddr < fc00::0 or ipv6.DstAddr >= fe00::0) and " \ + "(ipv6.DstAddr < fe80::0 or ipv6.DstAddr >= fec0::0) and " \ + "(ipv6.DstAddr < ff00::0 or ipv6.DstAddr >= ffff::0))" +#define DIVERT_NO_LOCALNETSv6_SRC "(" \ + "(ipv6.SrcAddr > ::1) and " \ + "(ipv6.SrcAddr < 2001::0 or ipv6.SrcAddr >= 2001:1::0) and " \ + "(ipv6.SrcAddr < fc00::0 or ipv6.SrcAddr >= fe00::0) and " \ + "(ipv6.SrcAddr < fe80::0 or ipv6.SrcAddr >= fec0::0) and " \ + "(ipv6.SrcAddr < ff00::0 or ipv6.SrcAddr >= ffff::0))" #define DIVERT_NO_LOCALNETS_SRC "(" DIVERT_NO_LOCALNETSv4_SRC " or " DIVERT_NO_LOCALNETSv6_SRC ")" #define DIVERT_NO_LOCALNETS_DST "(" DIVERT_NO_LOCALNETSv4_DST " or " DIVERT_NO_LOCALNETSv6_DST ")" @@ -743,53 +760,52 @@ static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6) static bool wf_make_filter( char *wf, size_t len, - unsigned int IfIdx,unsigned int SubIfIdx, + unsigned int IfIdx, unsigned int SubIfIdx, bool ipv4, bool ipv6, const char *pf_tcp_src, const char *pf_tcp_dst, const char *pf_udp_src, const char *pf_udp_dst) { - char pf_dst_buf[512],iface[64]; + char pf_dst_buf[512], iface[64]; const char *pf_dst; const char *f_tcpin = *pf_tcp_src ? *params.hostlist_auto_filename ? "(" DIVERT_TCP_INBOUNDS " or (" DIVERT_HTTP_REDIRECT "))" : DIVERT_TCP_INBOUNDS : ""; - snprintf(iface,sizeof(iface)," ifIdx=%u and subIfIdx=%u and",IfIdx,SubIfIdx); + snprintf(iface, sizeof(iface), " ifIdx=%u and subIfIdx=%u and", IfIdx, SubIfIdx); - if (!*pf_tcp_src && !*pf_udp_src) return false; + if (!*pf_tcp_src && !*pf_udp_src) + return false; if (*pf_tcp_src && *pf_udp_src) { - snprintf(pf_dst_buf,sizeof(pf_dst_buf),"(%s or %s)",pf_tcp_dst,pf_udp_dst); + snprintf(pf_dst_buf, sizeof(pf_dst_buf), "(%s or %s)", pf_tcp_dst, pf_udp_dst); pf_dst = pf_dst_buf; } else pf_dst = *pf_tcp_dst ? pf_tcp_dst : pf_udp_dst; - snprintf(wf,len, - DIVERT_PROLOG " and%s%s\n ((outbound and %s%s)\n or\n (inbound and tcp%s%s%s%s%s%s%s))", - IfIdx ? iface : "", - ipv4 ? ipv6 ? "" : " ip and" : " ipv6 and", - pf_dst, - ipv4 ? ipv6 ? " and " DIVERT_NO_LOCALNETS_DST : " and " DIVERT_NO_LOCALNETSv4_DST : " and " DIVERT_NO_LOCALNETSv6_DST, - *pf_tcp_src ? "" : " and false", - *f_tcpin ? " and " : "", - *f_tcpin ? f_tcpin : "", - *pf_tcp_src ? " and " : "", - *pf_tcp_src ? pf_tcp_src : "", - *pf_tcp_src ? " and " : "", - *pf_tcp_src ? ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_SRC : DIVERT_NO_LOCALNETSv4_SRC : DIVERT_NO_LOCALNETSv6_SRC : "" - ); + snprintf(wf, len, + DIVERT_PROLOG " and%s%s\n ((outbound and %s%s)\n or\n (inbound and tcp%s%s%s%s%s%s%s))", + IfIdx ? iface : "", + ipv4 ? ipv6 ? "" : " ip and" : " ipv6 and", + pf_dst, + ipv4 ? ipv6 ? " and " DIVERT_NO_LOCALNETS_DST : " and " DIVERT_NO_LOCALNETSv4_DST : " and " DIVERT_NO_LOCALNETSv6_DST, + *pf_tcp_src ? "" : " and false", + *f_tcpin ? " and " : "", + *f_tcpin ? f_tcpin : "", + *pf_tcp_src ? " and " : "", + *pf_tcp_src ? pf_tcp_src : "", + *pf_tcp_src ? " and " : "", + *pf_tcp_src ? ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_SRC : DIVERT_NO_LOCALNETSv4_SRC : DIVERT_NO_LOCALNETSv6_SRC : ""); return true; } -static unsigned int hash_jen(const void *data,unsigned int len) +static unsigned int hash_jen(const void *data, unsigned int len) { unsigned int hash; - HASH_JEN(data,len,hash); + HASH_JEN(data, len, hash); return hash; } #endif - static void exithelp(void) { printf( @@ -877,15 +893,14 @@ static void exithelp(void) CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP, HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT, #if defined(__linux__) || defined(SO_USER_COOKIE) - DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT, + DPI_DESYNC_FWMARK_DEFAULT, DPI_DESYNC_FWMARK_DEFAULT, #endif - AUTOTTL_DEFAULT_DELTA,AUTOTTL_DEFAULT_MIN,AUTOTTL_DEFAULT_MAX, + AUTOTTL_DEFAULT_DELTA, AUTOTTL_DEFAULT_MIN, AUTOTTL_DEFAULT_MAX, DPI_DESYNC_MAX_FAKE_LEN, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, - UDPLEN_INCREMENT_DEFAULT - ); + UDPLEN_INCREMENT_DEFAULT); exit(1); } static void exithelp_clean(void) @@ -930,12 +945,12 @@ int main(int argc, char **argv) char pidfile[256]; #ifdef __CYGWIN__ char windivert_filter[8192], wf_pf_tcp_src[256], wf_pf_tcp_dst[256], wf_pf_udp_src[256], wf_pf_udp_dst[256], wf_save_file[256]; - bool wf_ipv4=true, wf_ipv6=true; - unsigned int IfIdx=0, SubIfIdx=0; - unsigned int hash_wf_tcp=0,hash_wf_udp=0,hash_wf_raw=0,hash_ssid_filter=0,hash_nlm_filter=0; + bool wf_ipv4 = true, wf_ipv6 = true; + unsigned int IfIdx = 0, SubIfIdx = 0; + unsigned int hash_wf_tcp = 0, hash_wf_udp = 0, hash_wf_raw = 0, hash_ssid_filter = 0, hash_nlm_filter = 0; *windivert_filter = *wf_pf_tcp_src = *wf_pf_tcp_dst = *wf_pf_udp_src = *wf_pf_udp_dst = *wf_save_file = 0; #endif - + srandom(time(NULL)); memset(¶ms, 0, sizeof(params)); @@ -952,10 +967,10 @@ int main(int argc, char **argv) params.desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT; params.desync_repeats = 1; params.fake_tls_size = sizeof(fake_tls_clienthello_default); - memcpy(params.fake_tls,fake_tls_clienthello_default,params.fake_tls_size); + memcpy(params.fake_tls, fake_tls_clienthello_default, params.fake_tls_size); randomize_default_tls_payload(params.fake_tls); params.fake_http_size = strlen(fake_http_request_default); - memcpy(params.fake_http,fake_http_request_default,params.fake_http_size); + memcpy(params.fake_http, fake_http_request_default, params.fake_http_size); params.fake_quic_size = 620; // must be 601+ for TSPU hack params.fake_quic[0] = 0x40; // russian TSPU QUIC short header fake params.fake_wg_size = 64; @@ -963,7 +978,7 @@ int main(int argc, char **argv) params.fake_unknown_size = 256; params.fake_syndata_size = 16; params.fake_unknown_udp_size = 64; - params.wscale=-1; // default - dont change scale factor (client) + params.wscale = -1; // default - don't change scale factor (client) params.ctrack_t_syn = CTRACK_T_SYN; params.ctrack_t_est = CTRACK_T_EST; params.ctrack_t_fin = CTRACK_T_FIN; @@ -992,106 +1007,107 @@ int main(int argc, char **argv) #endif const struct option long_options[] = { - {"debug",optional_argument,0,0}, // optidx=0 + {"debug", optional_argument, 0, 0}, // optidx=0 #ifdef __linux__ - {"qnum",required_argument,0,0}, // optidx=1 + {"qnum", required_argument, 0, 0}, // optidx=1 #elif defined(BSD) - {"port",required_argument,0,0}, // optidx=1 + {"port", required_argument, 0, 0}, // optidx=1 #else - {"disabled_argument_1",no_argument,0,0},// optidx=1 + {"disabled_argument_1", no_argument, 0, 0}, // optidx=1 #endif - {"daemon",no_argument,0,0}, // optidx=2 - {"pidfile",required_argument,0,0}, // optidx=3 + {"daemon", no_argument, 0, 0}, // optidx=2 + {"pidfile", required_argument, 0, 0}, // optidx=3 #ifndef __CYGWIN__ - {"user",required_argument,0,0 }, // optidx=4 - {"uid",required_argument,0,0 }, // optidx=5 + {"user", required_argument, 0, 0}, // optidx=4 + {"uid", required_argument, 0, 0}, // optidx=5 #else - {"disabled_argument_2",no_argument,0,0}, // optidx=4 - {"disabled_argument_3",no_argument,0,0}, // optidx=5 + {"disabled_argument_2", no_argument, 0, 0}, // optidx=4 + {"disabled_argument_3", no_argument, 0, 0}, // optidx=5 #endif - {"wsize",required_argument,0,0}, // optidx=6 - {"wssize",required_argument,0,0}, // optidx=7 - {"wssize-cutoff",required_argument,0,0},// optidx=8 - {"ctrack-timeouts",required_argument,0,0},// optidx=9 - {"hostcase",no_argument,0,0}, // optidx=10 - {"hostspell",required_argument,0,0}, // optidx=11 - {"hostnospace",no_argument,0,0}, // optidx=12 - {"domcase",no_argument,0,0 }, // optidx=13 - {"dpi-desync",required_argument,0,0}, // optidx=14 + {"wsize", required_argument, 0, 0}, // optidx=6 + {"wssize", required_argument, 0, 0}, // optidx=7 + {"wssize-cutoff", required_argument, 0, 0}, // optidx=8 + {"ctrack-timeouts", required_argument, 0, 0}, // optidx=9 + {"hostcase", no_argument, 0, 0}, // optidx=10 + {"hostspell", required_argument, 0, 0}, // optidx=11 + {"hostnospace", no_argument, 0, 0}, // optidx=12 + {"domcase", no_argument, 0, 0}, // optidx=13 + {"dpi-desync", required_argument, 0, 0}, // optidx=14 #ifdef __linux__ - {"dpi-desync-fwmark",required_argument,0,0}, // optidx=15 + {"dpi-desync-fwmark", required_argument, 0, 0}, // optidx=15 #elif defined(SO_USER_COOKIE) - {"dpi-desync-sockarg",required_argument,0,0}, // optidx=15 + {"dpi-desync-sockarg", required_argument, 0, 0}, // optidx=15 #else - {"disabled_argument_4",no_argument,0,0}, // optidx=15 + {"disabled_argument_4", no_argument, 0, 0}, // optidx=15 #endif - {"dpi-desync-ttl",required_argument,0,0}, // optidx=16 - {"dpi-desync-ttl6",required_argument,0,0}, // optidx=17 - {"dpi-desync-autottl",optional_argument,0,0}, // optidx=18 - {"dpi-desync-autottl6",optional_argument,0,0}, // optidx=19 - {"dpi-desync-fooling",required_argument,0,0}, // optidx=20 - {"dpi-desync-repeats",required_argument,0,0}, // optidx=21 - {"dpi-desync-skip-nosni",optional_argument,0,0},// optidx=22 - {"dpi-desync-split-pos",required_argument,0,0},// optidx=23 - {"dpi-desync-split-http-req",required_argument,0,0 },// optidx=24 - {"dpi-desync-split-tls",required_argument,0,0 },// optidx=25 - {"dpi-desync-split-seqovl",required_argument,0,0 },// optidx=26 - {"dpi-desync-split-seqovl-pattern",required_argument,0,0 },// optidx=27 - {"dpi-desync-ipfrag-pos-tcp",required_argument,0,0},// optidx=28 - {"dpi-desync-ipfrag-pos-udp",required_argument,0,0},// optidx=29 - {"dpi-desync-badseq-increment",required_argument,0,0},// optidx=30 - {"dpi-desync-badack-increment",required_argument,0,0},// optidx=31 - {"dpi-desync-any-protocol",optional_argument,0,0},// optidx=32 - {"dpi-desync-fake-http",required_argument,0,0},// optidx=33 - {"dpi-desync-fake-tls",required_argument,0,0},// optidx=34 - {"dpi-desync-fake-unknown",required_argument,0,0},// optidx=35 - {"dpi-desync-fake-syndata",required_argument,0,0},// optidx=36 - {"dpi-desync-fake-quic",required_argument,0,0},// optidx=37 - {"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=38 - {"dpi-desync-fake-dht",required_argument,0,0},// optidx=39 - {"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=40 - {"dpi-desync-udplen-increment",required_argument,0,0},// optidx=41 - {"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=42 - {"dpi-desync-cutoff",required_argument,0,0},// optidx=43 - {"dpi-desync-start",required_argument,0,0},// optidx=43 - {"hostlist",required_argument,0,0}, // optidx=44 - {"hostlist-exclude",required_argument,0,0}, // optidx=45 - {"hostlist-auto",required_argument,0,0}, // optidx=46 - {"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=48 - {"hostlist-auto-fail-time",required_argument,0,0}, // optidx=49 - {"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=50 - {"hostlist-auto-debug",required_argument,0,0}, // optidx=51 - + {"dpi-desync-ttl", required_argument, 0, 0}, // optidx=16 + {"dpi-desync-ttl6", required_argument, 0, 0}, // optidx=17 + {"dpi-desync-autottl", optional_argument, 0, 0}, // optidx=18 + {"dpi-desync-autottl6", optional_argument, 0, 0}, // optidx=19 + {"dpi-desync-fooling", required_argument, 0, 0}, // optidx=20 + {"dpi-desync-repeats", required_argument, 0, 0}, // optidx=21 + {"dpi-desync-skip-nosni", optional_argument, 0, 0}, // optidx=22 + {"dpi-desync-split-pos", required_argument, 0, 0}, // optidx=23 + {"dpi-desync-split-http-req", required_argument, 0, 0}, // optidx=24 + {"dpi-desync-split-tls", required_argument, 0, 0}, // optidx=25 + {"dpi-desync-split-seqovl", required_argument, 0, 0}, // optidx=26 + {"dpi-desync-split-seqovl-pattern", required_argument, 0, 0}, // optidx=27 + {"dpi-desync-ipfrag-pos-tcp", required_argument, 0, 0}, // optidx=28 + {"dpi-desync-ipfrag-pos-udp", required_argument, 0, 0}, // optidx=29 + {"dpi-desync-badseq-increment", required_argument, 0, 0}, // optidx=30 + {"dpi-desync-badack-increment", required_argument, 0, 0}, // optidx=31 + {"dpi-desync-any-protocol", optional_argument, 0, 0}, // optidx=32 + {"dpi-desync-fake-http", required_argument, 0, 0}, // optidx=33 + {"dpi-desync-fake-tls", required_argument, 0, 0}, // optidx=34 + {"dpi-desync-fake-unknown", required_argument, 0, 0}, // optidx=35 + {"dpi-desync-fake-syndata", required_argument, 0, 0}, // optidx=36 + {"dpi-desync-fake-quic", required_argument, 0, 0}, // optidx=37 + {"dpi-desync-fake-wireguard", required_argument, 0, 0}, // optidx=38 + {"dpi-desync-fake-dht", required_argument, 0, 0}, // optidx=39 + {"dpi-desync-fake-unknown-udp", required_argument, 0, 0}, // optidx=40 + {"dpi-desync-udplen-increment", required_argument, 0, 0}, // optidx=41 + {"dpi-desync-udplen-pattern", required_argument, 0, 0}, // optidx=42 + {"dpi-desync-cutoff", required_argument, 0, 0}, // optidx=43 + {"dpi-desync-start", required_argument, 0, 0}, // optidx=43 + {"hostlist", required_argument, 0, 0}, // optidx=44 + {"hostlist-exclude", required_argument, 0, 0}, // optidx=45 + {"hostlist-auto", required_argument, 0, 0}, // optidx=46 + {"hostlist-auto-fail-threshold", required_argument, 0, 0}, // optidx=48 + {"hostlist-auto-fail-time", required_argument, 0, 0}, // optidx=49 + {"hostlist-auto-retrans-threshold", required_argument, 0, 0}, // optidx=50 + {"hostlist-auto-debug", required_argument, 0, 0}, // optidx=51 + #ifdef __linux__ - {"bind-fix4",no_argument,0,0}, // optidx=52 - {"bind-fix6",no_argument,0,0}, // optidx=53 + {"bind-fix4", no_argument, 0, 0}, // optidx=52 + {"bind-fix6", no_argument, 0, 0}, // optidx=53 #elif defined(__CYGWIN__) - {"wf-iface",required_argument,0,0}, // optidx=52 - {"wf-l3",required_argument,0,0}, // optidx=53 - {"wf-tcp",required_argument,0,0}, // optidx=54 - {"wf-udp",required_argument,0,0}, // optidx=55 - {"wf-raw",required_argument,0,0}, // optidx=56 - {"wf-save",required_argument,0,0}, // optidx=57 - {"ssid-filter",required_argument,0,0}, // optidx=58 - {"nlm-filter",required_argument,0,0}, // optidx=59 - {"nlm-list",optional_argument,0,0}, // optidx=60 + {"wf-iface", required_argument, 0, 0}, // optidx=52 + {"wf-l3", required_argument, 0, 0}, // optidx=53 + {"wf-tcp", required_argument, 0, 0}, // optidx=54 + {"wf-udp", required_argument, 0, 0}, // optidx=55 + {"wf-raw", required_argument, 0, 0}, // optidx=56 + {"wf-save", required_argument, 0, 0}, // optidx=57 + {"ssid-filter", required_argument, 0, 0}, // optidx=58 + {"nlm-filter", required_argument, 0, 0}, // optidx=59 + {"nlm-list", optional_argument, 0, 0}, // optidx=60 #endif - {NULL,0,NULL,0} - }; - if (argc < 2) exithelp(); + {NULL, 0, NULL, 0}}; + if (argc < 2) + exithelp(); while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { - if (v) exithelp(); + if (v) + exithelp(); switch (option_index) { case 0: /* debug */ if (optarg) { - if (*optarg=='@') + if (*optarg == '@') { - strncpy(params.debug_logfile,optarg+1,sizeof(params.debug_logfile)); - params.debug_logfile[sizeof(params.debug_logfile)-1] = 0; - FILE *F = fopen(params.debug_logfile,"wt"); + strncpy(params.debug_logfile, optarg + 1, sizeof(params.debug_logfile)); + params.debug_logfile[sizeof(params.debug_logfile) - 1] = 0; + FILE *F = fopen(params.debug_logfile, "wt"); if (!F) { fprintf(stderr, "cannot create %s\n", params.debug_logfile); @@ -1104,11 +1120,11 @@ int main(int argc, char **argv) params.debug = true; params.debug_target = LOG_TARGET_FILE; } - else if (!strcmp(optarg,"syslog")) + else if (!strcmp(optarg, "syslog")) { params.debug = true; params.debug_target = LOG_TARGET_SYSLOG; - openlog(progname,LOG_PID,LOG_USER); + openlog(progname, LOG_PID, LOG_USER); } else { @@ -1126,21 +1142,21 @@ int main(int argc, char **argv) case 1: /* qnum or port */ #ifdef __linux__ params.qnum = atoi(optarg); - if (params.qnum < 0 || params.qnum>65535) + if (params.qnum < 0 || params.qnum > 65535) { DLOG_ERR("bad qnum\n"); exit_clean(1); } #elif defined(BSD) + { + int i = atoi(optarg); + if (i <= 0 || i > 65535) { - int i = atoi(optarg); - if (i <= 0 || i > 65535) - { - DLOG_ERR("bad port number\n"); - exit_clean(1); - } - params.port = (uint16_t)i; + DLOG_ERR("bad port number\n"); + exit_clean(1); } + params.port = (uint16_t)i; + } #endif break; #endif @@ -1165,10 +1181,10 @@ int main(int argc, char **argv) params.droproot = true; break; } - case 5: /* uid */ + case 5: /* uid */ params.gid = 0x7FFFFFFF; // default gid. drop gid=0 params.droproot = true; - if (sscanf(optarg, "%u:%u", ¶ms.uid, ¶ms.gid)<1) + if (sscanf(optarg, "%u:%u", ¶ms.uid, ¶ms.gid) < 1) { DLOG_ERR("--uid should be : uid[:gid]\n"); exit_clean(1); @@ -1176,11 +1192,11 @@ int main(int argc, char **argv) break; #endif case 6: /* wsize */ - if (!parse_ws_scale_factor(optarg,¶ms.wsize,¶ms.wscale)) + if (!parse_ws_scale_factor(optarg, ¶ms.wsize, ¶ms.wscale)) exit_clean(1); break; case 7: /* wssize */ - if (!parse_ws_scale_factor(optarg,¶ms.wssize,¶ms.wsscale)) + if (!parse_ws_scale_factor(optarg, ¶ms.wssize, ¶ms.wsscale)) exit_clean(1); break; case 8: /* wssize-cutoff */ @@ -1191,7 +1207,7 @@ int main(int argc, char **argv) } break; case 9: /* ctrack-timeouts */ - if (sscanf(optarg, "%u:%u:%u:%u", ¶ms.ctrack_t_syn, ¶ms.ctrack_t_est, ¶ms.ctrack_t_fin, ¶ms.ctrack_t_udp)<3) + if (sscanf(optarg, "%u:%u:%u:%u", ¶ms.ctrack_t_syn, ¶ms.ctrack_t_est, ¶ms.ctrack_t_fin, ¶ms.ctrack_t_udp) < 3) { DLOG_ERR("invalid ctrack-timeouts value\n"); exit_clean(1); @@ -1216,55 +1232,58 @@ int main(int argc, char **argv) params.domcase = true; break; case 14: /* dpi-desync */ - { - char *mode=optarg,*mode2,*mode3; - mode2 = mode ? strchr(mode,',') : NULL; - if (mode2) *mode2++=0; - mode3 = mode2 ? strchr(mode2,',') : NULL; - if (mode3) *mode3++=0; + { + char *mode = optarg, *mode2, *mode3; + mode2 = mode ? strchr(mode, ',') : NULL; + if (mode2) + *mode2++ = 0; + mode3 = mode2 ? strchr(mode2, ',') : NULL; + if (mode3) + *mode3++ = 0; - params.desync_mode0 = desync_mode_from_string(mode); - if (desync_valid_zero_stage(params.desync_mode0)) - { - mode = mode2; - mode2 = mode3; - mode3 = NULL; - } - else - { - params.desync_mode0 = DESYNC_NONE; - } - params.desync_mode = desync_mode_from_string(mode); - params.desync_mode2 = desync_mode_from_string(mode2); - if (params.desync_mode0==DESYNC_INVALID || params.desync_mode==DESYNC_INVALID || params.desync_mode2==DESYNC_INVALID) - { - DLOG_ERR("invalid dpi-desync mode\n"); - exit_clean(1); - } - if (mode3) - { - DLOG_ERR("invalid desync combo : %s+%s+%s\n",mode,mode2,mode3); - exit_clean(1); - } - if (params.desync_mode2 && (desync_only_first_stage(params.desync_mode) || !(desync_valid_first_stage(params.desync_mode) && desync_valid_second_stage(params.desync_mode2)))) - { - DLOG_ERR("invalid desync combo : %s+%s\n", mode,mode2); - exit_clean(1); - } - #if defined(__OpenBSD__) - if (params.desync_mode==DESYNC_IPFRAG2 || params.desync_mode2==DESYNC_IPFRAG2) - { - DLOG_ERR("OpenBSD has checksum issues with fragmented packets. ipfrag disabled.\n"); - exit_clean(1); - } - #endif + params.desync_mode0 = desync_mode_from_string(mode); + if (desync_valid_zero_stage(params.desync_mode0)) + { + mode = mode2; + mode2 = mode3; + mode3 = NULL; } - break; + else + { + params.desync_mode0 = DESYNC_NONE; + } + params.desync_mode = desync_mode_from_string(mode); + params.desync_mode2 = desync_mode_from_string(mode2); + if (params.desync_mode0 == DESYNC_INVALID || params.desync_mode == DESYNC_INVALID || params.desync_mode2 == DESYNC_INVALID) + { + DLOG_ERR("invalid dpi-desync mode\n"); + exit_clean(1); + } + if (mode3) + { + DLOG_ERR("invalid desync combo : %s+%s+%s\n", mode, mode2, mode3); + exit_clean(1); + } + if (params.desync_mode2 && (desync_only_first_stage(params.desync_mode) || !(desync_valid_first_stage(params.desync_mode) && desync_valid_second_stage(params.desync_mode2)))) + { + DLOG_ERR("invalid desync combo : %s+%s\n", mode, mode2); + exit_clean(1); + } +#if defined(__OpenBSD__) + if (params.desync_mode == DESYNC_IPFRAG2 || params.desync_mode2 == DESYNC_IPFRAG2) + { + DLOG_ERR("OpenBSD has checksum issues with fragmented packets. ipfrag disabled.\n"); + exit_clean(1); + } +#endif + } + break; #ifndef __CYGWIN__ case 15: /* dpi-desync-fwmark/dpi-desync-sockarg */ #if defined(__linux__) || defined(SO_USER_COOKIE) params.desync_fwmark = 0; - if (sscanf(optarg, "0x%X", ¶ms.desync_fwmark)<=0) sscanf(optarg, "%u", ¶ms.desync_fwmark); + if (sscanf(optarg, "0x%X", ¶ms.desync_fwmark) <= 0) + sscanf(optarg, "%u", ¶ms.desync_fwmark); if (!params.desync_fwmark) { DLOG_ERR("fwmark/sockarg should be decimal or 0xHEX and should not be zero\n"); @@ -1297,42 +1316,43 @@ int main(int argc, char **argv) } break; case 20: /* dpi-desync-fooling */ + { + char *e, *p = optarg; + while (p) { - char *e,*p = optarg; - while (p) + e = strchr(p, ','); + if (e) + *e++ = 0; + if (!strcmp(p, "md5sig")) + params.desync_fooling_mode |= FOOL_MD5SIG; + else if (!strcmp(p, "ts")) + params.desync_fooling_mode |= FOOL_TS; + else if (!strcmp(p, "badsum")) { - e = strchr(p,','); - if (e) *e++=0; - if (!strcmp(p,"md5sig")) - params.desync_fooling_mode |= FOOL_MD5SIG; - else if (!strcmp(p,"ts")) - params.desync_fooling_mode |= FOOL_TS; - else if (!strcmp(p,"badsum")) - { - #ifdef __OpenBSD__ - DLOG_CONDUP("\nWARNING !!! OpenBSD may forcibly recompute tcp/udp checksums !!! In this case badsum fooling will not work.\nYou should check tcp checksum correctness in tcpdump manually before using badsum.\n\n"); - #endif - params.desync_fooling_mode |= FOOL_BADSUM; - } - else if (!strcmp(p,"badseq")) - params.desync_fooling_mode |= FOOL_BADSEQ; - else if (!strcmp(p,"datanoack")) - params.desync_fooling_mode |= FOOL_DATANOACK; - else if (!strcmp(p,"hopbyhop")) - params.desync_fooling_mode |= FOOL_HOPBYHOP; - else if (!strcmp(p,"hopbyhop2")) - params.desync_fooling_mode |= FOOL_HOPBYHOP2; - else if (strcmp(p,"none")) - { - DLOG_ERR("dpi-desync-fooling allowed values : none,md5sig,ts,badseq,badsum,datanoack,hopbyhop,hopbyhop2\n"); - exit_clean(1); - } - p = e; +#ifdef __OpenBSD__ + DLOG_CONDUP("\nWARNING !!! OpenBSD may forcibly recompute tcp/udp checksums !!! In this case badsum fooling will not work.\nYou should check tcp checksum correctness in tcpdump manually before using badsum.\n\n"); +#endif + params.desync_fooling_mode |= FOOL_BADSUM; } + else if (!strcmp(p, "badseq")) + params.desync_fooling_mode |= FOOL_BADSEQ; + else if (!strcmp(p, "datanoack")) + params.desync_fooling_mode |= FOOL_DATANOACK; + else if (!strcmp(p, "hopbyhop")) + params.desync_fooling_mode |= FOOL_HOPBYHOP; + else if (!strcmp(p, "hopbyhop2")) + params.desync_fooling_mode |= FOOL_HOPBYHOP2; + else if (strcmp(p, "none")) + { + DLOG_ERR("dpi-desync-fooling allowed values : none,md5sig,ts,badseq,badsum,datanoack,hopbyhop,hopbyhop2\n"); + exit_clean(1); + } + p = e; } - break; + } + break; case 21: /* dpi-desync-repeats */ - if (sscanf(optarg,"%u",¶ms.desync_repeats)<1 || !params.desync_repeats || params.desync_repeats>20) + if (sscanf(optarg, "%u", ¶ms.desync_repeats) < 1 || !params.desync_repeats || params.desync_repeats > 20) { DLOG_ERR("dpi-desync-repeats must be within 1..20\n"); exit_clean(1); @@ -1342,7 +1362,7 @@ int main(int argc, char **argv) params.desync_skip_nosni = !optarg || atoi(optarg); break; case 23: /* dpi-desync-split-pos */ - if (sscanf(optarg,"%u",¶ms.desync_split_pos)<1 || params.desync_split_pos<1) + if (sscanf(optarg, "%u", ¶ms.desync_split_pos) < 1 || params.desync_split_pos < 1) { DLOG_ERR("dpi-desync-split-pos is not valid\n"); exit_clean(1); @@ -1363,24 +1383,24 @@ int main(int argc, char **argv) } break; case 26: /* dpi-desync-split-seqovl */ - if (sscanf(optarg,"%u",¶ms.desync_seqovl)<1) + if (sscanf(optarg, "%u", ¶ms.desync_seqovl) < 1) { DLOG_ERR("dpi-desync-split-seqovl is not valid\n"); exit_clean(1); } break; case 27: /* dpi-desync-split-seqovl-pattern */ - { - char buf[sizeof(params.seqovl_pattern)]; - size_t sz=sizeof(buf); - load_file_or_exit(optarg,buf,&sz); - fill_pattern(params.seqovl_pattern,sizeof(params.seqovl_pattern),buf,sz); - } - break; + { + char buf[sizeof(params.seqovl_pattern)]; + size_t sz = sizeof(buf); + load_file_or_exit(optarg, buf, &sz); + fill_pattern(params.seqovl_pattern, sizeof(params.seqovl_pattern), buf, sz); + } + break; case 28: /* dpi-desync-ipfrag-pos-tcp */ - if (sscanf(optarg,"%u",¶ms.desync_ipfrag_pos_tcp)<1 || params.desync_ipfrag_pos_tcp<1 || params.desync_ipfrag_pos_tcp>DPI_DESYNC_MAX_FAKE_LEN) + if (sscanf(optarg, "%u", ¶ms.desync_ipfrag_pos_tcp) < 1 || params.desync_ipfrag_pos_tcp < 1 || params.desync_ipfrag_pos_tcp > DPI_DESYNC_MAX_FAKE_LEN) { - DLOG_ERR("dpi-desync-ipfrag-pos-tcp must be within 1..%u range\n",DPI_DESYNC_MAX_FAKE_LEN); + DLOG_ERR("dpi-desync-ipfrag-pos-tcp must be within 1..%u range\n", DPI_DESYNC_MAX_FAKE_LEN); exit_clean(1); } if (params.desync_ipfrag_pos_tcp & 7) @@ -1390,9 +1410,9 @@ int main(int argc, char **argv) } break; case 29: /* dpi-desync-ipfrag-pos-udp */ - if (sscanf(optarg,"%u",¶ms.desync_ipfrag_pos_udp)<1 || params.desync_ipfrag_pos_udp<1 || params.desync_ipfrag_pos_udp>DPI_DESYNC_MAX_FAKE_LEN) + if (sscanf(optarg, "%u", ¶ms.desync_ipfrag_pos_udp) < 1 || params.desync_ipfrag_pos_udp < 1 || params.desync_ipfrag_pos_udp > DPI_DESYNC_MAX_FAKE_LEN) { - DLOG_ERR("dpi-desync-ipfrag-pos-udp must be within 1..%u range\n",DPI_DESYNC_MAX_FAKE_LEN); + DLOG_ERR("dpi-desync-ipfrag-pos-udp must be within 1..%u range\n", DPI_DESYNC_MAX_FAKE_LEN); exit_clean(1); } if (params.desync_ipfrag_pos_udp & 7) @@ -1402,14 +1422,14 @@ int main(int argc, char **argv) } break; case 30: /* dpi-desync-badseq-increments */ - if (!parse_badseq_increment(optarg,¶ms.desync_badseq_increment)) + if (!parse_badseq_increment(optarg, ¶ms.desync_badseq_increment)) { DLOG_ERR("dpi-desync-badseq-increment should be signed decimal or signed 0xHEX\n"); exit_clean(1); } break; case 31: /* dpi-desync-badack-increment */ - if (!parse_badseq_increment(optarg,¶ms.desync_badseq_ack_increment)) + if (!parse_badseq_increment(optarg, ¶ms.desync_badseq_ack_increment)) { DLOG_ERR("dpi-desync-badack-increment should be signed decimal or signed 0xHEX\n"); exit_clean(1); @@ -1420,51 +1440,51 @@ int main(int argc, char **argv) break; case 33: /* dpi-desync-fake-http */ params.fake_http_size = sizeof(params.fake_http); - load_file_or_exit(optarg,params.fake_http,¶ms.fake_http_size); + load_file_or_exit(optarg, params.fake_http, ¶ms.fake_http_size); break; case 34: /* dpi-desync-fake-tls */ params.fake_tls_size = sizeof(params.fake_tls); - load_file_or_exit(optarg,params.fake_tls,¶ms.fake_tls_size); + load_file_or_exit(optarg, params.fake_tls, ¶ms.fake_tls_size); break; case 35: /* dpi-desync-fake-unknown */ params.fake_unknown_size = sizeof(params.fake_unknown); - load_file_or_exit(optarg,params.fake_unknown,¶ms.fake_unknown_size); + load_file_or_exit(optarg, params.fake_unknown, ¶ms.fake_unknown_size); break; case 36: /* dpi-desync-fake-syndata */ params.fake_syndata_size = sizeof(params.fake_syndata); - load_file_or_exit(optarg,params.fake_syndata,¶ms.fake_syndata_size); + load_file_or_exit(optarg, params.fake_syndata, ¶ms.fake_syndata_size); break; case 37: /* dpi-desync-fake-quic */ params.fake_quic_size = sizeof(params.fake_quic); - load_file_or_exit(optarg,params.fake_quic,¶ms.fake_quic_size); + load_file_or_exit(optarg, params.fake_quic, ¶ms.fake_quic_size); break; case 38: /* dpi-desync-fake-wireguard */ params.fake_wg_size = sizeof(params.fake_wg); - load_file_or_exit(optarg,params.fake_wg,¶ms.fake_wg_size); + load_file_or_exit(optarg, params.fake_wg, ¶ms.fake_wg_size); break; case 39: /* dpi-desync-fake-dht */ params.fake_dht_size = sizeof(params.fake_dht); - load_file_or_exit(optarg,params.fake_dht,¶ms.fake_dht_size); + load_file_or_exit(optarg, params.fake_dht, ¶ms.fake_dht_size); break; case 40: /* dpi-desync-fake-unknown-udp */ params.fake_unknown_udp_size = sizeof(params.fake_unknown_udp); - load_file_or_exit(optarg,params.fake_unknown_udp,¶ms.fake_unknown_udp_size); + load_file_or_exit(optarg, params.fake_unknown_udp, ¶ms.fake_unknown_udp_size); break; case 41: /* dpi-desync-udplen-increment */ - if (sscanf(optarg,"%d",¶ms.udplen_increment)<1 || params.udplen_increment>0x7FFF || params.udplen_increment<-0x8000) + if (sscanf(optarg, "%d", ¶ms.udplen_increment) < 1 || params.udplen_increment > 0x7FFF || params.udplen_increment < -0x8000) { DLOG_ERR("dpi-desync-udplen-increment must be integer within -32768..32767 range\n"); exit_clean(1); } break; case 42: /* dpi-desync-udplen-pattern */ - { - char buf[sizeof(params.udplen_pattern)]; - size_t sz=sizeof(buf); - load_file_or_exit(optarg,buf,&sz); - fill_pattern(params.udplen_pattern,sizeof(params.udplen_pattern),buf,sz); - } - break; + { + char buf[sizeof(params.udplen_pattern)]; + size_t sz = sizeof(buf); + load_file_or_exit(optarg, buf, &sz); + fill_pattern(params.udplen_pattern, sizeof(params.udplen_pattern), buf, sz); + } + break; case 43: /* desync-cutoff */ if (!parse_cutoff(optarg, ¶ms.desync_cutoff, ¶ms.desync_cutoff_mode)) { @@ -1500,7 +1520,7 @@ int main(int argc, char **argv) exit_clean(1); } { - FILE *F = fopen(optarg,"at"); + FILE *F = fopen(optarg, "at"); if (!F) { DLOG_ERR("cannot create %s\n", optarg); @@ -1528,7 +1548,7 @@ int main(int argc, char **argv) break; case 48: /* hostlist-auto-fail-threshold */ params.hostlist_auto_fail_threshold = (uint8_t)atoi(optarg); - if (params.hostlist_auto_fail_threshold<1 || params.hostlist_auto_fail_threshold>20) + if (params.hostlist_auto_fail_threshold < 1 || params.hostlist_auto_fail_threshold > 20) { DLOG_ERR("auto hostlist fail threshold must be within 1..20\n"); exit_clean(1); @@ -1536,7 +1556,7 @@ int main(int argc, char **argv) break; case 49: /* hostlist-auto-fail-time */ params.hostlist_auto_fail_time = (uint8_t)atoi(optarg); - if (params.hostlist_auto_fail_time<1) + if (params.hostlist_auto_fail_time < 1) { DLOG_ERR("auto hostlist fail time is not valid\n"); exit_clean(1); @@ -1544,29 +1564,29 @@ int main(int argc, char **argv) break; case 50: /* hostlist-auto-retrans-threshold */ params.hostlist_auto_retrans_threshold = (uint8_t)atoi(optarg); - if (params.hostlist_auto_retrans_threshold<2 || params.hostlist_auto_retrans_threshold>10) + if (params.hostlist_auto_retrans_threshold < 2 || params.hostlist_auto_retrans_threshold > 10) { DLOG_ERR("auto hostlist fail threshold must be within 2..10\n"); exit_clean(1); } break; case 51: /* hostlist-auto-debug */ + { + FILE *F = fopen(optarg, "a+t"); + if (!F) { - FILE *F = fopen(optarg,"a+t"); - if (!F) - { - DLOG_ERR("cannot create %s\n", optarg); - exit_clean(1); - } - fclose(F); -#ifndef __CYGWIN__ - if (params.droproot && chown(optarg, params.uid, -1)) - DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", optarg); -#endif - strncpy(params.hostlist_auto_debuglog, optarg, sizeof(params.hostlist_auto_debuglog)); - params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0'; + DLOG_ERR("cannot create %s\n", optarg); + exit_clean(1); } - break; + fclose(F); +#ifndef __CYGWIN__ + if (params.droproot && chown(optarg, params.uid, -1)) + DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", optarg); +#endif + strncpy(params.hostlist_auto_debuglog, optarg, sizeof(params.hostlist_auto_debuglog)); + params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0'; + } + break; #ifdef __linux__ case 52: /* bind-fix4 */ params.bind_fix4 = true; @@ -1576,43 +1596,43 @@ int main(int argc, char **argv) break; #elif defined(__CYGWIN__) case 52: /* wf-iface */ - if (!sscanf(optarg,"%u.%u",&IfIdx,&SubIfIdx)) + if (!sscanf(optarg, "%u.%u", &IfIdx, &SubIfIdx)) { DLOG_ERR("bad value for --wf-iface\n"); exit_clean(1); } break; case 53: /* wf-l3 */ - if (!wf_make_l3(optarg,&wf_ipv4,&wf_ipv6)) + if (!wf_make_l3(optarg, &wf_ipv4, &wf_ipv6)) { DLOG_ERR("bad value for --wf-l3\n"); exit_clean(1); } break; case 54: /* wf-tcp */ - hash_wf_tcp=hash_jen(optarg,strlen(optarg)); - if (!wf_make_pf(optarg,"tcp","SrcPort",wf_pf_tcp_src,sizeof(wf_pf_tcp_src)) || - !wf_make_pf(optarg,"tcp","DstPort",wf_pf_tcp_dst,sizeof(wf_pf_tcp_dst))) + hash_wf_tcp = hash_jen(optarg, strlen(optarg)); + if (!wf_make_pf(optarg, "tcp", "SrcPort", wf_pf_tcp_src, sizeof(wf_pf_tcp_src)) || + !wf_make_pf(optarg, "tcp", "DstPort", wf_pf_tcp_dst, sizeof(wf_pf_tcp_dst))) { DLOG_ERR("bad value for --wf-tcp\n"); exit_clean(1); } break; case 55: /* wf-udp */ - hash_wf_udp=hash_jen(optarg,strlen(optarg)); - if (!wf_make_pf(optarg,"udp","SrcPort",wf_pf_udp_src,sizeof(wf_pf_udp_src)) || - !wf_make_pf(optarg,"udp","DstPort",wf_pf_udp_dst,sizeof(wf_pf_udp_dst))) + hash_wf_udp = hash_jen(optarg, strlen(optarg)); + if (!wf_make_pf(optarg, "udp", "SrcPort", wf_pf_udp_src, sizeof(wf_pf_udp_src)) || + !wf_make_pf(optarg, "udp", "DstPort", wf_pf_udp_dst, sizeof(wf_pf_udp_dst))) { DLOG_ERR("bad value for --wf-udp\n"); exit_clean(1); } break; case 56: /* wf-raw */ - hash_wf_raw=hash_jen(optarg,strlen(optarg)); - if (optarg[0]=='@') + hash_wf_raw = hash_jen(optarg, strlen(optarg)); + if (optarg[0] == '@') { - size_t sz = sizeof(windivert_filter)-1; - load_file_or_exit(optarg+1,windivert_filter,&sz); + size_t sz = sizeof(windivert_filter) - 1; + load_file_or_exit(optarg + 1, windivert_filter, &sz); windivert_filter[sz] = 0; } else @@ -1626,43 +1646,43 @@ int main(int argc, char **argv) wf_save_file[sizeof(wf_save_file) - 1] = '\0'; break; case 58: /* ssid-filter */ - hash_ssid_filter=hash_jen(optarg,strlen(optarg)); + hash_ssid_filter = hash_jen(optarg, strlen(optarg)); { - char *e,*p = optarg; + char *e, *p = optarg; while (p) { - e = strchr(p,','); - if (e) *e++=0; + e = strchr(p, ','); + if (e) + *e++ = 0; if (*p && !strlist_add(¶ms.ssid_filter, p)) { DLOG_ERR("strlist_add failed\n"); exit_clean(1); } p = e; - } } break; case 59: /* nlm-filter */ - hash_nlm_filter=hash_jen(optarg,strlen(optarg)); + hash_nlm_filter = hash_jen(optarg, strlen(optarg)); { - char *e,*p = optarg; + char *e, *p = optarg; while (p) { - e = strchr(p,','); - if (e) *e++=0; + e = strchr(p, ','); + if (e) + *e++ = 0; if (*p && !strlist_add(¶ms.nlm_filter, p)) { DLOG_ERR("strlist_add failed\n"); exit_clean(1); } p = e; - } } break; case 60: /* nlm-list */ - if (!nlm_list(optarg && !strcmp(optarg,"all"))) + if (!nlm_list(optarg && !strcmp(optarg, "all"))) { DLOG_ERR("could not get list of NLM networks\n"); exit_clean(1); @@ -1674,7 +1694,7 @@ int main(int argc, char **argv) } #ifdef __linux__ - if (params.qnum<0) + if (params.qnum < 0) { DLOG_ERR("Need queue number (--qnum)\n"); exit_clean(1); @@ -1699,10 +1719,10 @@ int main(int argc, char **argv) exit_clean(1); } } - DLOG("windivert filter size: %zu\nwindivert filter:\n%s\n",strlen(windivert_filter),windivert_filter); + DLOG("windivert filter size: %zu\nwindivert filter:\n%s\n", strlen(windivert_filter), windivert_filter); if (*wf_save_file) { - if (save_file(wf_save_file,windivert_filter,strlen(windivert_filter))) + if (save_file(wf_save_file, windivert_filter, strlen(windivert_filter))) { DLOG_ERR("windivert filter: raw filter saved to %s\n", wf_save_file); exit_clean(0); @@ -1716,28 +1736,32 @@ int main(int argc, char **argv) HANDLE hMutexArg; { char mutex_name[128]; - snprintf(mutex_name,sizeof(mutex_name),"Global\\winws_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u",hash_wf_tcp,hash_wf_udp,hash_wf_raw,hash_ssid_filter,hash_nlm_filter,IfIdx,SubIfIdx,wf_ipv4,wf_ipv6); + snprintf(mutex_name, sizeof(mutex_name), "Global\\winws_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u", hash_wf_tcp, hash_wf_udp, hash_wf_raw, hash_ssid_filter, hash_nlm_filter, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6); - hMutexArg = CreateMutexA(NULL,TRUE,mutex_name); - if (hMutexArg && GetLastError()==ERROR_ALREADY_EXISTS) + hMutexArg = CreateMutexA(NULL, TRUE, mutex_name); + if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS) { - CloseHandle(hMutexArg); hMutexArg = NULL; + CloseHandle(hMutexArg); + hMutexArg = NULL; DLOG_ERR("A copy of winws is already running with the same filter\n"); goto exiterr; } - } #endif // not specified - use desync_ttl value instead - if (params.desync_ttl6 == 0xFF) params.desync_ttl6=params.desync_ttl; - if (!AUTOTTL_ENABLED(params.desync_autottl6)) params.desync_autottl6 = params.desync_autottl; + if (params.desync_ttl6 == 0xFF) + params.desync_ttl6 = params.desync_ttl; + if (!AUTOTTL_ENABLED(params.desync_autottl6)) + params.desync_autottl6 = params.desync_autottl; if (AUTOTTL_ENABLED(params.desync_autottl)) - DLOG("autottl ipv4 %u:%u-%u\n",params.desync_autottl.delta,params.desync_autottl.min,params.desync_autottl.max); + DLOG("autottl IPv4 %u:%u-%u\n", params.desync_autottl.delta, params.desync_autottl.min, params.desync_autottl.max); if (AUTOTTL_ENABLED(params.desync_autottl6)) - DLOG("autottl ipv6 %u:%u-%u\n",params.desync_autottl6.delta,params.desync_autottl6.min,params.desync_autottl6.max); - if (params.desync_split_tls==tlspos_none && params.desync_split_pos) params.desync_split_tls=tlspos_pos; - if (params.desync_split_http_req==httpreqpos_none && params.desync_split_pos) params.desync_split_http_req=httpreqpos_pos; + DLOG("autottl IPv6 %u:%u-%u\n", params.desync_autottl6.delta, params.desync_autottl6.min, params.desync_autottl6.max); + if (params.desync_split_tls == tlspos_none && params.desync_split_pos) + params.desync_split_tls = tlspos_pos; + if (params.desync_split_http_req == httpreqpos_none && params.desync_split_pos) + params.desync_split_http_req = httpreqpos_pos; if (!LoadIncludeHostLists()) { @@ -1752,7 +1776,8 @@ int main(int argc, char **argv) exit_clean(1); } - if (daemon) daemonize(); + if (daemon) + daemonize(); if (*pidfile && !writepid(pidfile)) { @@ -1770,7 +1795,7 @@ int main(int argc, char **argv) #elif defined(__CYGWIN__) result = win_main(windivert_filter); #else - #error unsupported OS +#error unsupported OS #endif ex: rawsend_cleanup(); diff --git a/nfq/packet_queue.c b/nfq/packet_queue.c index ff5ee73..709607f 100644 --- a/nfq/packet_queue.c +++ b/nfq/packet_queue.c @@ -9,26 +9,30 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q) } void rawpacket_free(struct rawpacket *rp) { - if (rp) free(rp->packet); + if (rp) + free(rp->packet); free(rp); } struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q) { struct rawpacket *rp; rp = TAILQ_FIRST(q); - if (rp) TAILQ_REMOVE(q, rp, next); + if (rp) + TAILQ_REMOVE(q, rp, next); return rp; } void rawpacket_queue_destroy(struct rawpacket_tailhead *q) { struct rawpacket *rp; - while((rp = rawpacket_dequeue(q))) rawpacket_free(rp); + while ((rp = rawpacket_dequeue(q))) + rawpacket_free(rp); } -struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len,size_t len_payload) +struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q, const struct sockaddr_storage *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len, size_t len_payload) { struct rawpacket *rp = malloc(sizeof(struct rawpacket)); - if (!rp) return NULL; + if (!rp) + return NULL; rp->packet = malloc(len); if (!rp->packet) @@ -36,30 +40,31 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock free(rp); return NULL; } - + rp->dst = *dst; rp->fwmark = fwmark; if (ifout) { - strncpy(rp->ifout,ifout,sizeof(rp->ifout)); - rp->ifout[sizeof(rp->ifout)-1]=0; + strncpy(rp->ifout, ifout, sizeof(rp->ifout)); + rp->ifout[sizeof(rp->ifout) - 1] = 0; } else - rp->ifout[0]=0; - memcpy(rp->packet,data,len); - rp->len=len; - rp->len_payload=len_payload; - + rp->ifout[0] = 0; + memcpy(rp->packet, data, len); + rp->len = len; + rp->len_payload = len_payload; + TAILQ_INSERT_TAIL(q, rp, next); - + return rp; } unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q) { const struct rawpacket *rp; - unsigned int ct=0; - TAILQ_FOREACH(rp, q, next) ct++; + unsigned int ct = 0; + TAILQ_FOREACH(rp, q, next) + ct++; return ct; } bool rawpacket_queue_empty(const struct rawpacket_tailhead *q) diff --git a/nfq/packet_queue.h b/nfq/packet_queue.h index fb57798..5ec3284 100644 --- a/nfq/packet_queue.h +++ b/nfq/packet_queue.h @@ -9,11 +9,12 @@ struct rawpacket { struct sockaddr_storage dst; - char ifout[IFNAMSIZ+1]; + char ifout[IFNAMSIZ + 1]; uint32_t fwmark; size_t len, len_payload; uint8_t *packet; - TAILQ_ENTRY(rawpacket) next; + TAILQ_ENTRY(rawpacket) + next; }; TAILQ_HEAD(rawpacket_tailhead, rawpacket); @@ -21,6 +22,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q); void rawpacket_queue_destroy(struct rawpacket_tailhead *q); bool rawpacket_queue_empty(const struct rawpacket_tailhead *q); unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q); -struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len,size_t len_payload); +struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q, const struct sockaddr_storage *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len, size_t len_payload); struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q); void rawpacket_free(struct rawpacket *rp); diff --git a/nfq/params.c b/nfq/params.c index 5e29a92..e701004 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -13,40 +13,39 @@ const char *progname = "nfqws"; #error UNKNOWN_SYSTEM_TIME #endif - int DLOG_FILE(FILE *F, const char *format, va_list args) { return vfprintf(F, format, args); } int DLOG_CON(const char *format, int syslog_priority, va_list args) { - return DLOG_FILE(syslog_priority==LOG_ERR ? stderr : stdout, format, args); + return DLOG_FILE(syslog_priority == LOG_ERR ? stderr : stdout, format, args); } int DLOG_FILENAME(const char *filename, const char *format, va_list args) { int r; - FILE *F = fopen(filename,"at"); + FILE *F = fopen(filename, "at"); if (F) { r = DLOG_FILE(F, format, args); fclose(F); } else - r=-1; + r = -1; return r; } static char syslog_buf[1024]; -static size_t syslog_buf_sz=0; +static size_t syslog_buf_sz = 0; static void syslog_buffered(int priority, const char *format, va_list args) { - if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0) + if (vsnprintf(syslog_buf + syslog_buf_sz, sizeof(syslog_buf) - syslog_buf_sz, format, args) > 0) { - syslog_buf_sz=strlen(syslog_buf); + syslog_buf_sz = strlen(syslog_buf); // log when buffer is full or buffer ends with \n - if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n')) + if (syslog_buf_sz >= (sizeof(syslog_buf) - 1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz - 1] == '\n')) { - syslog(priority,"%s",syslog_buf); + syslog(priority, "%s", syslog_buf); syslog_buf_sz = 0; } } @@ -54,31 +53,31 @@ static void syslog_buffered(int priority, const char *format, va_list args) static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list args) { - int r=0; + int r = 0; va_list args2; - if (condup && !(params.debug && params.debug_target==LOG_TARGET_CONSOLE)) + if (condup && !(params.debug && params.debug_target == LOG_TARGET_CONSOLE)) { - va_copy(args2,args); - DLOG_CON(format,syslog_priority,args2); + va_copy(args2, args); + DLOG_CON(format, syslog_priority, args2); } if (params.debug) { - switch(params.debug_target) + switch (params.debug_target) { - case LOG_TARGET_CONSOLE: - r = DLOG_CON(format,syslog_priority,args); - break; - case LOG_TARGET_FILE: - r = DLOG_FILENAME(params.debug_logfile,format,args); - break; - case LOG_TARGET_SYSLOG: - // skip newlines - syslog_buffered(syslog_priority,format,args); - r = 1; - break; - default: - break; + case LOG_TARGET_CONSOLE: + r = DLOG_CON(format, syslog_priority, args); + break; + case LOG_TARGET_FILE: + r = DLOG_FILENAME(params.debug_logfile, format, args); + break; + case LOG_TARGET_SYSLOG: + // skip newlines + syslog_buffered(syslog_priority, format, args); + r = 1; + break; + default: + break; } } return r; @@ -116,11 +115,10 @@ int DLOG_PERROR(const char *s) return DLOG_ERR("%s: %s\n", s, strerror(errno)); } - int LOG_APPEND(const char *filename, const char *format, va_list args) { int r; - FILE *F = fopen(filename,"at"); + FILE *F = fopen(filename, "at"); if (F) { fprint_localtime(F); @@ -130,7 +128,7 @@ int LOG_APPEND(const char *filename, const char *format, va_list args) fclose(F); } else - r=-1; + r = -1; return r; } diff --git a/nfq/params.h b/nfq/params.h index 70ed34e..452c6cf 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -13,27 +13,32 @@ #include #include -#define TLS_PARTIALS_ENABLE true +#define TLS_PARTIALS_ENABLE true -#define Q_RCVBUF (128*1024) // in bytes -#define Q_SNDBUF (64*1024) // in bytes -#define RAW_SNDBUF (64*1024) // in bytes +#define Q_RCVBUF (128 * 1024) // in bytes +#define Q_SNDBUF (64 * 1024) // in bytes +#define RAW_SNDBUF (64 * 1024) // in bytes -#define Q_MAXLEN 1024 // in packets +#define Q_MAXLEN 1024 // in packets -#define BADSEQ_INCREMENT_DEFAULT -10000 -#define BADSEQ_ACK_INCREMENT_DEFAULT -66000 +#define BADSEQ_INCREMENT_DEFAULT -10000 +#define BADSEQ_ACK_INCREMENT_DEFAULT -66000 #define IPFRAG_UDP_DEFAULT 8 #define IPFRAG_TCP_DEFAULT 32 -#define UDPLEN_INCREMENT_DEFAULT 2 +#define UDPLEN_INCREMENT_DEFAULT 2 -#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3 -#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 -#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3 +#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3 +#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 +#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3 -enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; +enum log_target +{ + LOG_TARGET_CONSOLE = 0, + LOG_TARGET_FILE, + LOG_TARGET_SYSLOG +}; struct params_s { @@ -41,8 +46,8 @@ struct params_s char debug_logfile[PATH_MAX]; bool debug; - uint16_t wsize,wssize; - uint8_t wscale,wsscale; + uint16_t wsize, wssize; + uint8_t wscale, wsscale; char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence unsigned int wssize_cutoff; #ifdef __linux__ @@ -50,12 +55,12 @@ struct params_s #elif defined(BSD) uint16_t port; // divert port #endif - char bind_fix4,bind_fix6; + char bind_fix4, bind_fix6; bool hostcase, hostnospace, domcase; char hostspell[4]; - enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2; - bool desync_retrans,desync_skip_nosni,desync_any_proto; - unsigned int desync_repeats,desync_split_pos,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp; + enum dpi_desync_mode desync_mode0, desync_mode, desync_mode2; + bool desync_retrans, desync_skip_nosni, desync_any_proto; + unsigned int desync_repeats, desync_split_pos, desync_seqovl, desync_ipfrag_pos_tcp, desync_ipfrag_pos_udp; enum httpreqpos desync_split_http_req; enum tlspos desync_split_tls; char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence @@ -65,13 +70,13 @@ struct params_s uint32_t desync_fooling_mode; uint32_t desync_fwmark; // unused in BSD uint32_t desync_badseq_increment, desync_badseq_ack_increment; - uint8_t fake_http[1460],fake_tls[1460],fake_unknown[1460],fake_syndata[1460],seqovl_pattern[1460]; - uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472]; - size_t fake_http_size,fake_tls_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size; + uint8_t fake_http[1460], fake_tls[1460], fake_unknown[1460], fake_syndata[1460], seqovl_pattern[1460]; + uint8_t fake_unknown_udp[1472], udplen_pattern[1472], fake_quic[1472], fake_wg[1472], fake_dht[1472]; + size_t fake_http_size, fake_tls_size, fake_quic_size, fake_wg_size, fake_dht_size, fake_unknown_size, fake_syndata_size, fake_unknown_udp_size; int udplen_increment; #ifdef __CYGWIN__ - struct str_list_head ssid_filter,nlm_filter; + struct str_list_head ssid_filter, nlm_filter; #else bool droproot; uid_t uid; diff --git a/nfq/pools.c b/nfq/pools.c index 785b04d..9639918 100644 --- a/nfq/pools.c +++ b/nfq/pools.c @@ -5,33 +5,33 @@ #include #define DESTROY_STR_POOL(etype, ppool) \ - etype *elem, *tmp; \ - HASH_ITER(hh, *ppool, elem, tmp) { \ - free(elem->str); \ - HASH_DEL(*ppool, elem); \ - free(elem); \ - } - -#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \ - etype *elem; \ - if (!(elem = (etype*)malloc(sizeof(etype)))) \ - return false; \ - if (!(elem->str = malloc(keystr_len + 1))) \ - { \ - free(elem); \ - return false; \ - } \ - memcpy(elem->str, keystr, keystr_len); \ - elem->str[keystr_len] = 0; \ - oom = false; \ - HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \ - if (oom) \ - { \ - free(elem->str); \ - free(elem); \ - return false; \ + etype *elem, *tmp; \ + HASH_ITER(hh, *ppool, elem, tmp) \ + { \ + free(elem->str); \ + HASH_DEL(*ppool, elem); \ + free(elem); \ } +#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \ + etype *elem; \ + if (!(elem = (etype *)malloc(sizeof(etype)))) \ + return false; \ + if (!(elem->str = malloc(keystr_len + 1))) \ + { \ + free(elem); \ + return false; \ + } \ + memcpy(elem->str, keystr, keystr_len); \ + elem->str[keystr_len] = 0; \ + oom = false; \ + HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \ + if (oom) \ + { \ + free(elem->str); \ + free(elem); \ + return false; \ + } #undef uthash_nonfatal_oom #define uthash_nonfatal_oom(elt) ut_oom_recover(elt) @@ -65,13 +65,8 @@ void StrPoolDestroy(strpool **pp) DESTROY_STR_POOL(strpool, pp) } - - -void HostFailPoolDestroy(hostfail_pool **pp) -{ - DESTROY_STR_POOL(hostfail_pool, pp) -} -hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time) +void HostFailPoolDestroy(hostfail_pool **pp){ + DESTROY_STR_POOL(hostfail_pool, pp)} hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time) { size_t slen = strlen(s); ADD_STR_POOL(hostfail_pool, pp, s, slen) @@ -79,7 +74,7 @@ hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time) elem->counter = 0; return elem; } -hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s) +hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s) { hostfail_pool *elem; HASH_FIND_STR(p, s, elem); @@ -104,7 +99,7 @@ void HostFailPoolPurge(hostfail_pool **pp) } } } -static time_t host_fail_purge_prev=0; +static time_t host_fail_purge_prev = 0; void HostFailPoolPurgeRateLimited(hostfail_pool **pp) { time_t now = time(NULL); @@ -120,14 +115,14 @@ void HostFailPoolDump(hostfail_pool *p) hostfail_pool *elem, *tmp; time_t now = time(NULL); HASH_ITER(hh, p, elem, tmp) - printf("host=%s counter=%d time_left=%lld\n",elem->str,elem->counter,(long long int)elem->expire-now); + printf("host=%s counter=%d time_left=%lld\n", elem->str, elem->counter, (long long int)elem->expire - now); } - bool strlist_add(struct str_list_head *head, const char *filename) { struct str_list *entry = malloc(sizeof(struct str_list)); - if (!entry) return false; + if (!entry) + return false; entry->str = strdup(filename); if (!entry->str) { @@ -139,7 +134,8 @@ bool strlist_add(struct str_list_head *head, const char *filename) } static void strlist_entry_destroy(struct str_list *entry) { - if (entry->str) free(entry->str); + if (entry->str) + free(entry->str); free(entry); } void strlist_destroy(struct str_list_head *head) diff --git a/nfq/pools.h b/nfq/pools.h index ab58968..b61245c 100644 --- a/nfq/pools.h +++ b/nfq/pools.h @@ -5,38 +5,41 @@ #include #include -//#define HASH_BLOOM 20 +// #define HASH_BLOOM 20 #define HASH_NONFATAL_OOM 1 #define HASH_FUNCTION HASH_BER #include "uthash.h" -typedef struct strpool { - char *str; /* key */ - UT_hash_handle hh; /* makes this structure hashable */ +typedef struct strpool +{ + char *str; /* key */ + UT_hash_handle hh; /* makes this structure hashable */ } strpool; void StrPoolDestroy(strpool **pp); -bool StrPoolAddStr(strpool **pp,const char *s); -bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen); -bool StrPoolCheckStr(strpool *p,const char *s); +bool StrPoolAddStr(strpool **pp, const char *s); +bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen); +bool StrPoolCheckStr(strpool *p, const char *s); -struct str_list { - char *str; - LIST_ENTRY(str_list) next; +struct str_list +{ + char *str; + LIST_ENTRY(str_list) + next; }; LIST_HEAD(str_list_head, str_list); - -typedef struct hostfail_pool { - char *str; /* key */ - int counter; /* value */ - time_t expire; /* when to expire record (unixtime) */ - UT_hash_handle hh; /* makes this structure hashable */ +typedef struct hostfail_pool +{ + char *str; /* key */ + int counter; /* value */ + time_t expire; /* when to expire record (unixtime) */ + UT_hash_handle hh; /* makes this structure hashable */ } hostfail_pool; void HostFailPoolDestroy(hostfail_pool **pp); -hostfail_pool *HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time); -hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s); +hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time); +hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s); void HostFailPoolDel(hostfail_pool **pp, hostfail_pool *elem); void HostFailPoolPurge(hostfail_pool **pp); void HostFailPoolPurgeRateLimited(hostfail_pool **pp); diff --git a/nfq/protocol.c b/nfq/protocol.c index 6a8f2aa..7b83a69 100644 --- a/nfq/protocol.c +++ b/nfq/protocol.c @@ -7,7 +7,7 @@ #include #include -const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL }; +const char *http_methods[] = {"GET /", "POST /", "HEAD /", "OPTIONS /", "PUT /", "DELETE /", "CONNECT /", "TRACE /", NULL}; const char *HttpMethod(const uint8_t *data, size_t len) { const char **method; @@ -22,24 +22,26 @@ const char *HttpMethod(const uint8_t *data, size_t len) } bool IsHttp(const uint8_t *data, size_t len) { - return !!HttpMethod(data,len); + return !!HttpMethod(data, len); } // pHost points to "Host: ..." -bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs) +bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs) { if (!*pHost) { *pHost = memmem(buf, bs, "\nHost:", 6); - if (*pHost) (*pHost)++; + if (*pHost) + (*pHost)++; } return !!*pHost; } -bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs) +bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs) { if (!*pHost) { *pHost = memmem(buf, bs, "\nHost:", 6); - if (*pHost) (*pHost)++; + if (*pHost) + (*pHost)++; } return !!*pHost; } @@ -47,32 +49,37 @@ bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs) bool IsHttpReply(const uint8_t *data, size_t len) { // HTTP/1.x 200\r\n - return len>14 && !memcmp(data,"HTTP/1.",7) && (data[7]=='0' || data[7]=='1') && data[8]==' ' && - data[9]>='0' && data[9]<='9' && - data[10]>='0' && data[10]<='9' && - data[11]>='0' && data[11]<='9'; + return len > 14 && !memcmp(data, "HTTP/1.", 7) && (data[7] == '0' || data[7] == '1') && data[8] == ' ' && + data[9] >= '0' && data[9] <= '9' && + data[10] >= '0' && data[10] <= '9' && + data[11] >= '0' && data[11] <= '9'; } int HttpReplyCode(const uint8_t *data, size_t len) { - return (data[9]-'0')*100 + (data[10]-'0')*10 + (data[11]-'0'); + return (data[9] - '0') * 100 + (data[10] - '0') * 10 + (data[11] - '0'); } bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf) { const uint8_t *p, *s, *e = data + len; - p = (uint8_t*)strncasestr((char*)data, header, len); - if (!p) return false; + p = (uint8_t *)strncasestr((char *)data, header, len); + if (!p) + return false; p += strlen(header); - while (p < e && (*p == ' ' || *p == '\t')) p++; + while (p < e && (*p == ' ' || *p == '\t')) + p++; s = p; - while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t')) s++; + while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t')) + s++; if (s > p) { size_t slen = s - p; if (buf && len_buf) { - if (slen >= len_buf) slen = len_buf - 1; - for (size_t i = 0; i < slen; i++) buf[i] = tolower(p[i]); + if (slen >= len_buf) + slen = len_buf - 1; + for (size_t i = 0; i < slen; i++) + buf[i] = tolower(p[i]); buf[slen] = 0; } return true; @@ -85,83 +92,97 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos } const char *HttpFind2ndLevelDomain(const char *host) { - const char *p=NULL; + const char *p = NULL; if (*host) { - for (p = host + strlen(host)-1; p>host && *p!='.'; p--); - if (*p=='.') for (p--; p>host && *p!='.'; p--); - if (*p=='.') p++; + for (p = host + strlen(host) - 1; p > host && *p != '.'; p--) + ; + if (*p == '.') + for (p--; p > host && *p != '.'; p--) + ; + if (*p == '.') + p++; } return p; } // DPI redirects are global redirects to another domain bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host) { - char loc[256],*redirect_host, *p; + char loc[256], *redirect_host, *p; int code; - - if (!host || !*host) return false; - - code = HttpReplyCode(data,len); - - if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false; + + if (!host || !*host) + return false; + + code = HttpReplyCode(data, len); + + if ((code != 302 && code != 307) || !HttpExtractHeader(data, len, "\nLocation:", loc, sizeof(loc))) + return false; // something like : https://censor.net/badpage.php?reason=denied&source=RKN - - if (!strncmp(loc,"http://",7)) - redirect_host=loc+7; - else if (!strncmp(loc,"https://",8)) - redirect_host=loc+8; + + if (!strncmp(loc, "http://", 7)) + redirect_host = loc + 7; + else if (!strncmp(loc, "https://", 8)) + redirect_host = loc + 8; else return false; - + // somethinkg like : censor.net/badpage.php?reason=denied&source=RKN - - for(p=redirect_host; *p && *p!='/' ; p++); - *p=0; - if (!*redirect_host) return false; + + for (p = redirect_host; *p && *p != '/'; p++) + ; + *p = 0; + if (!*redirect_host) + return false; // somethinkg like : censor.net - + // extract 2nd level domains const char *dhost = HttpFind2ndLevelDomain(host); const char *drhost = HttpFind2ndLevelDomain(redirect_host); - - return strcasecmp(dhost, drhost)!=0; + + return strcasecmp(dhost, drhost) != 0; } size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz) { const uint8_t *method, *host; int i; - - switch(tpos_type) - { - case httpreqpos_method: - // recognize some tpws pre-applied hacks - method=http; - if (sz<10) break; - if (*method=='\n' || *method=='\r') method++; - if (*method=='\n' || *method=='\r') method++; - for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++; - if (i<3 || *method!=' ') break; - return method-http-1; - case httpreqpos_host: - if (HttpFindHostConst(&host,http,sz) && (host-http+7)= 'A' && *method <= 'Z') + method++; + if (i < 3 || *method != ' ') + break; + return method - http - 1; + case httpreqpos_host: + if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz) + { + host += 5; + if (*host == ' ') + host++; + return host - http; + } + break; + case httpreqpos_pos: + break; + default: + return 0; + } + return hpos_pos < sz ? hpos_pos : 0; +} uint16_t TLSRecordDataLen(const uint8_t *data) { @@ -173,7 +194,7 @@ size_t TLSRecordLen(const uint8_t *data) } bool IsTLSRecordFull(const uint8_t *data, size_t len) { - return TLSRecordLen(data)<=len; + return TLSRecordLen(data) <= len; } bool IsTLSClientHello(const uint8_t *data, size_t len, bool bPartialIsOK) { @@ -186,14 +207,13 @@ size_t TLSHandshakeLen(const uint8_t *data) } bool IsTLSHandshakeClientHello(const uint8_t *data, size_t len) { - return len>=4 && data[0]==0x01 && TLSHandshakeLen(data)>0; + return len >= 4 && data[0] == 0x01 && TLSHandshakeLen(data) > 0; } bool IsTLSHandshakeFull(const uint8_t *data, size_t len) { - return (4+TLSHandshakeLen(data))<=len; + return (4 + TLSHandshakeLen(data)) <= len; } - // bPartialIsOK=true - accept partial packets not containing the whole TLS message bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK) { @@ -212,40 +232,51 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const size_t l; - if (!bPartialIsOK && !IsTLSHandshakeFull(data,len)) return false; + if (!bPartialIsOK && !IsTLSHandshakeFull(data, len)) + return false; l = 1 + 3 + 2 + 32; // SessionIDLength - if (len < (l + 1)) return false; + if (len < (l + 1)) + return false; l += data[l] + 1; // CipherSuitesLength - if (len < (l + 2)) return false; + if (len < (l + 2)) + return false; l += pntoh16(data + l) + 2; // CompressionMethodsLength - if (len < (l + 1)) return false; + if (len < (l + 1)) + return false; l += data[l] + 1; // ExtensionsLength - if (len < (l + 2)) return false; + if (len < (l + 2)) + return false; - data += l; len -= l; + data += l; + len -= l; l = pntoh16(data); - data += 2; len -= 2; - + data += 2; + len -= 2; + if (bPartialIsOK) { - if (len < l) l = len; + if (len < l) + l = len; } else { - if (len < l) return false; + if (len < l) + return false; } while (l >= 4) { uint16_t etype = pntoh16(data); size_t elen = pntoh16(data + 2); - data += 4; l -= 4; - if (l < elen) break; + data += 4; + l -= 4; + if (l < elen) + break; if (etype == type) { if (ext && len_ext) @@ -255,7 +286,8 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const } return true; } - data += elen; l -= elen; + data += elen; + l -= elen; } return false; @@ -267,9 +299,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t ** // u16 Version: TLS1.0 // u16 Length size_t reclen; - if (!IsTLSClientHello(data, len, bPartialIsOK)) return false; - reclen=TLSRecordLen(data); - if (reclen= len_host) slen = len_host - 1; - for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]); + if (slen >= len_host) + slen = len_host - 1; + for (size_t i = 0; i < slen; i++) + host[i] = tolower(ext[i]); host[slen] = 0; } return true; @@ -294,7 +333,8 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len const uint8_t *ext; size_t elen; - if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK)) return false; + if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK)) + return false; return TLSExtractHostFromExt(ext, elen, host, len_host); } bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK) @@ -302,48 +342,52 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos const uint8_t *ext; size_t elen; - if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false; + if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) + return false; return TLSExtractHostFromExt(ext, elen, host, len_host); } size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type) { size_t elen; const uint8_t *ext; - switch(tpos_type) + switch (tpos_type) { - case tlspos_sni: - case tlspos_sniext: - if (TLSFindExt(tls,sz,0,&ext,&elen,false)) - return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1; - // fall through - case tlspos_pos: - return tpos_pos> 6) { case 0: /* 0b00 => 1 byte length (6 bits Usable) */ - if (value) *value = *tvb & 0x3F; + if (value) + *value = *tvb & 0x3F; return 1; case 1: /* 0b01 => 2 bytes length (14 bits Usable) */ - if (value) *value = pntoh16(tvb) & 0x3FFF; + if (value) + *value = pntoh16(tvb) & 0x3FFF; return 2; case 2: /* 0b10 => 4 bytes length (30 bits Usable) */ - if (value) *value = pntoh32(tvb) & 0x3FFFFFFF; + if (value) + *value = pntoh32(tvb) & 0x3FFFFFFF; return 4; case 3: /* 0b11 => 8 bytes length (62 bits Usable) */ - if (value) *value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF; + if (value) + *value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF; return 8; } // impossible case - if (*value) *value = 0; + if (*value) + *value = 0; return 0; } static uint8_t tvb_get_size(uint8_t tvb) @@ -355,15 +399,21 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si { size_t offset = 1; uint64_t coff, clen; - if (len < 3 || *data != 6) return false; - if ((offset+tvb_get_size(data[offset])) >= len) return false; + if (len < 3 || *data != 6) + return false; + if ((offset + tvb_get_size(data[offset])) >= len) + return false; offset += tvb_get_varint(data + offset, &coff); // offset must be 0 if it's a full segment, not just a chunk - if (coff || (offset+tvb_get_size(data[offset])) >= len) return false; + if (coff || (offset + tvb_get_size(data[offset])) >= len) + return false; offset += tvb_get_varint(data + offset, &clen); - if ((offset + clen) > len || !IsTLSHandshakeClientHello(data+offset,clen)) return false; - if (hello_offset) *hello_offset = offset; - if (hello_len) *hello_len = (size_t)clen; + if ((offset + clen) > len || !IsTLSHandshakeClientHello(data + offset, clen)) + return false; + if (hello_offset) + *hello_offset = offset; + if (hello_len) + *hello_len = (size_t)clen; return true; } @@ -371,22 +421,26 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si uint8_t QUICDraftVersion(uint32_t version) { /* IETF Draft versions */ - if ((version >> 8) == 0xff0000) { + if ((version >> 8) == 0xff0000) + { return (uint8_t)version; } /* Facebook mvfst, based on draft -22. */ - if (version == 0xfaceb001) { + if (version == 0xfaceb001) + { return 22; } /* Facebook mvfst, based on draft -27. */ - if (version == 0xfaceb002 || version == 0xfaceb00e) { + if (version == 0xfaceb002 || version == 0xfaceb00e) + { return 27; } /* GQUIC Q050, T050 and T051: they are not really based on any drafts, * but we must return a sensible value */ if (version == 0x51303530 || version == 0x54303530 || - version == 0x54303531) { + version == 0x54303531) + { return 27; } /* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15 @@ -396,17 +450,20 @@ uint8_t QUICDraftVersion(uint32_t version) used to select a proper salt (which depends on the version itself), but we don't have a real version here! Let's hope that we need to handle only latest drafts... */ - if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) { + if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) + { return 29; } /* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the final draft version */ - if (version == 0x00000001) { + if (version == 0x00000001) + { return 34; } /* QUIC Version 2 */ /* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */ - if (version == 0x709A50C4) { + if (version == 0x709A50C4) + { return 100; } return 0; @@ -418,7 +475,7 @@ static bool is_quic_draft_max(uint32_t draft_version, uint8_t max_version) } static bool is_quic_v2(uint32_t version) { - return version == 0x6b3343cf; + return version == 0x6b3343cf; } static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len) @@ -426,9 +483,11 @@ static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, co uint8_t hkdflabel[64]; size_t label_size = strlen(label); - if (label_size > 255) return false; + if (label_size > 255) + return false; size_t hkdflabel_size = 2 + 1 + label_size + 1; - if (hkdflabel_size > sizeof(hkdflabel)) return false; + if (hkdflabel_size > sizeof(hkdflabel)) + return false; phton16(hkdflabel, out_len); hkdflabel[2] = (uint8_t)label_size; @@ -454,69 +513,89 @@ static bool quic_derive_initial_secret(const quic_cid_t *cid, uint8_t *client_in */ static const uint8_t handshake_salt_draft_22[20] = { 0x7f, 0xbc, 0xdb, 0x0e, 0x7c, 0x66, 0xbb, 0xe9, 0x19, 0x3a, - 0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a - }; + 0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a}; static const uint8_t handshake_salt_draft_23[20] = { - 0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, - 0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02, + 0xc3, + 0xee, + 0xf7, + 0x12, + 0xc7, + 0x2e, + 0xbb, + 0x5a, + 0x11, + 0xa7, + 0xd2, + 0x43, + 0x2b, + 0xb4, + 0x63, + 0x65, + 0xbe, + 0xf9, + 0xf5, + 0x02, }; static const uint8_t handshake_salt_draft_29[20] = { 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, - 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99 - }; + 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}; static const uint8_t handshake_salt_v1[20] = { 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, - 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a - }; + 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}; static const uint8_t hanshake_salt_draft_q50[20] = { 0x50, 0x45, 0x74, 0xEF, 0xD0, 0x66, 0xFE, 0x2F, 0x9D, 0x94, - 0x5C, 0xFC, 0xDB, 0xD3, 0xA7, 0xF0, 0xD3, 0xB5, 0x6B, 0x45 - }; + 0x5C, 0xFC, 0xDB, 0xD3, 0xA7, 0xF0, 0xD3, 0xB5, 0x6B, 0x45}; static const uint8_t hanshake_salt_draft_t50[20] = { 0x7f, 0xf5, 0x79, 0xe5, 0xac, 0xd0, 0x72, 0x91, 0x55, 0x80, - 0x30, 0x4c, 0x43, 0xa2, 0x36, 0x7c, 0x60, 0x48, 0x83, 0x10 - }; + 0x30, 0x4c, 0x43, 0xa2, 0x36, 0x7c, 0x60, 0x48, 0x83, 0x10}; static const uint8_t hanshake_salt_draft_t51[20] = { 0x7a, 0x4e, 0xde, 0xf4, 0xe7, 0xcc, 0xee, 0x5f, 0xa4, 0x50, - 0x6c, 0x19, 0x12, 0x4f, 0xc8, 0xcc, 0xda, 0x6e, 0x03, 0x3d - }; + 0x6c, 0x19, 0x12, 0x4f, 0xc8, 0xcc, 0xda, 0x6e, 0x03, 0x3d}; static const uint8_t handshake_salt_v2[20] = { 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, - 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9 - }; + 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9}; int err; const uint8_t *salt; uint8_t secret[USHAMaxHashSize]; uint8_t draft_version = QUICDraftVersion(version); - if (version == 0x51303530) { + if (version == 0x51303530) + { salt = hanshake_salt_draft_q50; } - else if (version == 0x54303530) { + else if (version == 0x54303530) + { salt = hanshake_salt_draft_t50; } - else if (version == 0x54303531) { + else if (version == 0x54303531) + { salt = hanshake_salt_draft_t51; } - else if (is_quic_draft_max(draft_version, 22)) { + else if (is_quic_draft_max(draft_version, 22)) + { salt = handshake_salt_draft_22; } - else if (is_quic_draft_max(draft_version, 28)) { + else if (is_quic_draft_max(draft_version, 28)) + { salt = handshake_salt_draft_23; } - else if (is_quic_draft_max(draft_version, 32)) { + else if (is_quic_draft_max(draft_version, 32)) + { salt = handshake_salt_draft_29; } - else if (is_quic_draft_max(draft_version, 34)) { + else if (is_quic_draft_max(draft_version, 34)) + { salt = handshake_salt_v1; } - else { + else + { salt = handshake_salt_v2; } err = hkdfExtract(SHA256, salt, 20, cid->cid, cid->len, secret); - if (err) return false; + if (err) + return false; if (client_initial_secret && !quic_hkdf_expand_label(secret, SHA256HashSize, "tls13 client in", client_initial_secret, SHA256HashSize)) return false; @@ -525,16 +604,17 @@ static bool quic_derive_initial_secret(const quic_cid_t *cid, uint8_t *client_in } bool QUICIsLongHeader(const uint8_t *data, size_t len) { - return len>=9 && !!(*data & 0x80); + return len >= 9 && !!(*data & 0x80); } uint32_t QUICExtractVersion(const uint8_t *data, size_t len) { // long header, fixed bit, type=initial - return QUICIsLongHeader(data, len) ? ntohl(*(uint32_t*)(data + 1)) : 0; + return QUICIsLongHeader(data, len) ? ntohl(*(uint32_t *)(data + 1)) : 0; } bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid) { - if (!QUICIsLongHeader(data,len) || !data[5] || data[5] > QUIC_MAX_CID_LENGTH || (6+data[5])>len) return false; + if (!QUICIsLongHeader(data, len) || !data[5] || data[5] > QUIC_MAX_CID_LENGTH || (6 + data[5]) > len) + return false; cid->len = data[5]; memcpy(&cid->cid, data + 6, data[5]); return true; @@ -542,13 +622,16 @@ bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid) bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len) { uint32_t ver = QUICExtractVersion(data, data_len); - if (!ver) return false; + if (!ver) + return false; quic_cid_t dcid; - if (!QUICExtractDCID(data, data_len, &dcid)) return false; + if (!QUICExtractDCID(data, data_len, &dcid)) + return false; uint8_t client_initial_secret[SHA256HashSize]; - if (!quic_derive_initial_secret(&dcid, client_initial_secret, ver)) return false; + if (!quic_derive_initial_secret(&dcid, client_initial_secret, ver)) + return false; uint8_t aeskey[16], aesiv[12], aeshp[16]; bool v1_label = !is_quic_v2(ver); @@ -559,23 +642,28 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si return false; } - uint64_t payload_len,token_len; + uint64_t payload_len, token_len; size_t pn_offset; pn_offset = 1 + 4 + 1 + data[5]; - if (pn_offset >= data_len) return false; + if (pn_offset >= data_len) + return false; pn_offset += 1 + data[pn_offset]; - if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false; + if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) + return false; pn_offset += tvb_get_varint(data + pn_offset, &token_len); pn_offset += token_len; - if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false; + if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) + return false; pn_offset += tvb_get_varint(data + pn_offset, &payload_len); - if (payload_len<20 || (pn_offset + payload_len)>data_len) return false; + if (payload_len < 20 || (pn_offset + payload_len) > data_len) + return false; aes_init_keygen_tables(); uint8_t sample_enc[16]; aes_context ctx; - if (aes_setkey(&ctx, 1, aeshp, sizeof(aeshp)) || aes_cipher(&ctx, data + pn_offset + 4, sample_enc)) return false; + if (aes_setkey(&ctx, 1, aeshp, sizeof(aeshp)) || aes_cipher(&ctx, data + pn_offset + 4, sample_enc)) + return false; uint8_t mask[5]; memcpy(mask, sample_enc, sizeof(mask)); @@ -586,21 +674,25 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si uint8_t pkn_bytes[4]; memcpy(pkn_bytes, data + pn_offset, pkn_len); uint32_t pkn = 0; - for (uint8_t i = 0; i < pkn_len; i++) pkn |= (uint32_t)(pkn_bytes[i] ^ mask[1 + i]) << (8 * (pkn_len - 1 - i)); + for (uint8_t i = 0; i < pkn_len; i++) + pkn |= (uint32_t)(pkn_bytes[i] ^ mask[1 + i]) << (8 * (pkn_len - 1 - i)); - phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn); + phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn); size_t cryptlen = payload_len - pkn_len - 16; - if (cryptlen > *clean_len) return false; + if (cryptlen > *clean_len) + return false; *clean_len = cryptlen; const uint8_t *decrypt_begin = data + pn_offset + pkn_len; - uint8_t atag[16],header[256]; + uint8_t atag[16], header[256]; size_t header_len = pn_offset + pkn_len; - if (header_len > sizeof(header)) return false; // not likely header will be so large + if (header_len > sizeof(header)) + return false; // not likely header will be so large memcpy(header, data, header_len); header[0] = packet0; - for(uint8_t i = 0; i < pkn_len; i++) header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i)); + for (uint8_t i = 0; i < pkn_len; i++) + header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i)); if (aes_gcm_crypt(AES_DECRYPT, clean, decrypt_begin, cryptlen, aeskey, sizeof(aeskey), aesiv, sizeof(aesiv), header, header_len, atag, sizeof(atag))) return false; @@ -609,48 +701,56 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16); } -bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len) +bool QUICDefragCrypto(const uint8_t *clean, size_t clean_len, uint8_t *defrag, size_t *defrag_len) { // Crypto frame can be split into multiple chunks // chromium randomly splits it and pads with zero/one bytes to force support the standard // mozilla does not split - if (*defrag_len<10) return false; - uint8_t *defrag_data = defrag+10; - size_t defrag_data_len = *defrag_len-10; + if (*defrag_len < 10) + return false; + uint8_t *defrag_data = defrag + 10; + size_t defrag_data_len = *defrag_len - 10; uint8_t ft; - uint64_t offset,sz,szmax=0,zeropos=0,pos=0; - bool found=false; + uint64_t offset, sz, szmax = 0, zeropos = 0, pos = 0; + bool found = false; - while(pos1) // 00 - padding, 01 - ping + if (ft > 1) // 00 - padding, 01 - ping { - if (ft!=6) return false; // dont want to know all possible frame type formats + if (ft != 6) + return false; // don't want to know all possible frame type formats - if (pos>=clean_len) return false; + if (pos >= clean_len) + return false; - if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false; - pos += tvb_get_varint(clean+pos, &offset); + if ((pos + tvb_get_size(clean[pos]) >= clean_len)) + return false; + pos += tvb_get_varint(clean + pos, &offset); - if ((pos+tvb_get_size(clean[pos])>clean_len)) return false; - pos += tvb_get_varint(clean+pos, &sz); - if ((pos+sz)>clean_len) return false; + if ((pos + tvb_get_size(clean[pos]) > clean_len)) + return false; + pos += tvb_get_varint(clean + pos, &sz); + if ((pos + sz) > clean_len) + return false; - if ((offset+sz)>defrag_data_len) return false; + if ((offset + sz) > defrag_data_len) + return false; if (zeropos < offset) // make sure no uninitialized gaps exist in case of not full fragment coverage - memset(defrag_data+zeropos,0,offset-zeropos); - if ((offset+sz) > zeropos) - zeropos=offset+sz; - memcpy(defrag_data+offset,clean+pos,sz); - if ((offset+sz) > szmax) szmax = offset+sz; + memset(defrag_data + zeropos, 0, offset - zeropos); + if ((offset + sz) > zeropos) + zeropos = offset + sz; + memcpy(defrag_data + offset, clean + pos, sz); + if ((offset + sz) > szmax) + szmax = offset + sz; - found=true; - pos+=sz; + found = true; + pos += sz; } } if (found) @@ -659,31 +759,38 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz defrag[1] = 0; // offset // 2..9 - length 64 bit // +10 - data start - phton64(defrag+2,szmax); + phton64(defrag + 2, szmax); defrag[2] |= 0xC0; // 64 bit value - *defrag_len = (size_t)(szmax+10); + *defrag_len = (size_t)(szmax + 10); } return found; } bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello) { - if (bIsCryptoHello) *bIsCryptoHello=false; - if (bDecryptOK) *bDecryptOK=false; + if (bIsCryptoHello) + *bIsCryptoHello = false; + if (bDecryptOK) + *bDecryptOK = false; uint8_t clean[1500]; size_t clean_len = sizeof(clean); - if (!QUICDecryptInitial(data,data_len,clean,&clean_len)) return false; + if (!QUICDecryptInitial(data, data_len, clean, &clean_len)) + return false; - if (bDecryptOK) *bDecryptOK=true; + if (bDecryptOK) + *bDecryptOK = true; uint8_t defrag[1500]; size_t defrag_len = sizeof(defrag); - if (!QUICDefragCrypto(clean,clean_len,defrag,&defrag_len)) return false; + if (!QUICDefragCrypto(clean, clean_len, defrag, &defrag_len)) + return false; size_t hello_offset, hello_len; - if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len)) return false; - if (bIsCryptoHello) *bIsCryptoHello=true; + if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len)) + return false; + if (bIsCryptoHello) + *bIsCryptoHello = true; return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, true); } @@ -692,47 +799,53 @@ bool IsQUICInitial(const uint8_t *data, size_t len) { // too small packets are not likely to be initials with client hello // long header, fixed bit - if (len < 256 || (data[0] & 0xC0)!=0xC0) return false; + if (len < 256 || (data[0] & 0xC0) != 0xC0) + return false; - uint32_t ver = QUICExtractVersion(data,len); - if (QUICDraftVersion(ver) < 11) return false; + uint32_t ver = QUICExtractVersion(data, len); + if (QUICDraftVersion(ver) < 11) + return false; - // quic v1 : initial packets are 00b - // quic v2 : initial packets are 01b - if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00)) return false; + // QUIC v1 : initial packets are 00b + // QUIC v2 : initial packets are 01b + if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00)) + return false; - uint64_t offset=5, sz; + uint64_t offset = 5, sz; // DCID. must be present - if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH) return false; + if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH) + return false; offset += 1 + data[offset]; // SCID - if (data[offset] > QUIC_MAX_CID_LENGTH) return false; + if (data[offset] > QUIC_MAX_CID_LENGTH) + return false; offset += 1 + data[offset]; // token length offset += tvb_get_varint(data + offset, &sz); offset += sz; - if (offset >= len) return false; + if (offset >= len) + return false; // payload length - if ((offset + tvb_get_size(data[offset])) > len) return false; + if ((offset + tvb_get_size(data[offset])) > len) + return false; tvb_get_varint(data + offset, &sz); offset += sz; - if (offset > len) return false; + if (offset > len) + return false; - // client hello cannot be too small. likely ACK - return sz>=96; + // ClientHello cannot be too small. likely ACK + return sz >= 96; } - - bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len) { - return len==148 && data[0]==1 && data[1]==0 && data[2]==0 && data[3]==0; + return len == 148 && data[0] == 1 && data[1] == 0 && data[2] == 0 && data[3] == 0; } bool IsDhtD1(const uint8_t *data, size_t len) { - return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e'; + return len >= 7 && data[0] == 'd' && data[1] == '1' && data[len - 1] == 'e'; } diff --git a/nfq/protocol.h b/nfq/protocol.h index 2264f81..72130ec 100644 --- a/nfq/protocol.h +++ b/nfq/protocol.h @@ -10,8 +10,8 @@ extern const char *http_methods[9]; const char *HttpMethod(const uint8_t *data, size_t len); bool IsHttp(const uint8_t *data, size_t len); -bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs); -bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs); +bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs); +bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs); // header must be passed like this : "\nHost:" bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf); bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host); @@ -21,7 +21,13 @@ const char *HttpFind2ndLevelDomain(const char *host); int HttpReplyCode(const uint8_t *data, size_t len); // must be pre-checked by IsHttpReply bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host); -enum httpreqpos { httpreqpos_none = 0, httpreqpos_method, httpreqpos_host, httpreqpos_pos }; +enum httpreqpos +{ + httpreqpos_none = 0, + httpreqpos_method, + httpreqpos_host, + httpreqpos_pos +}; size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz); uint16_t TLSRecordDataLen(const uint8_t *data); @@ -35,16 +41,23 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t ** bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK); bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK); bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK); -enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_pos }; +enum tlspos +{ + tlspos_none = 0, + tlspos_sni, + tlspos_sniext, + tlspos_pos +}; size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type); bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len); bool IsDhtD1(const uint8_t *data, size_t len); -#define QUIC_MAX_CID_LENGTH 20 -typedef struct quic_cid { - uint8_t len; - uint8_t cid[QUIC_MAX_CID_LENGTH]; +#define QUIC_MAX_CID_LENGTH 20 +typedef struct quic_cid +{ + uint8_t len; + uint8_t cid[QUIC_MAX_CID_LENGTH]; } quic_cid_t; bool IsQUICInitial(const uint8_t *data, size_t len); @@ -55,5 +68,5 @@ uint8_t QUICDraftVersion(uint32_t version); bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid); bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len); -bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len); +bool QUICDefragCrypto(const uint8_t *clean, size_t clean_len, uint8_t *defrag, size_t *defrag_len); bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello); diff --git a/nfq/sec.c b/nfq/sec.c index b6f8e66..c4e3a6b 100644 --- a/nfq/sec.c +++ b/nfq/sec.c @@ -25,128 +25,127 @@ // block most of the undesired syscalls to harden against code execution static long blocked_syscalls[] = { #ifdef SYS_execv -SYS_execv, + SYS_execv, #endif -SYS_execve, + SYS_execve, #ifdef SYS_execveat -SYS_execveat, + SYS_execveat, #endif #ifdef SYS_exec_with_loader -SYS_exec_with_loader, + SYS_exec_with_loader, #endif #ifdef SYS_clone -SYS_clone, + SYS_clone, #endif #ifdef SYS_clone2 -SYS_clone2, + SYS_clone2, #endif #ifdef SYS_clone3 -SYS_clone3, + SYS_clone3, #endif #ifdef SYS_osf_execve -SYS_osf_execve, + SYS_osf_execve, #endif #ifdef SYS_fork -SYS_fork, + SYS_fork, #endif #ifdef SYS_vfork -SYS_vfork, + SYS_vfork, #endif #ifdef SYS_uselib -SYS_uselib, + SYS_uselib, #endif #ifdef SYS_unlink -SYS_unlink, + SYS_unlink, #endif -SYS_unlinkat, + SYS_unlinkat, #ifdef SYS_chmod -SYS_chmod, + SYS_chmod, #endif -SYS_fchmod,SYS_fchmodat, + SYS_fchmod, SYS_fchmodat, #ifdef SYS_chown -SYS_chown, + SYS_chown, #endif #ifdef SYS_chown32 -SYS_chown32, + SYS_chown32, #endif -SYS_fchown, + SYS_fchown, #ifdef SYS_fchown32 -SYS_fchown32, + SYS_fchown32, #endif #ifdef SYS_lchown -SYS_lchown, + SYS_lchown, #endif #ifdef SYS_lchown32 -SYS_lchown32, + SYS_lchown32, #endif -SYS_fchownat, + SYS_fchownat, #ifdef SYS_symlink -SYS_symlink, + SYS_symlink, #endif -SYS_symlinkat, + SYS_symlinkat, #ifdef SYS_link -SYS_link, + SYS_link, #endif -SYS_linkat, + SYS_linkat, #ifdef SYS_pkey_mprotect -SYS_pkey_mprotect, + SYS_pkey_mprotect, #endif -SYS_mprotect, -SYS_truncate, + SYS_mprotect, + SYS_truncate, #ifdef SYS_truncate64 -SYS_truncate64, + SYS_truncate64, #endif -SYS_ftruncate, + SYS_ftruncate, #ifdef SYS_ftruncate64 -SYS_ftruncate64, + SYS_ftruncate64, #endif #ifdef SYS_mknod -SYS_mknod, + SYS_mknod, #endif -SYS_mknodat, + SYS_mknodat, #ifdef SYS_mkdir -SYS_mkdir, + SYS_mkdir, #endif -SYS_mkdirat, + SYS_mkdirat, #ifdef SYS_rmdir -SYS_rmdir, + SYS_rmdir, #endif #ifdef SYS_rename -SYS_rename, + SYS_rename, #endif #ifdef SYS_renameat2 -SYS_renameat2, + SYS_renameat2, #endif #ifdef SYS_renameat -SYS_renameat, + SYS_renameat, #endif #ifdef SYS_readdir -SYS_readdir, + SYS_readdir, #endif #ifdef SYS_getdents -SYS_getdents, + SYS_getdents, #endif #ifdef SYS_getdents64 -SYS_getdents64, + SYS_getdents64, #endif #ifdef SYS_process_vm_readv -SYS_process_vm_readv, + SYS_process_vm_readv, #endif #ifdef SYS_process_vm_writev -SYS_process_vm_writev, + SYS_process_vm_writev, #endif #ifdef SYS_process_madvise -SYS_process_madvise, + SYS_process_madvise, #endif #ifdef SYS_tkill -SYS_tkill, + SYS_tkill, #endif #ifdef SYS_tgkill -SYS_tgkill, + SYS_tgkill, #endif -SYS_kill, SYS_ptrace -}; -#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls)) + SYS_kill, SYS_ptrace}; +#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls)) static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k) { @@ -159,13 +158,13 @@ static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, static bool set_seccomp(void) { #ifdef __X32_SYSCALL_BIT - #define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT) +#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT) #else - #define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT) +#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT) #endif struct sock_filter sockf[SECCOMP_PROG_SIZE]; - struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE, .filter = sockf }; - int i,idx=0; + struct sock_fprog prog = {.len = SECCOMP_PROG_SIZE, .filter = sockf}; + int i, idx = 0; set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr); #ifdef __X32_SYSCALL_BIT @@ -178,19 +177,19 @@ static bool set_seccomp(void) set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); #endif -/* - // ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr - set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call - set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd - set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad - set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr -*/ - for(i=0 ; i= 0; } @@ -201,42 +200,41 @@ bool sec_harden(void) DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)"); return false; } -#if ARCH_NR!=0 +#if ARCH_NR != 0 if (!set_seccomp()) { DLOG_PERROR("seccomp"); - if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n"); + if (errno == EINVAL) + DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n"); return false; } #endif return true; } - - - bool checkpcap(uint64_t caps) { - if (!caps) return true; // no special caps reqd + if (!caps) + return true; // no special caps reqd struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()}; struct __user_cap_data_struct cd[2]; uint32_t c0 = (uint32_t)caps; - uint32_t c1 = (uint32_t)(caps>>32); + uint32_t c1 = (uint32_t)(caps >> 32); - return !capget(&ch,cd) && (cd[0].effective & c0)==c0 && (cd[1].effective & c1)==c1; + return !capget(&ch, cd) && (cd[0].effective & c0) == c0 && (cd[1].effective & c1) == c1; } bool setpcap(uint64_t caps) { struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()}; struct __user_cap_data_struct cd[2]; - + cd[0].effective = cd[0].permitted = (uint32_t)caps; cd[0].inheritable = 0; - cd[1].effective = cd[1].permitted = (uint32_t)(caps>>32); + cd[1].effective = cd[1].permitted = (uint32_t)(caps >> 32); cd[1].inheritable = 0; - return !capset(&ch,cd); + return !capset(&ch, cd); } int getmaxcap(void) { @@ -248,18 +246,17 @@ int getmaxcap(void) fclose(F); } return maxcap; - } bool dropcaps(void) { - uint64_t caps = (1< /* memcmp, memset, strlen */ -#include /* ptrdiff_t */ -#include /* exit */ +#include /* memcmp, memset, strlen */ +#include /* ptrdiff_t */ +#include /* exit */ #if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT /* This codepath is provided for backward compatibility, but I plan to remove it. */ @@ -37,7 +37,7 @@ typedef unsigned int uint32_t; typedef unsigned char uint8_t; #elif defined(HASH_NO_STDINT) && HASH_NO_STDINT #else -#include /* uint8_t, uint32_t */ +#include /* uint8_t, uint32_t */ #endif /* These macros use decltype or the earlier __typeof GNU extension. @@ -45,59 +45,61 @@ typedef unsigned char uint8_t; when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #if !defined(DECLTYPE) && !defined(NO_DECLTYPE) -#if defined(_MSC_VER) /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) -#else /* VS2008 or older (or VS2010 in C mode) */ +#else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #endif #elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE -#else /* GNU, Sun and other compilers */ +#else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #endif #ifdef NO_DECLTYPE #define DECLTYPE(x) -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - char **_da_dst = (char**)(&(dst)); \ - *_da_dst = (char*)(src); \ -} while (0) +#define DECLTYPE_ASSIGN(dst, src) \ + do \ + { \ + char **_da_dst = (char **)(&(dst)); \ + *_da_dst = (char *)(src); \ + } while (0) #else -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - (dst) = DECLTYPE(dst)(src); \ -} while (0) +#define DECLTYPE_ASSIGN(dst, src) \ + do \ + { \ + (dst) = DECLTYPE(dst)(src); \ + } while (0) #endif #ifndef uthash_malloc -#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #endif #ifndef uthash_free -#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#define uthash_free(ptr, sz) free(ptr) /* free fcn */ #endif #ifndef uthash_bzero -#define uthash_bzero(a,n) memset(a,'\0',n) +#define uthash_bzero(a, n) memset(a, '\0', n) #endif #ifndef uthash_strlen #define uthash_strlen(s) strlen(s) #endif #ifndef HASH_FUNCTION -#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv) +#define HASH_FUNCTION(keyptr, keylen, hashv) HASH_JEN(keyptr, keylen, hashv) #endif #ifndef HASH_KEYCMP -#define HASH_KEYCMP(a,b,n) memcmp(a,b,n) +#define HASH_KEYCMP(a, b, n) memcmp(a, b, n) #endif #ifndef uthash_noexpand_fyi -#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #endif #ifndef uthash_expand_fyi -#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ #endif #ifndef HASH_NONFATAL_OOM @@ -108,17 +110,24 @@ do { /* malloc failures can be recovered from */ #ifndef uthash_nonfatal_oom -#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ +#define uthash_nonfatal_oom(obj) \ + do \ + { \ + } while (0) /* non-fatal OOM error */ #endif -#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) +#define HASH_RECORD_OOM(oomed) \ + do \ + { \ + (oomed) = 1; \ + } while (0) #define IF_HASH_NONFATAL_OOM(x) x #else /* malloc failures result in lost memory, hash tables are unusable */ #ifndef uthash_fatal -#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ +#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ #endif #define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") @@ -132,306 +141,361 @@ do { #define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhp */ -#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +#define ELMT_FROM_HH(tbl, hhp) ((void *)(((char *)(hhp)) - ((tbl)->hho))) /* calculate the hash handle from element address elp */ -#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho))) +#define HH_FROM_ELMT(tbl, elp) ((UT_hash_handle *)(void *)(((char *)(elp)) + ((tbl)->hho))) -#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ -do { \ - struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ - unsigned _hd_bkt; \ - HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - (head)->hh.tbl->buckets[_hd_bkt].count++; \ - _hd_hh_item->hh_next = NULL; \ - _hd_hh_item->hh_prev = NULL; \ -} while (0) +#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ + do \ + { \ + struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ + unsigned _hd_bkt; \ + HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + (head)->hh.tbl->buckets[_hd_bkt].count++; \ + _hd_hh_item->hh_next = NULL; \ + _hd_hh_item->hh_prev = NULL; \ + } while (0) -#define HASH_VALUE(keyptr,keylen,hashv) \ -do { \ - HASH_FUNCTION(keyptr, keylen, hashv); \ -} while (0) +#define HASH_VALUE(keyptr, keylen, hashv) \ + do \ + { \ + HASH_FUNCTION(keyptr, keylen, hashv); \ + } while (0) -#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ -do { \ - (out) = NULL; \ - if (head) { \ - unsigned _hf_bkt; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ - if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ - HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ - } \ - } \ -} while (0) +#define HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, hashval, out) \ + do \ + { \ + (out) = NULL; \ + if (head) \ + { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) \ + { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[_hf_bkt], keyptr, keylen, hashval, out); \ + } \ + } \ + } while (0) -#define HASH_FIND(hh,head,keyptr,keylen,out) \ -do { \ - (out) = NULL; \ - if (head) { \ - unsigned _hf_hashv; \ - HASH_VALUE(keyptr, keylen, _hf_hashv); \ - HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ - } \ -} while (0) +#define HASH_FIND(hh, head, keyptr, keylen, out) \ + do \ + { \ + (out) = NULL; \ + if (head) \ + { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ + } \ + } while (0) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) -#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) -#define HASH_BLOOM_MAKE(tbl,oomed) \ -do { \ - (tbl)->bloom_nbits = HASH_BLOOM; \ - (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ - if (!(tbl)->bloom_bv) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ - (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ - } \ -} while (0) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN / 8UL) + (((HASH_BLOOM_BITLEN % 8UL) != 0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl, oomed) \ + do \ + { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t *)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) \ + { \ + HASH_RECORD_OOM(oomed); \ + } \ + else \ + { \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ + } \ + } while (0) -#define HASH_BLOOM_FREE(tbl) \ -do { \ - uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ -} while (0) +#define HASH_BLOOM_FREE(tbl) \ + do \ + { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + } while (0) -#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) -#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) +#define HASH_BLOOM_BITSET(bv, idx) (bv[(idx) / 8U] |= (1U << ((idx) % 8U))) +#define HASH_BLOOM_BITTEST(bv, idx) (bv[(idx) / 8U] & (1U << ((idx) % 8U))) -#define HASH_BLOOM_ADD(tbl,hashv) \ +#define HASH_BLOOM_ADD(tbl, hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) -#define HASH_BLOOM_TEST(tbl,hashv) \ +#define HASH_BLOOM_TEST(tbl, hashv) \ HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) #else -#define HASH_BLOOM_MAKE(tbl,oomed) +#define HASH_BLOOM_MAKE(tbl, oomed) #define HASH_BLOOM_FREE(tbl) -#define HASH_BLOOM_ADD(tbl,hashv) -#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_ADD(tbl, hashv) +#define HASH_BLOOM_TEST(tbl, hashv) (1) #define HASH_BLOOM_BYTELEN 0U #endif -#define HASH_MAKE_TABLE(hh,head,oomed) \ -do { \ - (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ - if (!(head)->hh.tbl) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head)->hh.tbl->tail = &((head)->hh); \ - (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ - (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ - (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ - (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ - HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ - (head)->hh.tbl->signature = HASH_SIGNATURE; \ - if (!(head)->hh.tbl->buckets) { \ - HASH_RECORD_OOM(oomed); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - } else { \ - uthash_bzero((head)->hh.tbl->buckets, \ - HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ - HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (oomed) { \ - uthash_free((head)->hh.tbl->buckets, \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - } \ - ) \ - } \ - } \ -} while (0) +#define HASH_MAKE_TABLE(hh, head, oomed) \ + do \ + { \ + (head)->hh.tbl = (UT_hash_table *)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) \ + { \ + HASH_RECORD_OOM(oomed); \ + } \ + else \ + { \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char *)(&(head)->hh) - (char *)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket *)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ + if (!(head)->hh.tbl->buckets) \ + { \ + HASH_RECORD_OOM(oomed); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } \ + else \ + { \ + uthash_bzero((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + uthash_free((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + }) \ + } \ + } \ + } while (0) -#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ -do { \ - (replaced) = NULL; \ - HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ - if (replaced) { \ - HASH_DELETE(hh, head, replaced); \ - } \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ -} while (0) +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, hashval, add, replaced, cmpfcn) \ + do \ + { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) \ + { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ + } while (0) -#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ -do { \ - (replaced) = NULL; \ - HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ - if (replaced) { \ - HASH_DELETE(hh, head, replaced); \ - } \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ -} while (0) +#define HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, hashval, add, replaced) \ + do \ + { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) \ + { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ + } while (0) -#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ -do { \ - unsigned _hr_hashv; \ - HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ - HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ -} while (0) +#define HASH_REPLACE(hh, head, fieldname, keylen_in, add, replaced) \ + do \ + { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ + } while (0) -#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ -do { \ - unsigned _hr_hashv; \ - HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ - HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ -} while (0) +#define HASH_REPLACE_INORDER(hh, head, fieldname, keylen_in, add, replaced, cmpfcn) \ + do \ + { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ + } while (0) -#define HASH_APPEND_LIST(hh, head, add) \ -do { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ - (head)->hh.tbl->tail->next = (add); \ - (head)->hh.tbl->tail = &((add)->hh); \ -} while (0) +#define HASH_APPEND_LIST(hh, head, add) \ + do \ + { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } while (0) -#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ -do { \ - do { \ - if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ - break; \ - } \ - } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ -} while (0) +#define HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn) \ + do \ + { \ + do \ + { \ + if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) \ + { \ + break; \ + } \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ + } while (0) #ifdef NO_DECLTYPE #undef HASH_AKBI_INNER_LOOP -#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ -do { \ - char *_hs_saved_head = (char*)(head); \ - do { \ - DECLTYPE_ASSIGN(head, _hs_iter); \ - if (cmpfcn(head, add) > 0) { \ - DECLTYPE_ASSIGN(head, _hs_saved_head); \ - break; \ - } \ - DECLTYPE_ASSIGN(head, _hs_saved_head); \ - } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ -} while (0) +#define HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn) \ + do \ + { \ + char *_hs_saved_head = (char *)(head); \ + do \ + { \ + DECLTYPE_ASSIGN(head, _hs_iter); \ + if (cmpfcn(head, add) > 0) \ + { \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + break; \ + } \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ + } while (0) #endif #if HASH_NONFATAL_OOM -#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ -do { \ - if (!(oomed)) { \ - unsigned _ha_bkt; \ - (head)->hh.tbl->num_items++; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ - if (oomed) { \ - HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ - HASH_DELETE_HH(hh, head, &(add)->hh); \ - (add)->hh.tbl = NULL; \ - uthash_nonfatal_oom(add); \ - } else { \ - HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ - HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ - } \ - } else { \ - (add)->hh.tbl = NULL; \ - uthash_nonfatal_oom(add); \ - } \ -} while (0) +#define HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, oomed) \ + do \ + { \ + if (!(oomed)) \ + { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + if (oomed) \ + { \ + HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ + HASH_DELETE_HH(hh, head, &(add)->hh); \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ + else \ + { \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } \ + } \ + else \ + { \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ + } while (0) #else -#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ -do { \ - unsigned _ha_bkt; \ - (head)->hh.tbl->num_items++; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ - HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ - HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ -} while (0) +#define HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, oomed) \ + do \ + { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } while (0) #endif - -#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ -do { \ - IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ - (add)->hh.hashv = (hashval); \ - (add)->hh.key = (char*) (keyptr); \ - (add)->hh.keylen = (unsigned) (keylen_in); \ - if (!(head)) { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh, add, _ha_oomed); \ - IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, hashval, add, cmpfcn) \ + do \ + { \ + IF_HASH_NONFATAL_OOM(int _ha_oomed = 0;) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char *)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) \ + { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM(if (!_ha_oomed) { ) \ (head) = (add); \ - IF_HASH_NONFATAL_OOM( } ) \ - } else { \ - void *_hs_iter = (head); \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ - if (_hs_iter) { \ - (add)->hh.next = _hs_iter; \ - if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ - HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ - } else { \ - (head) = (add); \ - } \ - HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ - } else { \ - HASH_APPEND_LIST(hh, head, add); \ - } \ - } \ - HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ - HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ -} while (0) + IF_HASH_NONFATAL_OOM( }) \ + } \ + else \ + { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) \ + { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) \ + { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ + } \ + else \ + { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } \ + else \ + { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ + } while (0) -#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ -do { \ - unsigned _hs_hashv; \ - HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ -} while (0) +#define HASH_ADD_KEYPTR_INORDER(hh, head, keyptr, keylen_in, add, cmpfcn) \ + do \ + { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ + } while (0) -#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ +#define HASH_ADD_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, hashval, add, cmpfcn) \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) -#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ +#define HASH_ADD_INORDER(hh, head, fieldname, keylen_in, add, cmpfcn) \ HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) -#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ -do { \ - IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ - (add)->hh.hashv = (hashval); \ - (add)->hh.key = (const void*) (keyptr); \ - (add)->hh.keylen = (unsigned) (keylen_in); \ - if (!(head)) { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh, add, _ha_oomed); \ - IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, hashval, add) \ + do \ + { \ + IF_HASH_NONFATAL_OOM(int _ha_oomed = 0;) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (const void *)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) \ + { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM(if (!_ha_oomed) { ) \ (head) = (add); \ - IF_HASH_NONFATAL_OOM( } ) \ - } else { \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_APPEND_LIST(hh, head, add); \ - } \ - HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ - HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ -} while (0) + IF_HASH_NONFATAL_OOM( }) \ + } \ + else \ + { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ + } while (0) -#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ -do { \ - unsigned _ha_hashv; \ - HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ -} while (0) +#define HASH_ADD_KEYPTR(hh, head, keyptr, keylen_in, add) \ + do \ + { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ + } while (0) -#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ +#define HASH_ADD_BYHASHVALUE(hh, head, fieldname, keylen_in, hashval, add) \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) -#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ +#define HASH_ADD(hh, head, fieldname, keylen_in, add) \ HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) -#define HASH_TO_BKT(hashv,num_bkts,bkt) \ -do { \ - bkt = ((hashv) & ((num_bkts) - 1U)); \ -} while (0) +#define HASH_TO_BKT(hashv, num_bkts, bkt) \ + do \ + { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ + } while (0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. @@ -445,360 +509,441 @@ do { * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ -#define HASH_DELETE(hh,head,delptr) \ - HASH_DELETE_HH(hh, head, &(delptr)->hh) +#define HASH_DELETE(hh, head, delptr) \ + HASH_DELETE_HH(hh, head, &(delptr)->hh) -#define HASH_DELETE_HH(hh,head,delptrhh) \ -do { \ - struct UT_hash_handle *_hd_hh_del = (delptrhh); \ - if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head) = NULL; \ - } else { \ - unsigned _hd_bkt; \ - if (_hd_hh_del == (head)->hh.tbl->tail) { \ - (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ +#define HASH_DELETE_HH(hh, head, delptrhh) \ + do \ + { \ + struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) \ + { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ } \ - if (_hd_hh_del->prev != NULL) { \ - HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ - } else { \ - DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + else \ + { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) \ + { \ + (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) \ + { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ + } \ + else \ + { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) \ + { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ } \ - if (_hd_hh_del->next != NULL) { \ - HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ - } \ - HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ - (head)->hh.tbl->num_items--; \ - } \ - HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ -} while (0) + HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ + } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ -#define HASH_FIND_STR(head,findstr,out) \ -do { \ - unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ - HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ -} while (0) -#define HASH_ADD_STR(head,strfield,add) \ -do { \ - unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ - HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ -} while (0) -#define HASH_REPLACE_STR(head,strfield,add,replaced) \ -do { \ - unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ - HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ -} while (0) -#define HASH_FIND_INT(head,findint,out) \ - HASH_FIND(hh,head,findint,sizeof(int),out) -#define HASH_ADD_INT(head,intfield,add) \ - HASH_ADD(hh,head,intfield,sizeof(int),add) -#define HASH_REPLACE_INT(head,intfield,add,replaced) \ - HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) -#define HASH_FIND_PTR(head,findptr,out) \ - HASH_FIND(hh,head,findptr,sizeof(void *),out) -#define HASH_ADD_PTR(head,ptrfield,add) \ - HASH_ADD(hh,head,ptrfield,sizeof(void *),add) -#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ - HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) -#define HASH_DEL(head,delptr) \ - HASH_DELETE(hh,head,delptr) +#define HASH_FIND_STR(head, findstr, out) \ + do \ + { \ + unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ + HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ + } while (0) +#define HASH_ADD_STR(head, strfield, add) \ + do \ + { \ + unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ + } while (0) +#define HASH_REPLACE_STR(head, strfield, add, replaced) \ + do \ + { \ + unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ + } while (0) +#define HASH_FIND_INT(head, findint, out) \ + HASH_FIND(hh, head, findint, sizeof(int), out) +#define HASH_ADD_INT(head, intfield, add) \ + HASH_ADD(hh, head, intfield, sizeof(int), add) +#define HASH_REPLACE_INT(head, intfield, add, replaced) \ + HASH_REPLACE(hh, head, intfield, sizeof(int), add, replaced) +#define HASH_FIND_PTR(head, findptr, out) \ + HASH_FIND(hh, head, findptr, sizeof(void *), out) +#define HASH_ADD_PTR(head, ptrfield, add) \ + HASH_ADD(hh, head, ptrfield, sizeof(void *), add) +#define HASH_REPLACE_PTR(head, ptrfield, add, replaced) \ + HASH_REPLACE(hh, head, ptrfield, sizeof(void *), add, replaced) +#define HASH_DEL(head, delptr) \ + HASH_DELETE(hh, head, delptr) /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG -#include /* fprintf, stderr */ -#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0) -#define HASH_FSCK(hh,head,where) \ -do { \ - struct UT_hash_handle *_thh; \ - if (head) { \ - unsigned _bkt_i; \ - unsigned _count = 0; \ - char *_prev; \ - for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ - unsigned _bkt_count = 0; \ - _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ - _prev = NULL; \ - while (_thh) { \ - if (_prev != (char*)(_thh->hh_prev)) { \ - HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ - (where), (void*)_thh->hh_prev, (void*)_prev); \ +#include /* fprintf, stderr */ +#define HASH_OOPS(...) \ + do \ + { \ + fprintf(stderr, __VA_ARGS__); \ + exit(-1); \ + } while (0) +#define HASH_FSCK(hh, head, where) \ + do \ + { \ + struct UT_hash_handle *_thh; \ + if (head) \ + { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) \ + { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) \ + { \ + if (_prev != (char *)(_thh->hh_prev)) \ + { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + (where), (void *)_thh->hh_prev, (void *)_prev); \ + } \ + _bkt_count++; \ + _prev = (char *)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) \ + { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ - _bkt_count++; \ - _prev = (char*)(_thh); \ - _thh = _thh->hh_next; \ } \ - _count += _bkt_count; \ - if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ - HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ - (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + if (_count != (head)->hh.tbl->num_items) \ + { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) \ + { \ + _count++; \ + if (_prev != (char *)_thh->prev) \ + { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", \ + (where), (void *)_thh->prev, (void *)_prev); \ + } \ + _prev = (char *)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) \ + { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ } \ } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ - (where), (head)->hh.tbl->num_items, _count); \ - } \ - _count = 0; \ - _prev = NULL; \ - _thh = &(head)->hh; \ - while (_thh) { \ - _count++; \ - if (_prev != (char*)_thh->prev) { \ - HASH_OOPS("%s: invalid prev %p, actual %p\n", \ - (where), (void*)_thh->prev, (void*)_prev); \ - } \ - _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ - _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ - (where), (head)->hh.tbl->num_items, _count); \ - } \ - } \ -} while (0) + } while (0) #else -#define HASH_FSCK(hh,head,where) +#define HASH_FSCK(hh, head, where) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ -do { \ - unsigned _klen = fieldlen; \ - write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ - write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ -} while (0) +#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen) \ + do \ + { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ + } while (0) #else -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen) #endif /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ -#define HASH_BER(key,keylen,hashv) \ -do { \ - unsigned _hb_keylen = (unsigned)keylen; \ - const unsigned char *_hb_key = (const unsigned char*)(key); \ - (hashv) = 0; \ - while (_hb_keylen-- != 0U) { \ - (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ - } \ -} while (0) - +#define HASH_BER(key, keylen, hashv) \ + do \ + { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char *)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) \ + { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ + } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ -#define HASH_SAX(key,keylen,hashv) \ -do { \ - unsigned _sx_i; \ - const unsigned char *_hs_key = (const unsigned char*)(key); \ - hashv = 0; \ - for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ - hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ - } \ -} while (0) +#define HASH_SAX(key, keylen, hashv) \ + do \ + { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char *)(key); \ + hashv = 0; \ + for (_sx_i = 0; _sx_i < keylen; _sx_i++) \ + { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ + } while (0) /* FNV-1a variation */ -#define HASH_FNV(key,keylen,hashv) \ -do { \ - unsigned _fn_i; \ - const unsigned char *_hf_key = (const unsigned char*)(key); \ - (hashv) = 2166136261U; \ - for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ - hashv = hashv ^ _hf_key[_fn_i]; \ - hashv = hashv * 16777619U; \ - } \ -} while (0) +#define HASH_FNV(key, keylen, hashv) \ + do \ + { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char *)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i = 0; _fn_i < keylen; _fn_i++) \ + { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ + } while (0) -#define HASH_OAT(key,keylen,hashv) \ -do { \ - unsigned _ho_i; \ - const unsigned char *_ho_key=(const unsigned char*)(key); \ - hashv = 0; \ - for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ - hashv += _ho_key[_ho_i]; \ - hashv += (hashv << 10); \ - hashv ^= (hashv >> 6); \ - } \ - hashv += (hashv << 3); \ - hashv ^= (hashv >> 11); \ - hashv += (hashv << 15); \ -} while (0) +#define HASH_OAT(key, keylen, hashv) \ + do \ + { \ + unsigned _ho_i; \ + const unsigned char *_ho_key = (const unsigned char *)(key); \ + hashv = 0; \ + for (_ho_i = 0; _ho_i < keylen; _ho_i++) \ + { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + } while (0) -#define HASH_JEN_MIX(a,b,c) \ -do { \ - a -= b; a -= c; a ^= ( c >> 13 ); \ - b -= c; b -= a; b ^= ( a << 8 ); \ - c -= a; c -= b; c ^= ( b >> 13 ); \ - a -= b; a -= c; a ^= ( c >> 12 ); \ - b -= c; b -= a; b ^= ( a << 16 ); \ - c -= a; c -= b; c ^= ( b >> 5 ); \ - a -= b; a -= c; a ^= ( c >> 3 ); \ - b -= c; b -= a; b ^= ( a << 10 ); \ - c -= a; c -= b; c ^= ( b >> 15 ); \ -} while (0) +#define HASH_JEN_MIX(a, b, c) \ + do \ + { \ + a -= b; \ + a -= c; \ + a ^= (c >> 13); \ + b -= c; \ + b -= a; \ + b ^= (a << 8); \ + c -= a; \ + c -= b; \ + c ^= (b >> 13); \ + a -= b; \ + a -= c; \ + a ^= (c >> 12); \ + b -= c; \ + b -= a; \ + b ^= (a << 16); \ + c -= a; \ + c -= b; \ + c ^= (b >> 5); \ + a -= b; \ + a -= c; \ + a ^= (c >> 3); \ + b -= c; \ + b -= a; \ + b ^= (a << 10); \ + c -= a; \ + c -= b; \ + c ^= (b >> 15); \ + } while (0) -#define HASH_JEN(key,keylen,hashv) \ -do { \ - unsigned _hj_i,_hj_j,_hj_k; \ - unsigned const char *_hj_key=(unsigned const char*)(key); \ - hashv = 0xfeedbeefu; \ - _hj_i = _hj_j = 0x9e3779b9u; \ - _hj_k = (unsigned)(keylen); \ - while (_hj_k >= 12U) { \ - _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ - + ( (unsigned)_hj_key[2] << 16 ) \ - + ( (unsigned)_hj_key[3] << 24 ) ); \ - _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ - + ( (unsigned)_hj_key[6] << 16 ) \ - + ( (unsigned)_hj_key[7] << 24 ) ); \ - hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ - + ( (unsigned)_hj_key[10] << 16 ) \ - + ( (unsigned)_hj_key[11] << 24 ) ); \ - \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - \ - _hj_key += 12; \ - _hj_k -= 12U; \ - } \ - hashv += (unsigned)(keylen); \ - switch ( _hj_k ) { \ - case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ - case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ - case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ - case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ - case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ - case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ - case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ - case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ - case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ - case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ - case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ - default: ; \ - } \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ -} while (0) +#define HASH_JEN(key, keylen, hashv) \ + do \ + { \ + unsigned _hj_i, _hj_j, _hj_k; \ + unsigned const char *_hj_key = (unsigned const char *)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) \ + { \ + _hj_i += (_hj_key[0] + ((unsigned)_hj_key[1] << 8) + ((unsigned)_hj_key[2] << 16) + ((unsigned)_hj_key[3] << 24)); \ + _hj_j += (_hj_key[4] + ((unsigned)_hj_key[5] << 8) + ((unsigned)_hj_key[6] << 16) + ((unsigned)_hj_key[7] << 24)); \ + hashv += (_hj_key[8] + ((unsigned)_hj_key[9] << 8) + ((unsigned)_hj_key[10] << 16) + ((unsigned)_hj_key[11] << 24)); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch (_hj_k) \ + { \ + case 11: \ + hashv += ((unsigned)_hj_key[10] << 24); /* FALLTHROUGH */ \ + case 10: \ + hashv += ((unsigned)_hj_key[9] << 16); /* FALLTHROUGH */ \ + case 9: \ + hashv += ((unsigned)_hj_key[8] << 8); /* FALLTHROUGH */ \ + case 8: \ + _hj_j += ((unsigned)_hj_key[7] << 24); /* FALLTHROUGH */ \ + case 7: \ + _hj_j += ((unsigned)_hj_key[6] << 16); /* FALLTHROUGH */ \ + case 6: \ + _hj_j += ((unsigned)_hj_key[5] << 8); /* FALLTHROUGH */ \ + case 5: \ + _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: \ + _hj_i += ((unsigned)_hj_key[3] << 24); /* FALLTHROUGH */ \ + case 3: \ + _hj_i += ((unsigned)_hj_key[2] << 16); /* FALLTHROUGH */ \ + case 2: \ + _hj_i += ((unsigned)_hj_key[1] << 8); /* FALLTHROUGH */ \ + case 1: \ + _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ + default:; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + } while (0) /* The Paul Hsieh hash function */ #undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__) +#define get16bits(d) (*((const uint16_t *)(d))) #endif -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ - +(uint32_t)(((const uint8_t *)(d))[0]) ) +#if !defined(get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) + (uint32_t)(((const uint8_t *)(d))[0])) #endif -#define HASH_SFH(key,keylen,hashv) \ -do { \ - unsigned const char *_sfh_key=(unsigned const char*)(key); \ - uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ - \ - unsigned _sfh_rem = _sfh_len & 3U; \ - _sfh_len >>= 2; \ - hashv = 0xcafebabeu; \ - \ - /* Main loop */ \ - for (;_sfh_len > 0U; _sfh_len--) { \ - hashv += get16bits (_sfh_key); \ - _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ - hashv = (hashv << 16) ^ _sfh_tmp; \ - _sfh_key += 2U*sizeof (uint16_t); \ - hashv += hashv >> 11; \ - } \ - \ - /* Handle end cases */ \ - switch (_sfh_rem) { \ - case 3: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 16; \ - hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ - hashv += hashv >> 11; \ - break; \ - case 2: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 11; \ - hashv += hashv >> 17; \ - break; \ - case 1: hashv += *_sfh_key; \ - hashv ^= hashv << 10; \ - hashv += hashv >> 1; \ - break; \ - default: ; \ - } \ - \ - /* Force "avalanching" of final 127 bits */ \ - hashv ^= hashv << 3; \ - hashv += hashv >> 5; \ - hashv ^= hashv << 4; \ - hashv += hashv >> 17; \ - hashv ^= hashv << 25; \ - hashv += hashv >> 6; \ -} while (0) +#define HASH_SFH(key, keylen, hashv) \ + do \ + { \ + unsigned const char *_sfh_key = (unsigned const char *)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (; _sfh_len > 0U; _sfh_len--) \ + { \ + hashv += get16bits(_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits(_sfh_key + 2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U * sizeof(uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) \ + { \ + case 3: \ + hashv += get16bits(_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof(uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: \ + hashv += get16bits(_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: \ + hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + break; \ + default:; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + } while (0) /* iterate over items in a known bucket to find desired item */ -#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ -do { \ - if ((head).hh_head != NULL) { \ - DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ - } else { \ - (out) = NULL; \ - } \ - while ((out) != NULL) { \ - if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ - if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ - break; \ - } \ - } \ - if ((out)->hh.hh_next != NULL) { \ - DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ - } else { \ - (out) = NULL; \ - } \ - } \ -} while (0) +#define HASH_FIND_IN_BKT(tbl, hh, head, keyptr, keylen_in, hashval, out) \ + do \ + { \ + if ((head).hh_head != NULL) \ + { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } \ + else \ + { \ + (out) = NULL; \ + } \ + while ((out) != NULL) \ + { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) \ + { \ + if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) \ + { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) \ + { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } \ + else \ + { \ + (out) = NULL; \ + } \ + } \ + } while (0) /* add an item to a bucket */ -#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ -do { \ - UT_hash_bucket *_ha_head = &(head); \ - _ha_head->count++; \ - (addhh)->hh_next = _ha_head->hh_head; \ - (addhh)->hh_prev = NULL; \ - if (_ha_head->hh_head != NULL) { \ - _ha_head->hh_head->hh_prev = (addhh); \ - } \ - _ha_head->hh_head = (addhh); \ - if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ - && !(addhh)->tbl->noexpand) { \ - HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (oomed) { \ - HASH_DEL_IN_BKT(head,addhh); \ - } \ - ) \ - } \ -} while (0) +#define HASH_ADD_TO_BKT(head, hh, addhh, oomed) \ + do \ + { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) \ + { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) && !(addhh)->tbl->noexpand) \ + { \ + HASH_EXPAND_BUCKETS(addhh, (addhh)->tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + HASH_DEL_IN_BKT(head, addhh); \ + }) \ + } \ + } while (0) /* remove an item from a given bucket */ -#define HASH_DEL_IN_BKT(head,delhh) \ -do { \ - UT_hash_bucket *_hd_head = &(head); \ - _hd_head->count--; \ - if (_hd_head->hh_head == (delhh)) { \ - _hd_head->hh_head = (delhh)->hh_next; \ - } \ - if ((delhh)->hh_prev) { \ - (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ - } \ - if ((delhh)->hh_next) { \ - (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ - } \ -} while (0) +#define HASH_DEL_IN_BKT(head, delhh) \ + do \ + { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) \ + { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) \ + { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) \ + { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ + } while (0) /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the @@ -829,259 +974,292 @@ do { * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ -#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ -do { \ - unsigned _he_bkt; \ - unsigned _he_bkt_i; \ - struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ - UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ - _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ - sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ - if (!_he_new_buckets) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero(_he_new_buckets, \ - sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ - (tbl)->ideal_chain_maxlen = \ - ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ - ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ - (tbl)->nonideal_items = 0; \ - for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ - _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ - while (_he_thh != NULL) { \ - _he_hh_nxt = _he_thh->hh_next; \ - HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ - _he_newbkt = &(_he_new_buckets[_he_bkt]); \ - if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ - (tbl)->nonideal_items++; \ - if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ - _he_newbkt->expand_mult++; \ - } \ - } \ - _he_thh->hh_prev = NULL; \ - _he_thh->hh_next = _he_newbkt->hh_head; \ - if (_he_newbkt->hh_head != NULL) { \ - _he_newbkt->hh_head->hh_prev = _he_thh; \ - } \ - _he_newbkt->hh_head = _he_thh; \ - _he_thh = _he_hh_nxt; \ - } \ - } \ - uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ - (tbl)->num_buckets *= 2U; \ - (tbl)->log2_num_buckets++; \ - (tbl)->buckets = _he_new_buckets; \ - (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ - ((tbl)->ineff_expands+1U) : 0U; \ - if ((tbl)->ineff_expands > 1U) { \ - (tbl)->noexpand = 1; \ - uthash_noexpand_fyi(tbl); \ - } \ - uthash_expand_fyi(tbl); \ - } \ -} while (0) - +#define HASH_EXPAND_BUCKETS(hh, tbl, oomed) \ + do \ + { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket *)uthash_malloc( \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + if (!_he_new_buckets) \ + { \ + HASH_RECORD_OOM(oomed); \ + } \ + else \ + { \ + uthash_bzero(_he_new_buckets, \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets + 1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets * 2U) - 1U)) != 0U) ? 1U : 0U); \ + (tbl)->nonideal_items = 0; \ + for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = (tbl)->buckets[_he_bkt_i].hh_head; \ + while (_he_thh != NULL) \ + { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) \ + { \ + (tbl)->nonideal_items++; \ + if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) \ + { \ + _he_newbkt->expand_mult++; \ + } \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) \ + { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? ((tbl)->ineff_expands + 1U) : 0U; \ + if ((tbl)->ineff_expands > 1U) \ + { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ + } \ + } while (0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ -#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) -#define HASH_SRT(hh,head,cmpfcn) \ -do { \ - unsigned _hs_i; \ - unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ - struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ - if (head != NULL) { \ - _hs_insize = 1; \ - _hs_looping = 1; \ - _hs_list = &((head)->hh); \ - while (_hs_looping != 0U) { \ - _hs_p = _hs_list; \ - _hs_list = NULL; \ - _hs_tail = NULL; \ - _hs_nmerges = 0; \ - while (_hs_p != NULL) { \ - _hs_nmerges++; \ - _hs_q = _hs_p; \ - _hs_psize = 0; \ - for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ - _hs_psize++; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - if (_hs_q == NULL) { \ - break; \ - } \ - } \ - _hs_qsize = _hs_insize; \ - while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ - if (_hs_psize == 0U) { \ - _hs_e = _hs_q; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - _hs_qsize--; \ - } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ - _hs_e = _hs_p; \ - if (_hs_p != NULL) { \ - _hs_p = ((_hs_p->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ - } \ - _hs_psize--; \ - } else if ((cmpfcn( \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ - )) <= 0) { \ - _hs_e = _hs_p; \ - if (_hs_p != NULL) { \ - _hs_p = ((_hs_p->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ - } \ - _hs_psize--; \ - } else { \ - _hs_e = _hs_q; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - _hs_qsize--; \ - } \ - if ( _hs_tail != NULL ) { \ - _hs_tail->next = ((_hs_e != NULL) ? \ - ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ - } else { \ - _hs_list = _hs_e; \ - } \ - if (_hs_e != NULL) { \ - _hs_e->prev = ((_hs_tail != NULL) ? \ - ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ - } \ - _hs_tail = _hs_e; \ - } \ - _hs_p = _hs_q; \ - } \ - if (_hs_tail != NULL) { \ - _hs_tail->next = NULL; \ - } \ - if (_hs_nmerges <= 1U) { \ - _hs_looping = 0; \ - (head)->hh.tbl->tail = _hs_tail; \ - DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ - } \ - _hs_insize *= 2U; \ - } \ - HASH_FSCK(hh, head, "HASH_SRT"); \ - } \ -} while (0) +#define HASH_SORT(head, cmpfcn) HASH_SRT(hh, head, cmpfcn) +#define HASH_SRT(hh, head, cmpfcn) \ + do \ + { \ + unsigned _hs_i; \ + unsigned _hs_looping, _hs_nmerges, _hs_insize, _hs_psize, _hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) \ + { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) \ + { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) \ + { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) \ + { \ + _hs_psize++; \ + _hs_q = ((_hs_q->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + if (_hs_q == NULL) \ + { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) \ + { \ + if (_hs_psize == 0U) \ + { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + else if ((_hs_qsize == 0U) || (_hs_q == NULL)) \ + { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) \ + { \ + _hs_p = ((_hs_p->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } \ + else if ((cmpfcn( \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)))) <= 0) \ + { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) \ + { \ + _hs_p = ((_hs_p->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } \ + else \ + { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + if (_hs_tail != NULL) \ + { \ + _hs_tail->next = ((_hs_e != NULL) ? ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ + } \ + else \ + { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) \ + { \ + _hs_e->prev = ((_hs_tail != NULL) ? ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) \ + { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) \ + { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ + } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ -#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ -do { \ - unsigned _src_bkt, _dst_bkt; \ - void *_last_elt = NULL, *_elt; \ - UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ - ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ - if ((src) != NULL) { \ - for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ - for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ - _src_hh != NULL; \ - _src_hh = _src_hh->hh_next) { \ - _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ - if (cond(_elt)) { \ - IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ - _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \ - _dst_hh->key = _src_hh->key; \ - _dst_hh->keylen = _src_hh->keylen; \ - _dst_hh->hashv = _src_hh->hashv; \ - _dst_hh->prev = _last_elt; \ - _dst_hh->next = NULL; \ - if (_last_elt_hh != NULL) { \ - _last_elt_hh->next = _elt; \ - } \ - if ((dst) == NULL) { \ - DECLTYPE_ASSIGN(dst, _elt); \ - HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (_hs_oomed) { \ - uthash_nonfatal_oom(_elt); \ - (dst) = NULL; \ - continue; \ - } \ - ) \ - } else { \ - _dst_hh->tbl = (dst)->hh_dst.tbl; \ - } \ - HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ - HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ - (dst)->hh_dst.tbl->num_items++; \ - IF_HASH_NONFATAL_OOM( \ - if (_hs_oomed) { \ - HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ - HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ - _dst_hh->tbl = NULL; \ - uthash_nonfatal_oom(_elt); \ - continue; \ - } \ - ) \ - HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ - _last_elt = _elt; \ - _last_elt_hh = _dst_hh; \ - } \ - } \ - } \ - } \ - HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ -} while (0) +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ + do \ + { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh = NULL; \ + ptrdiff_t _dst_hho = ((char *)(&(dst)->hh_dst) - (char *)(dst)); \ + if ((src) != NULL) \ + { \ + for (_src_bkt = 0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) \ + { \ + for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; \ + _src_hh = _src_hh->hh_next) \ + { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) \ + { \ + IF_HASH_NONFATAL_OOM(int _hs_oomed = 0;) \ + _dst_hh = (UT_hash_handle *)(void *)(((char *)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) \ + { \ + _last_elt_hh->next = _elt; \ + } \ + if ((dst) == NULL) \ + { \ + DECLTYPE_ASSIGN(dst, _elt); \ + HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + uthash_nonfatal_oom(_elt); \ + (dst) = NULL; \ + continue; \ + }) \ + } \ + else \ + { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ + (dst)->hh_dst.tbl->num_items++; \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ + HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ + _dst_hh->tbl = NULL; \ + uthash_nonfatal_oom(_elt); \ + continue; \ + }) \ + HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ + } while (0) -#define HASH_CLEAR(hh,head) \ -do { \ - if ((head) != NULL) { \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head) = NULL; \ - } \ -} while (0) +#define HASH_CLEAR(hh, head) \ + do \ + { \ + if ((head) != NULL) \ + { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } \ + } while (0) -#define HASH_OVERHEAD(hh,head) \ - (((head) != NULL) ? ( \ - (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ - ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ - sizeof(UT_hash_table) + \ - (HASH_BLOOM_BYTELEN))) : 0U) +#define HASH_OVERHEAD(hh, head) \ + (((head) != NULL) ? ( \ + (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + \ + (HASH_BLOOM_BYTELEN))) \ + : 0U) #ifdef NO_DECLTYPE -#define HASH_ITER(hh,head,el,tmp) \ -for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ - (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#define HASH_ITER(hh, head, el, tmp) \ + for (((el) = (head)), ((*(char **)(&(tmp))) = (char *)((head != NULL) ? (head)->hh.next : NULL)); \ + (el) != NULL; ((el) = (tmp)), ((*(char **)(&(tmp))) = (char *)((tmp != NULL) ? (tmp)->hh.next : NULL))) #else -#define HASH_ITER(hh,head,el,tmp) \ -for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ - (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#define HASH_ITER(hh, head, el, tmp) \ + for (((el) = (head)), ((tmp) = DECLTYPE(el)((head != NULL) ? (head)->hh.next : NULL)); \ + (el) != NULL; ((el) = (tmp)), ((tmp) = DECLTYPE(el)((tmp != NULL) ? (tmp)->hh.next : NULL))) #endif /* obtain a count of items in the hash */ -#define HASH_COUNT(head) HASH_CNT(hh,head) -#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) +#define HASH_COUNT(head) HASH_CNT(hh, head) +#define HASH_CNT(hh, head) ((head != NULL) ? ((head)->hh.tbl->num_items) : 0U) -typedef struct UT_hash_bucket { - struct UT_hash_handle *hh_head; - unsigned count; +typedef struct UT_hash_bucket +{ + struct UT_hash_handle *hh_head; + unsigned count; - /* expand_mult is normally set to 0. In this situation, the max chain length - * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If - * the bucket's chain exceeds this length, bucket expansion is triggered). - * However, setting expand_mult to a non-zero value delays bucket expansion - * (that would be triggered by additions to this particular bucket) - * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. - * (The multiplier is simply expand_mult+1). The whole idea of this - * multiplier is to reduce bucket expansions, since they are expensive, in - * situations where we know that a particular bucket tends to be overused. - * It is better to let its chain length grow to a longer yet-still-bounded - * value, than to do an O(n) bucket expansion too often. - */ - unsigned expand_mult; + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; } UT_hash_bucket; @@ -1089,48 +1267,50 @@ typedef struct UT_hash_bucket { #define HASH_SIGNATURE 0xa0111fe1u #define HASH_BLOOM_SIGNATURE 0xb12220f2u -typedef struct UT_hash_table { - UT_hash_bucket *buckets; - unsigned num_buckets, log2_num_buckets; - unsigned num_items; - struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ - ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ +typedef struct UT_hash_table +{ + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ - /* in an ideal situation (all buckets used equally), no bucket would have - * more than ceil(#items/#buckets) items. that's the ideal chain length. */ - unsigned ideal_chain_maxlen; + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; - /* nonideal_items is the number of items in the hash whose chain position - * exceeds the ideal chain maxlen. these items pay the penalty for an uneven - * hash distribution; reaching them in a chain traversal takes >ideal steps */ - unsigned nonideal_items; + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; - /* ineffective expands occur when a bucket doubling was performed, but - * afterward, more than half the items in the hash had nonideal chain - * positions. If this happens on two consecutive expansions we inhibit any - * further expansion, as it's not helping; this happens when the hash - * function isn't a good fit for the key domain. When expansion is inhibited - * the hash will still work, albeit no longer in constant time. */ - unsigned ineff_expands, noexpand; + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; - uint32_t signature; /* used only to find hash tables in external analysis */ + uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM - uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ - uint8_t *bloom_bv; - uint8_t bloom_nbits; + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; #endif } UT_hash_table; -typedef struct UT_hash_handle { - struct UT_hash_table *tbl; - void *prev; /* prev element in app order */ - void *next; /* next element in app order */ - struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ - struct UT_hash_handle *hh_next; /* next hh in bucket order */ - const void *key; /* ptr to enclosing struct's key */ - unsigned keylen; /* enclosing struct's key len */ - unsigned hashv; /* result of hash-fcn(key) */ +typedef struct UT_hash_handle +{ + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + const void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */ diff --git a/nfq/win.c b/nfq/win.c index e135324..7253de2 100644 --- a/nfq/win.c +++ b/nfq/win.c @@ -18,8 +18,7 @@ bool service_run(int argc, char *argv[]) { SERVICE_TABLE_ENTRY ServiceTable[] = { {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main}, - {NULL, NULL} - }; + {NULL, NULL}}; service_argc = argc; service_argv = argv; @@ -76,5 +75,4 @@ void service_main(int argc __attribute__((unused)), char *argv[] __attribute__(( return; } - #endif diff --git a/nfq/win.h b/nfq/win.h index 13a0980..c319fa1 100644 --- a/nfq/win.h +++ b/nfq/win.h @@ -7,4 +7,3 @@ bool service_run(); #endif - diff --git a/nfq/windivert/windivert.h b/nfq/windivert/windivert.h index fc63adf..de10916 100644 --- a/nfq/windivert/windivert.h +++ b/nfq/windivert/windivert.h @@ -21,12 +21,12 @@ * the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * + * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -37,11 +37,11 @@ #ifndef WINDIVERT_KERNEL #include -#endif /* WINDIVERT_KERNEL */ +#endif /* WINDIVERT_KERNEL */ #ifndef WINDIVERTEXPORT -#define WINDIVERTEXPORT extern __declspec(dllimport) -#endif /* WINDIVERTEXPORT */ +#define WINDIVERTEXPORT extern __declspec(dllimport) +#endif /* WINDIVERTEXPORT */ #ifdef __MINGW32__ #define __in @@ -51,423 +51,422 @@ #define __inout #define __inout_opt #include -#define INT8 int8_t -#define UINT8 uint8_t -#define INT16 int16_t -#define UINT16 uint16_t -#define INT32 int32_t -#define UINT32 uint32_t -#define INT64 int64_t -#define UINT64 uint64_t -#endif /* __MINGW32__ */ +#define INT8 int8_t +#define UINT8 uint8_t +#define INT16 int16_t +#define UINT16 uint16_t +#define INT32 int32_t +#define UINT32 uint32_t +#define INT64 int64_t +#define UINT64 uint64_t +#endif /* __MINGW32__ */ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/****************************************************************************/ -/* WINDIVERT API */ -/****************************************************************************/ + /****************************************************************************/ + /* WINDIVERT API */ + /****************************************************************************/ -/* - * WinDivert layers. - */ -typedef enum -{ - WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */ - WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */ - WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */ - WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */ - WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */ -} WINDIVERT_LAYER, *PWINDIVERT_LAYER; + /* + * WinDivert layers. + */ + typedef enum + { + WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */ + WINDIVERT_LAYER_NETWORK_FORWARD = 1, /* Network layer (forwarded packets) */ + WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */ + WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */ + WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */ + } WINDIVERT_LAYER, + *PWINDIVERT_LAYER; -/* - * WinDivert NETWORK and NETWORK_FORWARD layer data. - */ -typedef struct -{ - UINT32 IfIdx; /* Packet's interface index. */ - UINT32 SubIfIdx; /* Packet's sub-interface index. */ -} WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK; + /* + * WinDivert NETWORK and NETWORK_FORWARD layer data. + */ + typedef struct + { + UINT32 IfIdx; /* Packet's interface index. */ + UINT32 SubIfIdx; /* Packet's sub-interface index. */ + } WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK; -/* - * WinDivert FLOW layer data. - */ -typedef struct -{ - UINT64 EndpointId; /* Endpoint ID. */ - UINT64 ParentEndpointId; /* Parent endpoint ID. */ - UINT32 ProcessId; /* Process ID. */ - UINT32 LocalAddr[4]; /* Local address. */ - UINT32 RemoteAddr[4]; /* Remote address. */ - UINT16 LocalPort; /* Local port. */ - UINT16 RemotePort; /* Remote port. */ - UINT8 Protocol; /* Protocol. */ -} WINDIVERT_DATA_FLOW, *PWINDIVERT_DATA_FLOW; + /* + * WinDivert FLOW layer data. + */ + typedef struct + { + UINT64 EndpointId; /* Endpoint ID. */ + UINT64 ParentEndpointId; /* Parent endpoint ID. */ + UINT32 ProcessId; /* Process ID. */ + UINT32 LocalAddr[4]; /* Local address. */ + UINT32 RemoteAddr[4]; /* Remote address. */ + UINT16 LocalPort; /* Local port. */ + UINT16 RemotePort; /* Remote port. */ + UINT8 Protocol; /* Protocol. */ + } WINDIVERT_DATA_FLOW, *PWINDIVERT_DATA_FLOW; -/* - * WinDivert SOCKET layer data. - */ -typedef struct -{ - UINT64 EndpointId; /* Endpoint ID. */ - UINT64 ParentEndpointId; /* Parent Endpoint ID. */ - UINT32 ProcessId; /* Process ID. */ - UINT32 LocalAddr[4]; /* Local address. */ - UINT32 RemoteAddr[4]; /* Remote address. */ - UINT16 LocalPort; /* Local port. */ - UINT16 RemotePort; /* Remote port. */ - UINT8 Protocol; /* Protocol. */ -} WINDIVERT_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET; + /* + * WinDivert SOCKET layer data. + */ + typedef struct + { + UINT64 EndpointId; /* Endpoint ID. */ + UINT64 ParentEndpointId; /* Parent Endpoint ID. */ + UINT32 ProcessId; /* Process ID. */ + UINT32 LocalAddr[4]; /* Local address. */ + UINT32 RemoteAddr[4]; /* Remote address. */ + UINT16 LocalPort; /* Local port. */ + UINT16 RemotePort; /* Remote port. */ + UINT8 Protocol; /* Protocol. */ + } WINDIVERT_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET; -/* - * WinDivert REFLECTION layer data. - */ -typedef struct -{ - INT64 Timestamp; /* Handle open time. */ - UINT32 ProcessId; /* Handle process ID. */ - WINDIVERT_LAYER Layer; /* Handle layer. */ - UINT64 Flags; /* Handle flags. */ - INT16 Priority; /* Handle priority. */ -} WINDIVERT_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT; + /* + * WinDivert REFLECTION layer data. + */ + typedef struct + { + INT64 Timestamp; /* Handle open time. */ + UINT32 ProcessId; /* Handle process ID. */ + WINDIVERT_LAYER Layer; /* Handle layer. */ + UINT64 Flags; /* Handle flags. */ + INT16 Priority; /* Handle priority. */ + } WINDIVERT_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT; /* * WinDivert address. */ #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable: 4201) +#pragma warning(disable : 4201) #endif -typedef struct -{ - INT64 Timestamp; /* Packet's timestamp. */ - UINT32 Layer:8; /* Packet's layer. */ - UINT32 Event:8; /* Packet event. */ - UINT32 Sniffed:1; /* Packet was sniffed? */ - UINT32 Outbound:1; /* Packet is outound? */ - UINT32 Loopback:1; /* Packet is loopback? */ - UINT32 Impostor:1; /* Packet is impostor? */ - UINT32 IPv6:1; /* Packet is IPv6? */ - UINT32 IPChecksum:1; /* Packet has valid IPv4 checksum? */ - UINT32 TCPChecksum:1; /* Packet has valid TCP checksum? */ - UINT32 UDPChecksum:1; /* Packet has valid UDP checksum? */ - UINT32 Reserved1:8; - UINT32 Reserved2; - union + typedef struct { - WINDIVERT_DATA_NETWORK Network; /* Network layer data. */ - WINDIVERT_DATA_FLOW Flow; /* Flow layer data. */ - WINDIVERT_DATA_SOCKET Socket; /* Socket layer data. */ - WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */ - UINT8 Reserved3[64]; - }; -} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS; + INT64 Timestamp; /* Packet's timestamp. */ + UINT32 Layer : 8; /* Packet's layer. */ + UINT32 Event : 8; /* Packet event. */ + UINT32 Sniffed : 1; /* Packet was sniffed? */ + UINT32 Outbound : 1; /* Packet is outound? */ + UINT32 Loopback : 1; /* Packet is loopback? */ + UINT32 Impostor : 1; /* Packet is impostor? */ + UINT32 IPv6 : 1; /* Packet is IPv6? */ + UINT32 IPChecksum : 1; /* Packet has valid IPv4 checksum? */ + UINT32 TCPChecksum : 1; /* Packet has valid TCP checksum? */ + UINT32 UDPChecksum : 1; /* Packet has valid UDP checksum? */ + UINT32 Reserved1 : 8; + UINT32 Reserved2; + union + { + WINDIVERT_DATA_NETWORK Network; /* Network layer data. */ + WINDIVERT_DATA_FLOW Flow; /* Flow layer data. */ + WINDIVERT_DATA_SOCKET Socket; /* Socket layer data. */ + WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */ + UINT8 Reserved3[64]; + }; + } WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS; #ifdef _MSC_VER #pragma warning(pop) #endif -/* - * WinDivert events. - */ -typedef enum -{ - WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */ - WINDIVERT_EVENT_FLOW_ESTABLISHED = 1, - /* Flow established. */ - WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */ - WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */ - WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */ - WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */ - WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */ - WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */ - WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */ - WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */ -} WINDIVERT_EVENT, *PWINDIVERT_EVENT; + /* + * WinDivert events. + */ + typedef enum + { + WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */ + WINDIVERT_EVENT_FLOW_ESTABLISHED = 1, + /* Flow established. */ + WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */ + WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */ + WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */ + WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */ + WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */ + WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */ + WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */ + WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */ + } WINDIVERT_EVENT, + *PWINDIVERT_EVENT; /* * WinDivert flags. */ -#define WINDIVERT_FLAG_SNIFF 0x0001 -#define WINDIVERT_FLAG_DROP 0x0002 -#define WINDIVERT_FLAG_RECV_ONLY 0x0004 -#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY -#define WINDIVERT_FLAG_SEND_ONLY 0x0008 -#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY -#define WINDIVERT_FLAG_NO_INSTALL 0x0010 -#define WINDIVERT_FLAG_FRAGMENTS 0x0020 +#define WINDIVERT_FLAG_SNIFF 0x0001 +#define WINDIVERT_FLAG_DROP 0x0002 +#define WINDIVERT_FLAG_RECV_ONLY 0x0004 +#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY +#define WINDIVERT_FLAG_SEND_ONLY 0x0008 +#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY +#define WINDIVERT_FLAG_NO_INSTALL 0x0010 +#define WINDIVERT_FLAG_FRAGMENTS 0x0020 -/* - * WinDivert parameters. - */ -typedef enum -{ - WINDIVERT_PARAM_QUEUE_LENGTH = 0, /* Packet queue length. */ - WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */ - WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */ - WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */ - WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */ -} WINDIVERT_PARAM, *PWINDIVERT_PARAM; -#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR + /* + * WinDivert parameters. + */ + typedef enum + { + WINDIVERT_PARAM_QUEUE_LENGTH = 0, /* Packet queue length. */ + WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */ + WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */ + WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */ + WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */ + } WINDIVERT_PARAM, + *PWINDIVERT_PARAM; +#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR -/* - * WinDivert shutdown parameter. - */ -typedef enum -{ - WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */ - WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */ - WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */ -} WINDIVERT_SHUTDOWN, *PWINDIVERT_SHUTDOWN; -#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH + /* + * WinDivert shutdown parameter. + */ + typedef enum + { + WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */ + WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */ + WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */ + } WINDIVERT_SHUTDOWN, + *PWINDIVERT_SHUTDOWN; +#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH #ifndef WINDIVERT_KERNEL -/* - * Open a WinDivert handle. - */ -WINDIVERTEXPORT HANDLE WinDivertOpen( - __in const char *filter, - __in WINDIVERT_LAYER layer, - __in INT16 priority, - __in UINT64 flags); + /* + * Open a WinDivert handle. + */ + WINDIVERTEXPORT HANDLE WinDivertOpen( + __in const char *filter, + __in WINDIVERT_LAYER layer, + __in INT16 priority, + __in UINT64 flags); -/* - * Receive (read) a packet from a WinDivert handle. - */ -WINDIVERTEXPORT BOOL WinDivertRecv( - __in HANDLE handle, - __out_opt VOID *pPacket, - __in UINT packetLen, - __out_opt UINT *pRecvLen, - __out_opt WINDIVERT_ADDRESS *pAddr); + /* + * Receive (read) a packet from a WinDivert handle. + */ + WINDIVERTEXPORT BOOL WinDivertRecv( + __in HANDLE handle, + __out_opt VOID *pPacket, + __in UINT packetLen, + __out_opt UINT *pRecvLen, + __out_opt WINDIVERT_ADDRESS *pAddr); -/* - * Receive (read) a packet from a WinDivert handle. - */ -WINDIVERTEXPORT BOOL WinDivertRecvEx( - __in HANDLE handle, - __out_opt VOID *pPacket, - __in UINT packetLen, - __out_opt UINT *pRecvLen, - __in UINT64 flags, - __out WINDIVERT_ADDRESS *pAddr, - __inout_opt UINT *pAddrLen, - __inout_opt LPOVERLAPPED lpOverlapped); + /* + * Receive (read) a packet from a WinDivert handle. + */ + WINDIVERTEXPORT BOOL WinDivertRecvEx( + __in HANDLE handle, + __out_opt VOID *pPacket, + __in UINT packetLen, + __out_opt UINT *pRecvLen, + __in UINT64 flags, + __out WINDIVERT_ADDRESS *pAddr, + __inout_opt UINT *pAddrLen, + __inout_opt LPOVERLAPPED lpOverlapped); -/* - * Send (write/inject) a packet to a WinDivert handle. - */ -WINDIVERTEXPORT BOOL WinDivertSend( - __in HANDLE handle, - __in const VOID *pPacket, - __in UINT packetLen, - __out_opt UINT *pSendLen, - __in const WINDIVERT_ADDRESS *pAddr); + /* + * Send (write/inject) a packet to a WinDivert handle. + */ + WINDIVERTEXPORT BOOL WinDivertSend( + __in HANDLE handle, + __in const VOID *pPacket, + __in UINT packetLen, + __out_opt UINT *pSendLen, + __in const WINDIVERT_ADDRESS *pAddr); -/* - * Send (write/inject) a packet to a WinDivert handle. - */ -WINDIVERTEXPORT BOOL WinDivertSendEx( - __in HANDLE handle, - __in const VOID *pPacket, - __in UINT packetLen, - __out_opt UINT *pSendLen, - __in UINT64 flags, - __in const WINDIVERT_ADDRESS *pAddr, - __in UINT addrLen, - __inout_opt LPOVERLAPPED lpOverlapped); + /* + * Send (write/inject) a packet to a WinDivert handle. + */ + WINDIVERTEXPORT BOOL WinDivertSendEx( + __in HANDLE handle, + __in const VOID *pPacket, + __in UINT packetLen, + __out_opt UINT *pSendLen, + __in UINT64 flags, + __in const WINDIVERT_ADDRESS *pAddr, + __in UINT addrLen, + __inout_opt LPOVERLAPPED lpOverlapped); -/* - * Shutdown a WinDivert handle. - */ -WINDIVERTEXPORT BOOL WinDivertShutdown( - __in HANDLE handle, - __in WINDIVERT_SHUTDOWN how); + /* + * Shutdown a WinDivert handle. + */ + WINDIVERTEXPORT BOOL WinDivertShutdown( + __in HANDLE handle, + __in WINDIVERT_SHUTDOWN how); -/* - * Close a WinDivert handle. - */ -WINDIVERTEXPORT BOOL WinDivertClose( - __in HANDLE handle); + /* + * Close a WinDivert handle. + */ + WINDIVERTEXPORT BOOL WinDivertClose( + __in HANDLE handle); -/* - * Set a WinDivert handle parameter. - */ -WINDIVERTEXPORT BOOL WinDivertSetParam( - __in HANDLE handle, - __in WINDIVERT_PARAM param, - __in UINT64 value); + /* + * Set a WinDivert handle parameter. + */ + WINDIVERTEXPORT BOOL WinDivertSetParam( + __in HANDLE handle, + __in WINDIVERT_PARAM param, + __in UINT64 value); -/* - * Get a WinDivert handle parameter. - */ -WINDIVERTEXPORT BOOL WinDivertGetParam( - __in HANDLE handle, - __in WINDIVERT_PARAM param, - __out UINT64 *pValue); + /* + * Get a WinDivert handle parameter. + */ + WINDIVERTEXPORT BOOL WinDivertGetParam( + __in HANDLE handle, + __in WINDIVERT_PARAM param, + __out UINT64 *pValue); -#endif /* WINDIVERT_KERNEL */ +#endif /* WINDIVERT_KERNEL */ /* * WinDivert constants. */ -#define WINDIVERT_PRIORITY_HIGHEST 30000 -#define WINDIVERT_PRIORITY_LOWEST (-WINDIVERT_PRIORITY_HIGHEST) -#define WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT 4096 -#define WINDIVERT_PARAM_QUEUE_LENGTH_MIN 32 -#define WINDIVERT_PARAM_QUEUE_LENGTH_MAX 16384 -#define WINDIVERT_PARAM_QUEUE_TIME_DEFAULT 2000 /* 2s */ -#define WINDIVERT_PARAM_QUEUE_TIME_MIN 100 /* 100ms */ -#define WINDIVERT_PARAM_QUEUE_TIME_MAX 16000 /* 16s */ -#define WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT 4194304 /* 4MB */ -#define WINDIVERT_PARAM_QUEUE_SIZE_MIN 65535 /* 64KB */ -#define WINDIVERT_PARAM_QUEUE_SIZE_MAX 33554432 /* 32MB */ -#define WINDIVERT_BATCH_MAX 0xFF /* 255 */ -#define WINDIVERT_MTU_MAX (40 + 0xFFFF) +#define WINDIVERT_PRIORITY_HIGHEST 30000 +#define WINDIVERT_PRIORITY_LOWEST (-WINDIVERT_PRIORITY_HIGHEST) +#define WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT 4096 +#define WINDIVERT_PARAM_QUEUE_LENGTH_MIN 32 +#define WINDIVERT_PARAM_QUEUE_LENGTH_MAX 16384 +#define WINDIVERT_PARAM_QUEUE_TIME_DEFAULT 2000 /* 2s */ +#define WINDIVERT_PARAM_QUEUE_TIME_MIN 100 /* 100ms */ +#define WINDIVERT_PARAM_QUEUE_TIME_MAX 16000 /* 16s */ +#define WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT 4194304 /* 4MB */ +#define WINDIVERT_PARAM_QUEUE_SIZE_MIN 65535 /* 64KB */ +#define WINDIVERT_PARAM_QUEUE_SIZE_MAX 33554432 /* 32MB */ +#define WINDIVERT_BATCH_MAX 0xFF /* 255 */ +#define WINDIVERT_MTU_MAX (40 + 0xFFFF) -/****************************************************************************/ -/* WINDIVERT HELPER API */ -/****************************************************************************/ + /****************************************************************************/ + /* WINDIVERT HELPER API */ + /****************************************************************************/ #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable: 4214) +#pragma warning(disable : 4214) #endif -/* - * IPv4/IPv6/ICMP/ICMPv6/TCP/UDP header definitions. - */ -typedef struct -{ - UINT8 HdrLength:4; - UINT8 Version:4; - UINT8 TOS; - UINT16 Length; - UINT16 Id; - UINT16 FragOff0; - UINT8 TTL; - UINT8 Protocol; - UINT16 Checksum; - UINT32 SrcAddr; - UINT32 DstAddr; -} WINDIVERT_IPHDR, *PWINDIVERT_IPHDR; + /* + * IPv4/IPv6/ICMP/ICMPv6/TCP/UDP header definitions. + */ + typedef struct + { + UINT8 HdrLength : 4; + UINT8 Version : 4; + UINT8 TOS; + UINT16 Length; + UINT16 Id; + UINT16 FragOff0; + UINT8 TTL; + UINT8 Protocol; + UINT16 Checksum; + UINT32 SrcAddr; + UINT32 DstAddr; + } WINDIVERT_IPHDR, *PWINDIVERT_IPHDR; -#define WINDIVERT_IPHDR_GET_FRAGOFF(hdr) \ +#define WINDIVERT_IPHDR_GET_FRAGOFF(hdr) \ (((hdr)->FragOff0) & 0xFF1F) -#define WINDIVERT_IPHDR_GET_MF(hdr) \ +#define WINDIVERT_IPHDR_GET_MF(hdr) \ ((((hdr)->FragOff0) & 0x0020) != 0) -#define WINDIVERT_IPHDR_GET_DF(hdr) \ +#define WINDIVERT_IPHDR_GET_DF(hdr) \ ((((hdr)->FragOff0) & 0x0040) != 0) -#define WINDIVERT_IPHDR_GET_RESERVED(hdr) \ +#define WINDIVERT_IPHDR_GET_RESERVED(hdr) \ ((((hdr)->FragOff0) & 0x0080) != 0) -#define WINDIVERT_IPHDR_SET_FRAGOFF(hdr, val) \ - do \ - { \ - (hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \ - ((val) & 0xFF1F); \ - } \ - while (FALSE) -#define WINDIVERT_IPHDR_SET_MF(hdr, val) \ - do \ - { \ - (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \ - (((val) & 0x0001) << 5); \ - } \ - while (FALSE) -#define WINDIVERT_IPHDR_SET_DF(hdr, val) \ - do \ - { \ - (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \ - (((val) & 0x0001) << 6); \ - } \ - while (FALSE) -#define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \ - do \ - { \ - (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \ - (((val) & 0x0001) << 7); \ - } \ - while (FALSE) +#define WINDIVERT_IPHDR_SET_FRAGOFF(hdr, val) \ + do \ + { \ + (hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \ + ((val) & 0xFF1F); \ + } while (FALSE) +#define WINDIVERT_IPHDR_SET_MF(hdr, val) \ + do \ + { \ + (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \ + (((val) & 0x0001) << 5); \ + } while (FALSE) +#define WINDIVERT_IPHDR_SET_DF(hdr, val) \ + do \ + { \ + (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \ + (((val) & 0x0001) << 6); \ + } while (FALSE) +#define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \ + do \ + { \ + (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \ + (((val) & 0x0001) << 7); \ + } while (FALSE) -typedef struct -{ - UINT8 TrafficClass0:4; - UINT8 Version:4; - UINT8 FlowLabel0:4; - UINT8 TrafficClass1:4; - UINT16 FlowLabel1; - UINT16 Length; - UINT8 NextHdr; - UINT8 HopLimit; - UINT32 SrcAddr[4]; - UINT32 DstAddr[4]; -} WINDIVERT_IPV6HDR, *PWINDIVERT_IPV6HDR; + typedef struct + { + UINT8 TrafficClass0 : 4; + UINT8 Version : 4; + UINT8 FlowLabel0 : 4; + UINT8 TrafficClass1 : 4; + UINT16 FlowLabel1; + UINT16 Length; + UINT8 NextHdr; + UINT8 HopLimit; + UINT32 SrcAddr[4]; + UINT32 DstAddr[4]; + } WINDIVERT_IPV6HDR, *PWINDIVERT_IPV6HDR; -#define WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(hdr) \ +#define WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(hdr) \ ((((hdr)->TrafficClass0) << 4) | ((hdr)->TrafficClass1)) -#define WINDIVERT_IPV6HDR_GET_FLOWLABEL(hdr) \ +#define WINDIVERT_IPV6HDR_GET_FLOWLABEL(hdr) \ ((((UINT32)(hdr)->FlowLabel0) << 16) | ((UINT32)(hdr)->FlowLabel1)) -#define WINDIVERT_IPV6HDR_SET_TRAFFICCLASS(hdr, val) \ - do \ - { \ - (hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \ - (hdr)->TrafficClass1 = (UINT8)(val); \ - } \ - while (FALSE) -#define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \ - do \ - { \ - (hdr)->FlowLabel0 = (UINT8)((val) >> 16); \ - (hdr)->FlowLabel1 = (UINT16)(val); \ - } \ - while (FALSE) +#define WINDIVERT_IPV6HDR_SET_TRAFFICCLASS(hdr, val) \ + do \ + { \ + (hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \ + (hdr)->TrafficClass1 = (UINT8)(val); \ + } while (FALSE) +#define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \ + do \ + { \ + (hdr)->FlowLabel0 = (UINT8)((val) >> 16); \ + (hdr)->FlowLabel1 = (UINT16)(val); \ + } while (FALSE) -typedef struct -{ - UINT8 Type; - UINT8 Code; - UINT16 Checksum; - UINT32 Body; -} WINDIVERT_ICMPHDR, *PWINDIVERT_ICMPHDR; + typedef struct + { + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + UINT32 Body; + } WINDIVERT_ICMPHDR, *PWINDIVERT_ICMPHDR; -typedef struct -{ - UINT8 Type; - UINT8 Code; - UINT16 Checksum; - UINT32 Body; -} WINDIVERT_ICMPV6HDR, *PWINDIVERT_ICMPV6HDR; + typedef struct + { + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + UINT32 Body; + } WINDIVERT_ICMPV6HDR, *PWINDIVERT_ICMPV6HDR; -typedef struct -{ - UINT16 SrcPort; - UINT16 DstPort; - UINT32 SeqNum; - UINT32 AckNum; - UINT16 Reserved1:4; - UINT16 HdrLength:4; - UINT16 Fin:1; - UINT16 Syn:1; - UINT16 Rst:1; - UINT16 Psh:1; - UINT16 Ack:1; - UINT16 Urg:1; - UINT16 Reserved2:2; - UINT16 Window; - UINT16 Checksum; - UINT16 UrgPtr; -} WINDIVERT_TCPHDR, *PWINDIVERT_TCPHDR; + typedef struct + { + UINT16 SrcPort; + UINT16 DstPort; + UINT32 SeqNum; + UINT32 AckNum; + UINT16 Reserved1 : 4; + UINT16 HdrLength : 4; + UINT16 Fin : 1; + UINT16 Syn : 1; + UINT16 Rst : 1; + UINT16 Psh : 1; + UINT16 Ack : 1; + UINT16 Urg : 1; + UINT16 Reserved2 : 2; + UINT16 Window; + UINT16 Checksum; + UINT16 UrgPtr; + } WINDIVERT_TCPHDR, *PWINDIVERT_TCPHDR; -typedef struct -{ - UINT16 SrcPort; - UINT16 DstPort; - UINT16 Length; - UINT16 Checksum; -} WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR; + typedef struct + { + UINT16 SrcPort; + UINT16 DstPort; + UINT16 Length; + UINT16 Checksum; + } WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR; #ifdef _MSC_VER #pragma warning(pop) @@ -476,155 +475,155 @@ typedef struct /* * Flags for WinDivertHelperCalcChecksums() */ -#define WINDIVERT_HELPER_NO_IP_CHECKSUM 1 -#define WINDIVERT_HELPER_NO_ICMP_CHECKSUM 2 -#define WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM 4 -#define WINDIVERT_HELPER_NO_TCP_CHECKSUM 8 -#define WINDIVERT_HELPER_NO_UDP_CHECKSUM 16 +#define WINDIVERT_HELPER_NO_IP_CHECKSUM 1 +#define WINDIVERT_HELPER_NO_ICMP_CHECKSUM 2 +#define WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM 4 +#define WINDIVERT_HELPER_NO_TCP_CHECKSUM 8 +#define WINDIVERT_HELPER_NO_UDP_CHECKSUM 16 #ifndef WINDIVERT_KERNEL -/* - * Hash a packet. - */ -WINDIVERTEXPORT UINT64 WinDivertHelperHashPacket( - __in const VOID *pPacket, - __in UINT packetLen, - __in UINT64 seed + /* + * Hash a packet. + */ + WINDIVERTEXPORT UINT64 WinDivertHelperHashPacket( + __in const VOID *pPacket, + __in UINT packetLen, + __in UINT64 seed #ifdef __cplusplus - = 0 + = 0 #endif -); + ); -/* - * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet. - */ -WINDIVERTEXPORT BOOL WinDivertHelperParsePacket( - __in const VOID *pPacket, - __in UINT packetLen, - __out_opt PWINDIVERT_IPHDR *ppIpHdr, - __out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr, - __out_opt UINT8 *pProtocol, - __out_opt PWINDIVERT_ICMPHDR *ppIcmpHdr, - __out_opt PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr, - __out_opt PWINDIVERT_TCPHDR *ppTcpHdr, - __out_opt PWINDIVERT_UDPHDR *ppUdpHdr, - __out_opt PVOID *ppData, - __out_opt UINT *pDataLen, - __out_opt PVOID *ppNext, - __out_opt UINT *pNextLen); + /* + * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet. + */ + WINDIVERTEXPORT BOOL WinDivertHelperParsePacket( + __in const VOID *pPacket, + __in UINT packetLen, + __out_opt PWINDIVERT_IPHDR *ppIpHdr, + __out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr, + __out_opt UINT8 *pProtocol, + __out_opt PWINDIVERT_ICMPHDR *ppIcmpHdr, + __out_opt PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr, + __out_opt PWINDIVERT_TCPHDR *ppTcpHdr, + __out_opt PWINDIVERT_UDPHDR *ppUdpHdr, + __out_opt PVOID *ppData, + __out_opt UINT *pDataLen, + __out_opt PVOID *ppNext, + __out_opt UINT *pNextLen); -/* - * Parse an IPv4 address. - */ -WINDIVERTEXPORT BOOL WinDivertHelperParseIPv4Address( - __in const char *addrStr, - __out_opt UINT32 *pAddr); + /* + * Parse an IPv4 address. + */ + WINDIVERTEXPORT BOOL WinDivertHelperParseIPv4Address( + __in const char *addrStr, + __out_opt UINT32 *pAddr); -/* - * Parse an IPv6 address. - */ -WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address( - __in const char *addrStr, - __out_opt UINT32 *pAddr); + /* + * Parse an IPv6 address. + */ + WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address( + __in const char *addrStr, + __out_opt UINT32 *pAddr); -/* - * Format an IPv4 address. - */ -WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address( - __in UINT32 addr, - __out char *buffer, - __in UINT bufLen); + /* + * Format an IPv4 address. + */ + WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address( + __in UINT32 addr, + __out char *buffer, + __in UINT bufLen); -/* - * Format an IPv6 address. - */ -WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address( - __in const UINT32 *pAddr, - __out char *buffer, - __in UINT bufLen); + /* + * Format an IPv6 address. + */ + WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address( + __in const UINT32 *pAddr, + __out char *buffer, + __in UINT bufLen); -/* - * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums. - */ -WINDIVERTEXPORT BOOL WinDivertHelperCalcChecksums( - __inout VOID *pPacket, - __in UINT packetLen, - __out_opt WINDIVERT_ADDRESS *pAddr, - __in UINT64 flags); + /* + * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums. + */ + WINDIVERTEXPORT BOOL WinDivertHelperCalcChecksums( + __inout VOID *pPacket, + __in UINT packetLen, + __out_opt WINDIVERT_ADDRESS *pAddr, + __in UINT64 flags); -/* - * Decrement the TTL/HopLimit. - */ -WINDIVERTEXPORT BOOL WinDivertHelperDecrementTTL( - __inout VOID *pPacket, - __in UINT packetLen); + /* + * Decrement the TTL/HopLimit. + */ + WINDIVERTEXPORT BOOL WinDivertHelperDecrementTTL( + __inout VOID *pPacket, + __in UINT packetLen); -/* - * Compile the given filter string. - */ -WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter( - __in const char *filter, - __in WINDIVERT_LAYER layer, - __out_opt char *object, - __in UINT objLen, - __out_opt const char **errorStr, - __out_opt UINT *errorPos); + /* + * Compile the given filter string. + */ + WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter( + __in const char *filter, + __in WINDIVERT_LAYER layer, + __out_opt char *object, + __in UINT objLen, + __out_opt const char **errorStr, + __out_opt UINT *errorPos); -/* - * Evaluate the given filter string. - */ -WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter( - __in const char *filter, - __in const VOID *pPacket, - __in UINT packetLen, - __in const WINDIVERT_ADDRESS *pAddr); + /* + * Evaluate the given filter string. + */ + WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter( + __in const char *filter, + __in const VOID *pPacket, + __in UINT packetLen, + __in const WINDIVERT_ADDRESS *pAddr); -/* - * Format the given filter string. - */ -WINDIVERTEXPORT BOOL WinDivertHelperFormatFilter( - __in const char *filter, - __in WINDIVERT_LAYER layer, - __out char *buffer, - __in UINT bufLen); + /* + * Format the given filter string. + */ + WINDIVERTEXPORT BOOL WinDivertHelperFormatFilter( + __in const char *filter, + __in WINDIVERT_LAYER layer, + __out char *buffer, + __in UINT bufLen); -/* - * Byte ordering. - */ -WINDIVERTEXPORT UINT16 WinDivertHelperNtohs( - __in UINT16 x); -WINDIVERTEXPORT UINT16 WinDivertHelperHtons( - __in UINT16 x); -WINDIVERTEXPORT UINT32 WinDivertHelperNtohl( - __in UINT32 x); -WINDIVERTEXPORT UINT32 WinDivertHelperHtonl( - __in UINT32 x); -WINDIVERTEXPORT UINT64 WinDivertHelperNtohll( - __in UINT64 x); -WINDIVERTEXPORT UINT64 WinDivertHelperHtonll( - __in UINT64 x); -WINDIVERTEXPORT void WinDivertHelperNtohIPv6Address( - __in const UINT *inAddr, - __out UINT *outAddr); -WINDIVERTEXPORT void WinDivertHelperHtonIPv6Address( - __in const UINT *inAddr, - __out UINT *outAddr); + /* + * Byte ordering. + */ + WINDIVERTEXPORT UINT16 WinDivertHelperNtohs( + __in UINT16 x); + WINDIVERTEXPORT UINT16 WinDivertHelperHtons( + __in UINT16 x); + WINDIVERTEXPORT UINT32 WinDivertHelperNtohl( + __in UINT32 x); + WINDIVERTEXPORT UINT32 WinDivertHelperHtonl( + __in UINT32 x); + WINDIVERTEXPORT UINT64 WinDivertHelperNtohll( + __in UINT64 x); + WINDIVERTEXPORT UINT64 WinDivertHelperHtonll( + __in UINT64 x); + WINDIVERTEXPORT void WinDivertHelperNtohIPv6Address( + __in const UINT *inAddr, + __out UINT *outAddr); + WINDIVERTEXPORT void WinDivertHelperHtonIPv6Address( + __in const UINT *inAddr, + __out UINT *outAddr); -/* - * Old names to be removed in the next version. - */ -WINDIVERTEXPORT void WinDivertHelperNtohIpv6Address( - __in const UINT *inAddr, - __out UINT *outAddr); -WINDIVERTEXPORT void WinDivertHelperHtonIpv6Address( - __in const UINT *inAddr, - __out UINT *outAddr); + /* + * Old names to be removed in the next version. + */ + WINDIVERTEXPORT void WinDivertHelperNtohIpv6Address( + __in const UINT *inAddr, + __out UINT *outAddr); + WINDIVERTEXPORT void WinDivertHelperHtonIpv6Address( + __in const UINT *inAddr, + __out UINT *outAddr); -#endif /* WINDIVERT_KERNEL */ +#endif /* WINDIVERT_KERNEL */ #ifdef __cplusplus } #endif -#endif /* __WINDIVERT_H */ +#endif /* __WINDIVERT_H */ diff --git a/tpws/epoll-shim/include/sys/epoll.h b/tpws/epoll-shim/include/sys/epoll.h index f96c0f1..2583b8d 100644 --- a/tpws/epoll-shim/include/sys/epoll.h +++ b/tpws/epoll-shim/include/sys/epoll.h @@ -1,8 +1,9 @@ -#ifndef SHIM_SYS_EPOLL_H -#define SHIM_SYS_EPOLL_H +#ifndef SHIM_SYS_EPOLL_H +#define SHIM_SYS_EPOLL_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif #include @@ -18,7 +19,10 @@ extern "C" { #define EPOLL_CLOEXEC O_CLOEXEC #define EPOLL_NONBLOCK O_NONBLOCK -enum EPOLL_EVENTS { __EPOLL_DUMMY }; + enum EPOLL_EVENTS + { + __EPOLL_DUMMY + }; #define EPOLLIN 0x001 #define EPOLLPRI 0x002 #define EPOLLOUT 0x004 @@ -31,48 +35,47 @@ enum EPOLL_EVENTS { __EPOLL_DUMMY }; #define EPOLLERR 0x008 #define EPOLLHUP 0x010 #define EPOLLRDHUP 0x2000 -#define EPOLLEXCLUSIVE (1U<<28) -#define EPOLLWAKEUP (1U<<29) -#define EPOLLONESHOT (1U<<30) -#define EPOLLET (1U<<31) +#define EPOLLEXCLUSIVE (1U << 28) +#define EPOLLWAKEUP (1U << 29) +#define EPOLLONESHOT (1U << 30) +#define EPOLLET (1U << 31) #define EPOLL_CTL_ADD 1 #define EPOLL_CTL_DEL 2 #define EPOLL_CTL_MOD 3 -typedef union epoll_data { - void *ptr; - int fd; - uint32_t u32; - uint64_t u64; -} epoll_data_t; + typedef union epoll_data + { + void *ptr; + int fd; + uint32_t u32; + uint64_t u64; + } epoll_data_t; -struct epoll_event { - uint32_t events; - epoll_data_t data; -} + struct epoll_event + { + uint32_t events; + epoll_data_t data; + } #ifdef __x86_64__ -__attribute__ ((__packed__)) + __attribute__((__packed__)) #endif -; - - -int epoll_create(int); -int epoll_create1(int); -int epoll_ctl(int, int, int, struct epoll_event *); -int epoll_wait(int, struct epoll_event *, int, int); -int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *); + ; + int epoll_create(int); + int epoll_create1(int); + int epoll_ctl(int, int, int, struct epoll_event *); + int epoll_wait(int, struct epoll_event *, int, int); + int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *); #ifndef SHIM_SYS_SHIM_HELPERS #define SHIM_SYS_SHIM_HELPERS #include /* IWYU pragma: keep */ -extern int epoll_shim_close(int); + extern int epoll_shim_close(int); #define close epoll_shim_close #endif - #ifdef __cplusplus } #endif diff --git a/tpws/epoll-shim/src/epoll.c b/tpws/epoll-shim/src/epoll.c index 7b11653..7eae3e1 100644 --- a/tpws/epoll-shim/src/epoll.c +++ b/tpws/epoll-shim/src/epoll.c @@ -21,14 +21,16 @@ // TODO(jan): Remove this once the definition is exposed in in // all supported FreeBSD versions. #ifndef timespecsub -#define timespecsub(tsp, usp, vsp) \ - do { \ - (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ - (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ - if ((vsp)->tv_nsec < 0) { \ - (vsp)->tv_sec--; \ - (vsp)->tv_nsec += 1000000000L; \ - } \ +#define timespecsub(tsp, usp, vsp) \ + do \ + { \ + (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ + if ((vsp)->tv_nsec < 0) \ + { \ + (vsp)->tv_sec--; \ + (vsp)->tv_nsec += 1000000000L; \ + } \ } while (0) #endif @@ -39,9 +41,9 @@ epollfd_close(FDContextMapNode *node) } static FDContextVTable const epollfd_vtable = { - .read_fun = fd_context_default_read, - .write_fun = fd_context_default_write, - .close_fun = epollfd_close, + .read_fun = fd_context_default_read, + .write_fun = fd_context_default_write, + .close_fun = epollfd_close, }; static FDContextMapNode * @@ -50,14 +52,16 @@ epoll_create_impl(errno_t *ec) FDContextMapNode *node; node = epoll_shim_ctx_create_node(&epoll_shim_ctx, ec); - if (!node) { + if (!node) + { return NULL; } node->flags = 0; if ((*ec = epollfd_ctx_init(&node->ctx.epollfd, /**/ - node->fd)) != 0) { + node->fd)) != 0) + { goto fail; } @@ -77,7 +81,8 @@ epoll_create_common(void) errno_t ec; node = epoll_create_impl(&ec); - if (!node) { + if (!node) + { errno = ec; return -1; } @@ -85,10 +90,10 @@ epoll_create_common(void) return node->fd; } -int -epoll_create(int size) +int epoll_create(int size) { - if (size <= 0) { + if (size <= 0) + { errno = EINVAL; return -1; } @@ -96,10 +101,10 @@ epoll_create(int size) return epoll_create_common(); } -int -epoll_create1(int flags) +int epoll_create1(int flags) { - if (flags & ~EPOLL_CLOEXEC) { + if (flags & ~EPOLL_CLOEXEC) + { errno = EINVAL; return -1; } @@ -110,12 +115,14 @@ epoll_create1(int flags) static errno_t epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev) { - if (!ev && op != EPOLL_CTL_DEL) { + if (!ev && op != EPOLL_CTL_DEL) + { return EFAULT; } FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd); - if (!node || node->vtable != &epollfd_vtable) { + if (!node || node->vtable != &epollfd_vtable) + { struct stat sb; return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL; } @@ -123,11 +130,11 @@ epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev) return epollfd_ctx_ctl(&node->ctx.epollfd, op, fd2, ev); } -int -epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev) +int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev) { errno_t ec = epoll_ctl_impl(fd, op, fd2, ev); - if (ec != 0) { + if (ec != 0) + { errno = ec; return -1; } @@ -143,33 +150,39 @@ is_no_wait_deadline(struct timespec const *deadline) static errno_t epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, - int *actual_cnt, struct timespec const *deadline, sigset_t const *sigs) + int *actual_cnt, struct timespec const *deadline, sigset_t const *sigs) { errno_t ec; - for (;;) { + for (;;) + { if ((ec = epollfd_ctx_wait(epollfd, /**/ - ev, cnt, actual_cnt)) != 0) { + ev, cnt, actual_cnt)) != 0) + { return ec; } - if (*actual_cnt || is_no_wait_deadline(deadline)) { + if (*actual_cnt || is_no_wait_deadline(deadline)) + { return 0; } struct timespec timeout; - if (deadline) { + if (deadline) + { struct timespec current_time; if (clock_gettime(CLOCK_MONOTONIC, /**/ - ¤t_time) < 0) { + ¤t_time) < 0) + { return errno; } timespecsub(deadline, ¤t_time, &timeout); if (timeout.tv_sec < 0 || - is_no_wait_deadline(&timeout)) { + is_no_wait_deadline(&timeout)) + { return 0; } } @@ -180,14 +193,16 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, size_t size; if (__builtin_mul_overflow(nfds, sizeof(struct pollfd), - &size)) { + &size)) + { ec = ENOMEM; (void)pthread_mutex_unlock(&epollfd->mutex); return ec; } struct pollfd *pfds = malloc(size); - if (!pfds) { + if (!pfds) + { ec = errno; (void)pthread_mutex_unlock(&epollfd->mutex); return ec; @@ -211,7 +226,8 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, #endif int n = ppoll(pfds, nfds, deadline ? &timeout : NULL, sigs); - if (n < 0) { + if (n < 0) + { ec = errno; } @@ -219,13 +235,15 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, (void)pthread_mutex_lock(&epollfd->nr_polling_threads_mutex); --epollfd->nr_polling_threads; - if (epollfd->nr_polling_threads == 0) { + if (epollfd->nr_polling_threads == 0) + { (void)pthread_cond_signal( - &epollfd->nr_polling_threads_cond); + &epollfd->nr_polling_threads_cond); } (void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex); - if (n < 0) { + if (n < 0) + { return ec; } } @@ -236,21 +254,27 @@ timeout_to_deadline(struct timespec *deadline, int to) { assert(to >= 0); - if (to == 0) { + if (to == 0) + { *deadline = (struct timespec){0, 0}; - } else if (to > 0) { - if (clock_gettime(CLOCK_MONOTONIC, deadline) < 0) { + } + else if (to > 0) + { + if (clock_gettime(CLOCK_MONOTONIC, deadline) < 0) + { return errno; } if (__builtin_add_overflow(deadline->tv_sec, to / 1000 + 1, - &deadline->tv_sec)) { + &deadline->tv_sec)) + { return EINVAL; } deadline->tv_sec -= 1; deadline->tv_nsec += (to % 1000) * 1000000L; - if (deadline->tv_nsec >= 1000000000) { + if (deadline->tv_nsec >= 1000000000) + { deadline->tv_nsec -= 1000000000; deadline->tv_sec += 1; } @@ -261,36 +285,39 @@ timeout_to_deadline(struct timespec *deadline, int to) static errno_t epoll_pwait_impl(int fd, struct epoll_event *ev, int cnt, int to, - sigset_t const *sigs, int *actual_cnt) + sigset_t const *sigs, int *actual_cnt) { - if (cnt < 1 || cnt > (int)(INT_MAX / sizeof(struct epoll_event))) { + if (cnt < 1 || cnt > (int)(INT_MAX / sizeof(struct epoll_event))) + { return EINVAL; } FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd); - if (!node || node->vtable != &epollfd_vtable) { + if (!node || node->vtable != &epollfd_vtable) + { struct stat sb; return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL; } struct timespec deadline; errno_t ec; - if (to >= 0 && (ec = timeout_to_deadline(&deadline, to)) != 0) { + if (to >= 0 && (ec = timeout_to_deadline(&deadline, to)) != 0) + { return ec; } return epollfd_ctx_wait_or_block(&node->ctx.epollfd, ev, cnt, - actual_cnt, (to >= 0) ? &deadline : NULL, sigs); + actual_cnt, (to >= 0) ? &deadline : NULL, sigs); } -int -epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, - sigset_t const *sigs) +int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, + sigset_t const *sigs) { int actual_cnt; errno_t ec = epoll_pwait_impl(fd, ev, cnt, to, sigs, &actual_cnt); - if (ec != 0) { + if (ec != 0) + { errno = ec; return -1; } @@ -298,8 +325,7 @@ epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, return actual_cnt; } -int -epoll_wait(int fd, struct epoll_event *ev, int cnt, int to) +int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to) { return epoll_pwait(fd, ev, cnt, to, NULL); } diff --git a/tpws/epoll-shim/src/epoll_shim_ctx.c b/tpws/epoll-shim/src/epoll_shim_ctx.c index ac89f5f..a9e5cf4 100644 --- a/tpws/epoll-shim/src/epoll_shim_ctx.c +++ b/tpws/epoll-shim/src/epoll_shim_ctx.c @@ -20,7 +20,8 @@ fd_context_map_node_create(int kq, errno_t *ec) FDContextMapNode *node; node = malloc(sizeof(FDContextMapNode)); - if (!node) { + if (!node) + { *ec = errno; return NULL; } @@ -34,7 +35,8 @@ fd_context_map_node_terminate(FDContextMapNode *node, bool close_fd) { errno_t ec = node->vtable ? node->vtable->close_fun(node) : 0; - if (close_fd && close(node->fd) < 0) { + if (close_fd && close(node->fd) < 0) + { ec = ec ? ec : errno; } @@ -53,7 +55,7 @@ fd_context_map_node_destroy(FDContextMapNode *node) errno_t fd_context_default_read(FDContextMapNode *node, /**/ - void *buf, size_t nbytes, size_t *bytes_transferred) + void *buf, size_t nbytes, size_t *bytes_transferred) { (void)node; (void)buf; @@ -65,7 +67,7 @@ fd_context_default_read(FDContextMapNode *node, /**/ errno_t fd_context_default_write(FDContextMapNode *node, /**/ - void const *buf, size_t nbytes, size_t *bytes_transferred) + void const *buf, size_t nbytes, size_t *bytes_transferred) { (void)node; (void)buf; @@ -84,18 +86,18 @@ fd_context_map_node_cmp(FDContextMapNode *e1, FDContextMapNode *e2) } RB_PROTOTYPE_STATIC(fd_context_map_, fd_context_map_node_, entry, - fd_context_map_node_cmp); + fd_context_map_node_cmp); RB_GENERATE_STATIC(fd_context_map_, fd_context_map_node_, entry, - fd_context_map_node_cmp); + fd_context_map_node_cmp); EpollShimCtx epoll_shim_ctx = { - .fd_context_map = RB_INITIALIZER(&fd_context_map), - .mutex = PTHREAD_MUTEX_INITIALIZER, + .fd_context_map = RB_INITIALIZER(&fd_context_map), + .mutex = PTHREAD_MUTEX_INITIALIZER, }; static FDContextMapNode * epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq, - errno_t *ec) + errno_t *ec) { FDContextMapNode *node; @@ -104,10 +106,11 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq, find.fd = kq; node = RB_FIND(fd_context_map_, /**/ - &epoll_shim_ctx->fd_context_map, &find); + &epoll_shim_ctx->fd_context_map, &find); } - if (node) { + if (node) + { /* * If we get here, someone must have already closed the old fd * with a normal 'close()' call, i.e. not with our @@ -118,14 +121,17 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq, */ (void)fd_context_map_node_terminate(node, false); fd_context_map_node_init(node, kq); - } else { + } + else + { node = fd_context_map_node_create(kq, ec); - if (!node) { + if (!node) + { return NULL; } void *colliding_node = RB_INSERT(fd_context_map_, - &epoll_shim_ctx->fd_context_map, node); + &epoll_shim_ctx->fd_context_map, node); (void)colliding_node; assert(colliding_node == NULL); } @@ -139,7 +145,8 @@ epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec) FDContextMapNode *node; int kq = kqueue(); - if (kq < 0) { + if (kq < 0) + { *ec = errno; return NULL; } @@ -148,7 +155,8 @@ epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec) node = epoll_shim_ctx_create_node_impl(epoll_shim_ctx, kq, ec); (void)pthread_mutex_unlock(&epoll_shim_ctx->mutex); - if (!node) { + if (!node) + { close(kq); } @@ -164,7 +172,7 @@ epoll_shim_ctx_find_node_impl(EpollShimCtx *epoll_shim_ctx, int fd) find.fd = fd; node = RB_FIND(fd_context_map_, /**/ - &epoll_shim_ctx->fd_context_map, &find); + &epoll_shim_ctx->fd_context_map, &find); return node; } @@ -188,39 +196,40 @@ epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, int fd) (void)pthread_mutex_lock(&epoll_shim_ctx->mutex); node = epoll_shim_ctx_find_node_impl(epoll_shim_ctx, fd); - if (node) { + if (node) + { RB_REMOVE(fd_context_map_, /**/ - &epoll_shim_ctx->fd_context_map, node); + &epoll_shim_ctx->fd_context_map, node); } (void)pthread_mutex_unlock(&epoll_shim_ctx->mutex); return node; } -void -epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx, - FDContextMapNode *node) +void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx, + FDContextMapNode *node) { (void)pthread_mutex_lock(&epoll_shim_ctx->mutex); RB_REMOVE(fd_context_map_, /**/ - &epoll_shim_ctx->fd_context_map, node); + &epoll_shim_ctx->fd_context_map, node); (void)pthread_mutex_unlock(&epoll_shim_ctx->mutex); } /**/ -int -epoll_shim_close(int fd) +int epoll_shim_close(int fd) { FDContextMapNode *node; node = epoll_shim_ctx_remove_node(&epoll_shim_ctx, fd); - if (!node) { + if (!node) + { return close(fd); } errno_t ec = fd_context_map_node_destroy(node); - if (ec != 0) { + if (ec != 0) + { errno = ec; return -1; } @@ -234,19 +243,22 @@ epoll_shim_read(int fd, void *buf, size_t nbytes) FDContextMapNode *node; node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd); - if (!node) { + if (!node) + { return read(fd, buf, nbytes); } - if (nbytes > SSIZE_MAX) { + if (nbytes > SSIZE_MAX) + { errno = EINVAL; return -1; } size_t bytes_transferred; errno_t ec = node->vtable->read_fun(node, /**/ - buf, nbytes, &bytes_transferred); - if (ec != 0) { + buf, nbytes, &bytes_transferred); + if (ec != 0) + { errno = ec; return -1; } @@ -260,19 +272,22 @@ epoll_shim_write(int fd, void const *buf, size_t nbytes) FDContextMapNode *node; node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd); - if (!node) { + if (!node) + { return write(fd, buf, nbytes); } - if (nbytes > SSIZE_MAX) { + if (nbytes > SSIZE_MAX) + { errno = EINVAL; return -1; } size_t bytes_transferred; errno_t ec = node->vtable->write_fun(node, /**/ - buf, nbytes, &bytes_transferred); - if (ec != 0) { + buf, nbytes, &bytes_transferred); + if (ec != 0) + { errno = ec; return -1; } diff --git a/tpws/epoll-shim/src/epoll_shim_ctx.h b/tpws/epoll-shim/src/epoll_shim_ctx.h index 01ae19a..39726b3 100644 --- a/tpws/epoll-shim/src/epoll_shim_ctx.h +++ b/tpws/epoll-shim/src/epoll_shim_ctx.h @@ -16,27 +16,31 @@ struct fd_context_map_node_; typedef struct fd_context_map_node_ FDContextMapNode; typedef errno_t (*fd_context_read_fun)(FDContextMapNode *node, /**/ - void *buf, size_t nbytes, size_t *bytes_transferred); + void *buf, size_t nbytes, size_t *bytes_transferred); typedef errno_t (*fd_context_write_fun)(FDContextMapNode *node, /**/ - const void *buf, size_t nbytes, size_t *bytes_transferred); + const void *buf, size_t nbytes, size_t *bytes_transferred); typedef errno_t (*fd_context_close_fun)(FDContextMapNode *node); -typedef struct { +typedef struct +{ fd_context_read_fun read_fun; fd_context_write_fun write_fun; fd_context_close_fun close_fun; } FDContextVTable; errno_t fd_context_default_read(FDContextMapNode *node, /**/ - void *buf, size_t nbytes, size_t *bytes_transferred); + void *buf, size_t nbytes, size_t *bytes_transferred); errno_t fd_context_default_write(FDContextMapNode *node, /**/ - void const *buf, size_t nbytes, size_t *bytes_transferred); + void const *buf, size_t nbytes, size_t *bytes_transferred); -struct fd_context_map_node_ { - RB_ENTRY(fd_context_map_node_) entry; +struct fd_context_map_node_ +{ + RB_ENTRY(fd_context_map_node_) + entry; int fd; int flags; - union { + union + { EpollFDCtx epollfd; EventFDCtx eventfd; TimerFDCtx timerfd; @@ -51,7 +55,8 @@ errno_t fd_context_map_node_destroy(FDContextMapNode *node); typedef RB_HEAD(fd_context_map_, fd_context_map_node_) FDContextMap; -typedef struct { +typedef struct +{ FDContextMap fd_context_map; pthread_mutex_t mutex; } EpollShimCtx; @@ -59,13 +64,13 @@ typedef struct { extern EpollShimCtx epoll_shim_ctx; FDContextMapNode *epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, - errno_t *ec); + errno_t *ec); FDContextMapNode *epoll_shim_ctx_find_node(EpollShimCtx *epoll_shim_ctx, - int fd); + int fd); FDContextMapNode *epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, - int fd); + int fd); void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx, - FDContextMapNode *node); + FDContextMapNode *node); /**/ diff --git a/tpws/epoll-shim/src/epollfd_ctx.c b/tpws/epoll-shim/src/epollfd_ctx.c index baf3dc2..592b3fb 100644 --- a/tpws/epoll-shim/src/epollfd_ctx.c +++ b/tpws/epoll-shim/src/epollfd_ctx.c @@ -31,7 +31,8 @@ registered_fds_node_create(int fd) RegisteredFDsNode *node; node = malloc(sizeof(*node)); - if (!node) { + if (!node) + { return NULL; } @@ -43,7 +44,8 @@ registered_fds_node_create(int fd) static void registered_fds_node_destroy(RegisteredFDsNode *node) { - if (node->self_pipe[0] >= 0 && node->self_pipe[1] >= 0) { + if (node->self_pipe[0] >= 0 && node->self_pipe[1] >= 0) + { (void)close(node->self_pipe[0]); (void)close(node->self_pipe[1]); } @@ -51,7 +53,8 @@ registered_fds_node_destroy(RegisteredFDsNode *node) free(node); } -typedef struct { +typedef struct +{ int evfilt_read; int evfilt_write; int evfilt_except; @@ -64,76 +67,91 @@ get_needed_filters(RegisteredFDsNode *fd2_node) needed_filters.evfilt_except = 0; - if (fd2_node->node_type == NODE_TYPE_FIFO) { + if (fd2_node->node_type == NODE_TYPE_FIFO) + { if (fd2_node->node_data.fifo.readable && - fd2_node->node_data.fifo.writable) { + fd2_node->node_data.fifo.writable) + { needed_filters.evfilt_read = !!( - fd2_node->events & EPOLLIN); + fd2_node->events & EPOLLIN); needed_filters.evfilt_write = !!( - fd2_node->events & EPOLLOUT); + fd2_node->events & EPOLLOUT); - if (fd2_node->events == 0) { + if (fd2_node->events == 0) + { needed_filters.evfilt_read = - fd2_node->eof_state ? 1 : EV_CLEAR; + fd2_node->eof_state ? 1 : EV_CLEAR; } - - } else if (fd2_node->node_data.fifo.readable) { + } + else if (fd2_node->node_data.fifo.readable) + { needed_filters.evfilt_read = !!( - fd2_node->events & EPOLLIN); + fd2_node->events & EPOLLIN); needed_filters.evfilt_write = 0; - if (needed_filters.evfilt_read == 0) { + if (needed_filters.evfilt_read == 0) + { needed_filters.evfilt_read = - fd2_node->eof_state ? 1 : EV_CLEAR; + fd2_node->eof_state ? 1 : EV_CLEAR; } - } else if (fd2_node->node_data.fifo.writable) { + } + else if (fd2_node->node_data.fifo.writable) + { needed_filters.evfilt_read = 0; needed_filters.evfilt_write = !!( - fd2_node->events & EPOLLOUT); + fd2_node->events & EPOLLOUT); - if (needed_filters.evfilt_write == 0) { + if (needed_filters.evfilt_write == 0) + { needed_filters.evfilt_write = - fd2_node->eof_state ? 1 : EV_CLEAR; + fd2_node->eof_state ? 1 : EV_CLEAR; } - } else { + } + else + { __builtin_unreachable(); } goto out; } - if (fd2_node->node_type == NODE_TYPE_KQUEUE) { + if (fd2_node->node_type == NODE_TYPE_KQUEUE) + { needed_filters.evfilt_read = !!(fd2_node->events & EPOLLIN); needed_filters.evfilt_write = 0; assert(fd2_node->eof_state == 0); - if (needed_filters.evfilt_read == 0) { + if (needed_filters.evfilt_read == 0) + { needed_filters.evfilt_read = EV_CLEAR; } goto out; } - if (fd2_node->node_type == NODE_TYPE_SOCKET) { + if (fd2_node->node_type == NODE_TYPE_SOCKET) + { needed_filters.evfilt_read = !!(fd2_node->events & EPOLLIN); if (needed_filters.evfilt_read == 0 && - (fd2_node->events & EPOLLRDHUP)) { + (fd2_node->events & EPOLLRDHUP)) + { needed_filters.evfilt_read = (fd2_node->eof_state & - EOF_STATE_READ_EOF) - ? 1 - : EV_CLEAR; + EOF_STATE_READ_EOF) + ? 1 + : EV_CLEAR; } #ifdef EVFILT_EXCEPT needed_filters.evfilt_except = !!(fd2_node->events & EPOLLPRI); #else if (needed_filters.evfilt_read == 0 && - (fd2_node->events & EPOLLPRI)) { + (fd2_node->events & EPOLLPRI)) + { needed_filters.evfilt_read = fd2_node->pollpri_active - ? 1 - : EV_CLEAR; + ? 1 + : EV_CLEAR; } #endif @@ -141,34 +159,44 @@ get_needed_filters(RegisteredFDsNode *fd2_node) /* Let's use EVFILT_READ to drive the POLLHUP. */ if (fd2_node->eof_state == - (EOF_STATE_READ_EOF | EOF_STATE_WRITE_EOF)) { + (EOF_STATE_READ_EOF | EOF_STATE_WRITE_EOF)) + { if (needed_filters.evfilt_read != 1 && - needed_filters.evfilt_write != 1) { + needed_filters.evfilt_write != 1) + { needed_filters.evfilt_read = 1; } - if (needed_filters.evfilt_read) { + if (needed_filters.evfilt_read) + { needed_filters.evfilt_write = 0; - } else { + } + else + { needed_filters.evfilt_read = 0; } } /* We need something to detect POLLHUP. */ if (fd2_node->eof_state == 0 && - needed_filters.evfilt_read == 0 && - needed_filters.evfilt_write == 0) { + needed_filters.evfilt_read == 0 && + needed_filters.evfilt_write == 0) + { needed_filters.evfilt_read = EV_CLEAR; } - if (fd2_node->eof_state == EOF_STATE_READ_EOF) { - if (needed_filters.evfilt_write == 0) { + if (fd2_node->eof_state == EOF_STATE_READ_EOF) + { + if (needed_filters.evfilt_write == 0) + { needed_filters.evfilt_write = EV_CLEAR; } } - if (fd2_node->eof_state == EOF_STATE_WRITE_EOF) { - if (needed_filters.evfilt_read == 0) { + if (fd2_node->eof_state == EOF_STATE_WRITE_EOF) + { + if (needed_filters.evfilt_read == 0) + { needed_filters.evfilt_read = EV_CLEAR; } } @@ -179,65 +207,73 @@ get_needed_filters(RegisteredFDsNode *fd2_node) needed_filters.evfilt_read = !!(fd2_node->events & EPOLLIN); needed_filters.evfilt_write = !!(fd2_node->events & EPOLLOUT); - if (fd2_node->events == 0) { + if (fd2_node->events == 0) + { needed_filters.evfilt_read = fd2_node->eof_state ? 1 - : EV_CLEAR; + : EV_CLEAR; } out: - if (fd2_node->is_edge_triggered) { - if (needed_filters.evfilt_read) { + if (fd2_node->is_edge_triggered) + { + if (needed_filters.evfilt_read) + { needed_filters.evfilt_read = EV_CLEAR; } - if (needed_filters.evfilt_write) { + if (needed_filters.evfilt_write) + { needed_filters.evfilt_write = EV_CLEAR; } - if (needed_filters.evfilt_except) { + if (needed_filters.evfilt_except) + { needed_filters.evfilt_except = EV_CLEAR; } } assert(needed_filters.evfilt_read || needed_filters.evfilt_write); assert(needed_filters.evfilt_read == 0 || - needed_filters.evfilt_read == 1 || - needed_filters.evfilt_read == EV_CLEAR); + needed_filters.evfilt_read == 1 || + needed_filters.evfilt_read == EV_CLEAR); assert(needed_filters.evfilt_write == 0 || - needed_filters.evfilt_write == 1 || - needed_filters.evfilt_write == EV_CLEAR); + needed_filters.evfilt_write == 1 || + needed_filters.evfilt_write == EV_CLEAR); assert(needed_filters.evfilt_except == 0 || - needed_filters.evfilt_except == 1 || - needed_filters.evfilt_except == EV_CLEAR); + needed_filters.evfilt_except == 1 || + needed_filters.evfilt_except == EV_CLEAR); return needed_filters; } static void registered_fds_node_update_flags_from_epoll_event(RegisteredFDsNode *fd2_node, - struct epoll_event *ev) + struct epoll_event *ev) { fd2_node->events = ev->events & - (EPOLLIN | EPOLLPRI | EPOLLRDHUP | EPOLLOUT); + (EPOLLIN | EPOLLPRI | EPOLLRDHUP | EPOLLOUT); fd2_node->data = ev->data; fd2_node->is_edge_triggered = ev->events & EPOLLET; fd2_node->is_oneshot = ev->events & EPOLLONESHOT; - if (fd2_node->is_oneshot) { + if (fd2_node->is_oneshot) + { fd2_node->is_edge_triggered = true; } } static errno_t registered_fds_node_add_self_trigger(RegisteredFDsNode *fd2_node, - EpollFDCtx *epollfd) + EpollFDCtx *epollfd) { struct kevent kevs[1]; #ifdef EVFILT_USER EV_SET(&kevs[0], (uintptr_t)fd2_node, EVFILT_USER, /**/ - EV_ADD | EV_CLEAR, 0, 0, fd2_node); + EV_ADD | EV_CLEAR, 0, 0, fd2_node); #else - if (fd2_node->self_pipe[0] < 0 && fd2_node->self_pipe[1] < 0) { - if (pipe2(fd2_node->self_pipe, O_NONBLOCK | O_CLOEXEC) < 0) { + if (fd2_node->self_pipe[0] < 0 && fd2_node->self_pipe[1] < 0) + { + if (pipe2(fd2_node->self_pipe, O_NONBLOCK | O_CLOEXEC) < 0) + { errno_t ec = errno; fd2_node->self_pipe[0] = fd2_node->self_pipe[1] = -1; return ec; @@ -248,10 +284,11 @@ registered_fds_node_add_self_trigger(RegisteredFDsNode *fd2_node, } EV_SET(&kevs[0], fd2_node->self_pipe[0], EVFILT_READ, /**/ - EV_ADD | EV_CLEAR, 0, 0, fd2_node); + EV_ADD | EV_CLEAR, 0, 0, fd2_node); #endif - if (kevent(epollfd->kq, kevs, 1, NULL, 0, NULL) < 0) { + if (kevent(epollfd->kq, kevs, 1, NULL, 0, NULL) < 0) + { return errno; } @@ -260,12 +297,12 @@ registered_fds_node_add_self_trigger(RegisteredFDsNode *fd2_node, static void registered_fds_node_trigger_self(RegisteredFDsNode *fd2_node, - EpollFDCtx *epollfd) + EpollFDCtx *epollfd) { #ifdef EVFILT_USER struct kevent kevs[1]; EV_SET(&kevs[0], (uintptr_t)fd2_node, EVFILT_USER, /**/ - 0, NOTE_TRIGGER, 0, fd2_node); + 0, NOTE_TRIGGER, 0, fd2_node); (void)kevent(epollfd->kq, kevs, 1, NULL, 0, NULL); #else (void)epollfd; @@ -278,42 +315,45 @@ registered_fds_node_trigger_self(RegisteredFDsNode *fd2_node, static void registered_fds_node_feed_event(RegisteredFDsNode *fd2_node, - EpollFDCtx *epollfd, struct kevent const *kev) + EpollFDCtx *epollfd, struct kevent const *kev) { int revents = 0; - if (fd2_node->node_type == NODE_TYPE_POLL) { + if (fd2_node->node_type == NODE_TYPE_POLL) + { assert(fd2_node->revents == 0); #ifdef EVFILT_USER assert(kev->filter == EVFILT_USER); #else char c[32]; - while (read(fd2_node->self_pipe[0], c, sizeof(c)) >= 0) { + while (read(fd2_node->self_pipe[0], c, sizeof(c)) >= 0) + { } #endif struct pollfd pfd = { - .fd = fd2_node->fd, - .events = (short)fd2_node->events, + .fd = fd2_node->fd, + .events = (short)fd2_node->events, }; revents = poll(&pfd, 1, 0) < 0 ? EPOLLERR : pfd.revents; fd2_node->revents = revents & POLLNVAL ? 0 : (uint32_t)revents; assert(!(fd2_node->revents & - ~(uint32_t)(POLLIN | POLLOUT | POLLERR | POLLHUP))); + ~(uint32_t)(POLLIN | POLLOUT | POLLERR | POLLHUP))); return; } if (fd2_node->node_type == NODE_TYPE_FIFO && #ifdef EVFILT_USER - kev->filter == EVFILT_USER + kev->filter == EVFILT_USER #else - (fd2_node->self_pipe[0] >= 0 && - kev->ident == (uintptr_t)fd2_node->self_pipe[0]) + (fd2_node->self_pipe[0] >= 0 && + kev->ident == (uintptr_t)fd2_node->self_pipe[0]) #endif - ) { + ) + { assert(fd2_node->revents == 0); assert(!fd2_node->has_evfilt_read); @@ -325,21 +365,25 @@ registered_fds_node_feed_event(RegisteredFDsNode *fd2_node, struct kevent nkev[1]; EV_SET(&nkev[0], fd2_node->fd, EVFILT_WRITE, - EV_ADD | (needed_filters.evfilt_write & EV_CLEAR) | - EV_RECEIPT, - 0, 0, fd2_node); + EV_ADD | (needed_filters.evfilt_write & EV_CLEAR) | + EV_RECEIPT, + 0, 0, fd2_node); if (kevent(epollfd->kq, nkev, 1, nkev, 1, NULL) != 1 || - nkev[0].data != 0) { + nkev[0].data != 0) + { revents = EPOLLERR | EPOLLOUT; - if (!fd2_node->is_edge_triggered) { + if (!fd2_node->is_edge_triggered) + { registered_fds_node_trigger_self(fd2_node, - epollfd); + epollfd); } goto out; - } else { + } + else + { fd2_node->has_evfilt_write = true; return; } @@ -347,35 +391,43 @@ registered_fds_node_feed_event(RegisteredFDsNode *fd2_node, #ifdef EVFILT_EXCEPT assert(kev->filter == EVFILT_READ || kev->filter == EVFILT_WRITE || - kev->filter == EVFILT_EXCEPT); + kev->filter == EVFILT_EXCEPT); #else assert(kev->filter == EVFILT_READ || kev->filter == EVFILT_WRITE); #endif assert((int)kev->ident == fd2_node->fd); - if (kev->filter == EVFILT_READ) { + if (kev->filter == EVFILT_READ) + { revents |= EPOLLIN; #ifndef EVFILT_EXCEPT - if (fd2_node->events & EPOLLPRI) { + if (fd2_node->events & EPOLLPRI) + { struct pollfd pfd = { - .fd = fd2_node->fd, - .events = POLLPRI, + .fd = fd2_node->fd, + .events = POLLPRI, }; if ((poll(&pfd, 1, 0) == 1) && - (pfd.revents & POLLPRI)) { + (pfd.revents & POLLPRI)) + { revents |= EPOLLPRI; fd2_node->pollpri_active = true; - } else { + } + else + { fd2_node->pollpri_active = false; } } #endif - } else if (kev->filter == EVFILT_WRITE) { + } + else if (kev->filter == EVFILT_WRITE) + { revents |= EPOLLOUT; } #ifdef EVFILT_EXCEPT - else if (kev->filter == EVFILT_EXCEPT) { + else if (kev->filter == EVFILT_EXCEPT) + { assert((kev->fflags & NOTE_OOB) != 0); revents |= EPOLLPRI; @@ -383,63 +435,94 @@ registered_fds_node_feed_event(RegisteredFDsNode *fd2_node, } #endif - if (fd2_node->node_type == NODE_TYPE_SOCKET) { - if (kev->filter == EVFILT_READ) { - if (kev->flags & EV_EOF) { + if (fd2_node->node_type == NODE_TYPE_SOCKET) + { + if (kev->filter == EVFILT_READ) + { + if (kev->flags & EV_EOF) + { fd2_node->eof_state |= EOF_STATE_READ_EOF; - } else { + } + else + { fd2_node->eof_state &= ~EOF_STATE_READ_EOF; } - } else if (kev->filter == EVFILT_WRITE) { - if (kev->flags & EV_EOF) { + } + else if (kev->filter == EVFILT_WRITE) + { + if (kev->flags & EV_EOF) + { fd2_node->eof_state |= EOF_STATE_WRITE_EOF; - } else { + } + else + { fd2_node->eof_state &= ~EOF_STATE_WRITE_EOF; } } - } else { - if (kev->filter == EVFILT_READ) { - if (kev->flags & EV_EOF) { + } + else + { + if (kev->filter == EVFILT_READ) + { + if (kev->flags & EV_EOF) + { fd2_node->eof_state = EOF_STATE_READ_EOF | - EOF_STATE_WRITE_EOF; - } else { + EOF_STATE_WRITE_EOF; + } + else + { fd2_node->eof_state = 0; } - } else if (kev->filter == EVFILT_WRITE) { - if (kev->flags & EV_EOF) { + } + else if (kev->filter == EVFILT_WRITE) + { + if (kev->flags & EV_EOF) + { fd2_node->eof_state = EOF_STATE_READ_EOF | - EOF_STATE_WRITE_EOF; - } else { + EOF_STATE_WRITE_EOF; + } + else + { fd2_node->eof_state = 0; } } } - if (kev->flags & EV_ERROR) { + if (kev->flags & EV_ERROR) + { revents |= EPOLLERR; } - if (kev->flags & EV_EOF) { - if (kev->fflags) { + if (kev->flags & EV_EOF) + { + if (kev->fflags) + { revents |= EPOLLERR; } } - if (fd2_node->eof_state) { + if (fd2_node->eof_state) + { int epoll_event; - if (fd2_node->node_type == NODE_TYPE_FIFO) { - if (kev->filter == EVFILT_READ) { + if (fd2_node->node_type == NODE_TYPE_FIFO) + { + if (kev->filter == EVFILT_READ) + { epoll_event = EPOLLHUP; - if (kev->data == 0) { + if (kev->data == 0) + { revents &= ~EPOLLIN; } - } else if (kev->filter == EVFILT_WRITE) { - if (fd2_node->has_evfilt_read) { + } + else if (kev->filter == EVFILT_WRITE) + { + if (fd2_node->has_evfilt_read) + { assert( - fd2_node->node_data.fifo.readable); + fd2_node->node_data.fifo.readable); assert( - fd2_node->node_data.fifo.writable); + fd2_node->node_data.fifo.writable); /* * Any non-zero revents must have come @@ -457,35 +540,46 @@ registered_fds_node_feed_event(RegisteredFDsNode *fd2_node, * (which will be EOF). */ - if (fd2_node->revents != 0) { + if (fd2_node->revents != 0) + { fd2_node->revents |= POLLHUP; } return; } epoll_event = EPOLLERR; - if (kev->data < PIPE_BUF) { + if (kev->data < PIPE_BUF) + { revents &= ~EPOLLOUT; } - } else { + } + else + { __builtin_unreachable(); } - } else if (fd2_node->node_type == NODE_TYPE_SOCKET) { + } + else if (fd2_node->node_type == NODE_TYPE_SOCKET) + { epoll_event = 0; - if (fd2_node->eof_state & EOF_STATE_READ_EOF) { + if (fd2_node->eof_state & EOF_STATE_READ_EOF) + { epoll_event |= EPOLLIN | EPOLLRDHUP; } - if (fd2_node->eof_state & EOF_STATE_WRITE_EOF) { + if (fd2_node->eof_state & EOF_STATE_WRITE_EOF) + { epoll_event |= EPOLLOUT; } if (fd2_node->eof_state == - (EOF_STATE_READ_EOF | EOF_STATE_WRITE_EOF)) { + (EOF_STATE_READ_EOF | EOF_STATE_WRITE_EOF)) + { epoll_event |= EPOLLHUP; } - } else { + } + else + { epoll_event = EPOLLHUP; } @@ -496,14 +590,19 @@ out: fd2_node->revents |= (uint32_t)revents; fd2_node->revents &= (fd2_node->events | EPOLLHUP | EPOLLERR); - if (fd2_node->revents && (uintptr_t)fd2_node->fd == kev->ident) { - if (kev->filter == EVFILT_READ) { + if (fd2_node->revents && (uintptr_t)fd2_node->fd == kev->ident) + { + if (kev->filter == EVFILT_READ) + { fd2_node->got_evfilt_read = true; - } else if (kev->filter == EVFILT_WRITE) { + } + else if (kev->filter == EVFILT_WRITE) + { fd2_node->got_evfilt_write = true; } #ifdef EVFILT_EXCEPT - else if (kev->filter == EVFILT_EXCEPT) { + else if (kev->filter == EVFILT_EXCEPT) + { fd2_node->got_evfilt_except = true; } #endif @@ -512,37 +611,43 @@ out: static void registered_fds_node_register_for_completion(int *kq, - RegisteredFDsNode *fd2_node) + RegisteredFDsNode *fd2_node) { struct kevent kev[3]; int n = 0; - if (fd2_node->has_evfilt_read && !fd2_node->got_evfilt_read) { + if (fd2_node->has_evfilt_read && !fd2_node->got_evfilt_read) + { EV_SET(&kev[n++], fd2_node->fd, EVFILT_READ, - EV_ADD | EV_ONESHOT | EV_RECEIPT, 0, 0, fd2_node); + EV_ADD | EV_ONESHOT | EV_RECEIPT, 0, 0, fd2_node); } - if (fd2_node->has_evfilt_write && !fd2_node->got_evfilt_write) { + if (fd2_node->has_evfilt_write && !fd2_node->got_evfilt_write) + { EV_SET(&kev[n++], fd2_node->fd, EVFILT_WRITE, - EV_ADD | EV_ONESHOT | EV_RECEIPT, 0, 0, fd2_node); + EV_ADD | EV_ONESHOT | EV_RECEIPT, 0, 0, fd2_node); } - if (fd2_node->has_evfilt_except && !fd2_node->got_evfilt_except) { + if (fd2_node->has_evfilt_except && !fd2_node->got_evfilt_except) + { #ifdef EVFILT_EXCEPT EV_SET(&kev[n++], fd2_node->fd, EVFILT_EXCEPT, - EV_ADD | EV_ONESHOT | EV_RECEIPT, NOTE_OOB, 0, fd2_node); + EV_ADD | EV_ONESHOT | EV_RECEIPT, NOTE_OOB, 0, fd2_node); #else assert(0); #endif } - if (n == 0) { + if (n == 0) + { return; } - if (*kq < 0) { + if (*kq < 0) + { *kq = kqueue(); } - if (*kq >= 0) { + if (*kq >= 0) + { (void)kevent(*kq, kev, n, kev, n, NULL); } } @@ -550,7 +655,8 @@ registered_fds_node_register_for_completion(int *kq, static void registered_fds_node_complete(int kq) { - if (kq < 0) { + if (kq < 0) + { return; } @@ -558,13 +664,15 @@ registered_fds_node_complete(int kq) int n; while ((n = kevent(kq, /**/ - NULL, 0, kevs, 32, &(struct timespec){0, 0})) > 0) { - for (int i = 0; i < n; ++i) { + NULL, 0, kevs, 32, &(struct timespec){0, 0})) > 0) + { + for (int i = 0; i < n; ++i) + { RegisteredFDsNode *fd2_node = - (RegisteredFDsNode *)kevs[i].udata; + (RegisteredFDsNode *)kevs[i].udata; registered_fds_node_feed_event(fd2_node, NULL, - &kevs[i]); + &kevs[i]); } } @@ -586,25 +694,28 @@ epollfd_ctx_init(EpollFDCtx *epollfd, int kq) errno_t ec; *epollfd = (EpollFDCtx){ - .kq = kq, - .registered_fds = RB_INITIALIZER(®istered_fds), - .self_pipe = {-1, -1}, + .kq = kq, + .registered_fds = RB_INITIALIZER(®istered_fds), + .self_pipe = {-1, -1}, }; TAILQ_INIT(&epollfd->poll_fds); - if ((ec = pthread_mutex_init(&epollfd->mutex, NULL)) != 0) { + if ((ec = pthread_mutex_init(&epollfd->mutex, NULL)) != 0) + { return ec; } if ((ec = pthread_mutex_init(&epollfd->nr_polling_threads_mutex, - NULL)) != 0) { + NULL)) != 0) + { pthread_mutex_destroy(&epollfd->mutex); return ec; } if ((ec = pthread_cond_init(&epollfd->nr_polling_threads_cond, - NULL)) != 0) { + NULL)) != 0) + { pthread_mutex_destroy(&epollfd->nr_polling_threads_mutex); pthread_mutex_destroy(&epollfd->mutex); return ec; @@ -629,7 +740,7 @@ epollfd_ctx_terminate(EpollFDCtx *epollfd) RegisteredFDsNode *np; RegisteredFDsNode *np_temp; RB_FOREACH_SAFE(np, registered_fds_set_, &epollfd->registered_fds, - np_temp) + np_temp) { RB_REMOVE(registered_fds_set_, &epollfd->registered_fds, np); registered_fds_node_destroy(np); @@ -637,7 +748,8 @@ epollfd_ctx_terminate(EpollFDCtx *epollfd) free(epollfd->kevs); free(epollfd->pfds); - if (epollfd->self_pipe[0] >= 0 && epollfd->self_pipe[1] >= 0) { + if (epollfd->self_pipe[0] >= 0 && epollfd->self_pipe[1] >= 0) + { (void)close(epollfd->self_pipe[0]); (void)close(epollfd->self_pipe[1]); } @@ -650,17 +762,20 @@ epollfd_ctx_make_kevs_space(EpollFDCtx *epollfd, size_t cnt) { assert(cnt > 0); - if (cnt <= epollfd->kevs_length) { + if (cnt <= epollfd->kevs_length) + { return 0; } size_t size; - if (__builtin_mul_overflow(cnt, sizeof(struct kevent), &size)) { + if (__builtin_mul_overflow(cnt, sizeof(struct kevent), &size)) + { return ENOMEM; } struct kevent *new_kevs = realloc(epollfd->kevs, size); - if (!new_kevs) { + if (!new_kevs) + { return errno; } @@ -675,17 +790,20 @@ epollfd_ctx_make_pfds_space(EpollFDCtx *epollfd) { size_t cnt = 1 + epollfd->poll_fds_size; - if (cnt <= epollfd->pfds_length) { + if (cnt <= epollfd->pfds_length) + { return 0; } size_t size; - if (__builtin_mul_overflow(cnt, sizeof(struct pollfd), &size)) { + if (__builtin_mul_overflow(cnt, sizeof(struct pollfd), &size)) + { return ENOMEM; } struct pollfd *new_pfds = realloc(epollfd->pfds, size); - if (!new_pfds) { + if (!new_pfds) + { return errno; } @@ -703,8 +821,10 @@ epollfd_ctx__add_self_trigger(EpollFDCtx *epollfd) #ifdef EVFILT_USER EV_SET(&kevs[0], 0, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0); #else - if (epollfd->self_pipe[0] < 0 && epollfd->self_pipe[1] < 0) { - if (pipe2(epollfd->self_pipe, O_NONBLOCK | O_CLOEXEC) < 0) { + if (epollfd->self_pipe[0] < 0 && epollfd->self_pipe[1] < 0) + { + if (pipe2(epollfd->self_pipe, O_NONBLOCK | O_CLOEXEC) < 0) + { errno_t ec = errno; epollfd->self_pipe[0] = epollfd->self_pipe[1] = -1; return ec; @@ -715,10 +835,11 @@ epollfd_ctx__add_self_trigger(EpollFDCtx *epollfd) } EV_SET(&kevs[0], epollfd->self_pipe[0], EVFILT_READ, /**/ - EV_ADD | EV_CLEAR, 0, 0, 0); + EV_ADD | EV_CLEAR, 0, 0, 0); #endif - if (kevent(epollfd->kq, kevs, 1, NULL, 0, NULL) < 0) { + if (kevent(epollfd->kq, kevs, 1, NULL, 0, NULL) < 0) + { return errno; } @@ -748,31 +869,35 @@ epollfd_ctx__trigger_repoll(EpollFDCtx *epollfd) unsigned long nr_polling_threads = epollfd->nr_polling_threads; (void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex); - if (nr_polling_threads == 0) { + if (nr_polling_threads == 0) + { return; } epollfd_ctx__trigger_self(epollfd); (void)pthread_mutex_lock(&epollfd->nr_polling_threads_mutex); - while (epollfd->nr_polling_threads != 0) { + while (epollfd->nr_polling_threads != 0) + { pthread_cond_wait(&epollfd->nr_polling_threads_cond, - &epollfd->nr_polling_threads_mutex); + &epollfd->nr_polling_threads_mutex); } (void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex); #ifndef EVFILT_USER char c[32]; - while (read(epollfd->self_pipe[0], c, sizeof(c)) >= 0) { + while (read(epollfd->self_pipe[0], c, sizeof(c)) >= 0) + { } #endif } static void epollfd_ctx__remove_node_from_kq(EpollFDCtx *epollfd, - RegisteredFDsNode *fd2_node) + RegisteredFDsNode *fd2_node) { - if (fd2_node->is_on_pollfd_list) { + if (fd2_node->is_on_pollfd_list) + { TAILQ_REMOVE(&epollfd->poll_fds, fd2_node, pollfd_list_entry); fd2_node->is_on_pollfd_list = false; assert(epollfd->poll_fds_size != 0); @@ -781,35 +906,40 @@ epollfd_ctx__remove_node_from_kq(EpollFDCtx *epollfd, epollfd_ctx__trigger_repoll(epollfd); } - if (fd2_node->self_pipe[0] >= 0) { + if (fd2_node->self_pipe[0] >= 0) + { struct kevent kevs[1]; EV_SET(&kevs[0], fd2_node->self_pipe[0], EVFILT_READ, /**/ - EV_DELETE, 0, 0, 0); + EV_DELETE, 0, 0, 0); (void)kevent(epollfd->kq, kevs, 1, NULL, 0, NULL); char c[32]; - while (read(fd2_node->self_pipe[0], c, sizeof(c)) >= 0) { + while (read(fd2_node->self_pipe[0], c, sizeof(c)) >= 0) + { } } - if (fd2_node->node_type == NODE_TYPE_POLL) { + if (fd2_node->node_type == NODE_TYPE_POLL) + { #ifdef EVFILT_USER struct kevent kevs[1]; EV_SET(&kevs[0], (uintptr_t)fd2_node, EVFILT_USER, /**/ - EV_DELETE, 0, 0, 0); + EV_DELETE, 0, 0, 0); (void)kevent(epollfd->kq, kevs, 1, NULL, 0, NULL); #endif - } else { + } + else + { struct kevent kevs[3]; int fd2 = fd2_node->fd; EV_SET(&kevs[0], fd2, EVFILT_READ, /**/ - EV_DELETE | EV_RECEIPT, 0, 0, 0); + EV_DELETE | EV_RECEIPT, 0, 0, 0); EV_SET(&kevs[1], fd2, EVFILT_WRITE, /**/ - EV_DELETE | EV_RECEIPT, 0, 0, 0); + EV_DELETE | EV_RECEIPT, 0, 0, 0); #ifdef EVFILT_USER EV_SET(&kevs[2], (uintptr_t)fd2_node, EVFILT_USER, /**/ - EV_DELETE | EV_RECEIPT, 0, 0, 0); + EV_DELETE | EV_RECEIPT, 0, 0, 0); #endif (void)kevent(epollfd->kq, kevs, 3, kevs, 3, NULL); @@ -825,17 +955,18 @@ epollfd_ctx__register_events(EpollFDCtx *epollfd, RegisteredFDsNode *fd2_node) errno_t ec = 0; /* Only sockets support EPOLLRDHUP and EPOLLPRI. */ - if (fd2_node->node_type != NODE_TYPE_SOCKET) { + if (fd2_node->node_type != NODE_TYPE_SOCKET) + { fd2_node->events &= ~(uint32_t)EPOLLRDHUP; fd2_node->events &= ~(uint32_t)EPOLLPRI; } int const fd2 = fd2_node->fd; struct kevent kev[4] = { - {.data = 0}, - {.data = 0}, - {.data = 0}, - {.data = 0}, + {.data = 0}, + {.data = 0}, + {.data = 0}, + {.data = 0}, }; assert(fd2 >= 0); @@ -843,8 +974,10 @@ epollfd_ctx__register_events(EpollFDCtx *epollfd, RegisteredFDsNode *fd2_node) int evfilt_read_index = -1; int evfilt_write_index = -1; - if (fd2_node->node_type != NODE_TYPE_POLL) { - if (fd2_node->is_registered) { + if (fd2_node->node_type != NODE_TYPE_POLL) + { + if (fd2_node->is_registered) + { epollfd_ctx__remove_node_from_kq(epollfd, fd2_node); } @@ -856,60 +989,67 @@ epollfd_ctx__register_events(EpollFDCtx *epollfd, RegisteredFDsNode *fd2_node) NeededFilters needed_filters = get_needed_filters(fd2_node); - if (needed_filters.evfilt_read) { + if (needed_filters.evfilt_read) + { fd2_node->has_evfilt_read = true; evfilt_read_index = n; EV_SET(&kev[n++], fd2, EVFILT_READ, - EV_ADD | (needed_filters.evfilt_read & EV_CLEAR), - 0, 0, fd2_node); + EV_ADD | (needed_filters.evfilt_read & EV_CLEAR), + 0, 0, fd2_node); } - if (needed_filters.evfilt_write) { + if (needed_filters.evfilt_write) + { fd2_node->has_evfilt_write = true; evfilt_write_index = n; EV_SET(&kev[n++], fd2, EVFILT_WRITE, - EV_ADD | (needed_filters.evfilt_write & EV_CLEAR), - 0, 0, fd2_node); + EV_ADD | (needed_filters.evfilt_write & EV_CLEAR), + 0, 0, fd2_node); } assert(n != 0); - if (needed_filters.evfilt_except) { + if (needed_filters.evfilt_except) + { #ifdef EVFILT_EXCEPT fd2_node->has_evfilt_except = true; EV_SET(&kev[n++], fd2, EVFILT_EXCEPT, - EV_ADD | (needed_filters.evfilt_except & EV_CLEAR), - NOTE_OOB, 0, fd2_node); + EV_ADD | (needed_filters.evfilt_except & EV_CLEAR), + NOTE_OOB, 0, fd2_node); #else assert(0); #endif } - for (int i = 0; i < n; ++i) { + for (int i = 0; i < n; ++i) + { kev[i].flags |= EV_RECEIPT; } int ret = kevent(epollfd->kq, kev, n, kev, n, NULL); - if (ret < 0) { + if (ret < 0) + { ec = errno; goto out; } assert(ret == n); - for (int i = 0; i < n; ++i) { + for (int i = 0; i < n; ++i) + { assert((kev[i].flags & EV_ERROR) != 0); } } /* Check for fds that only support poll. */ if (((fd2_node->node_type == NODE_TYPE_OTHER && - kev[0].data == ENODEV) || - fd2_node->node_type == NODE_TYPE_POLL)) { + kev[0].data == ENODEV) || + fd2_node->node_type == NODE_TYPE_POLL)) + { assert((fd2_node->events & /**/ - ~(uint32_t)(EPOLLIN | EPOLLOUT)) == 0); + ~(uint32_t)(EPOLLIN | EPOLLOUT)) == 0); assert(fd2_node->is_registered || - fd2_node->node_type == NODE_TYPE_OTHER); + fd2_node->node_type == NODE_TYPE_OTHER); fd2_node->has_evfilt_read = false; fd2_node->has_evfilt_write = false; @@ -918,18 +1058,21 @@ epollfd_ctx__register_events(EpollFDCtx *epollfd, RegisteredFDsNode *fd2_node) fd2_node->node_type = NODE_TYPE_POLL; if ((ec = registered_fds_node_add_self_trigger(fd2_node, - epollfd)) != 0) { + epollfd)) != 0) + { goto out; } - if (!fd2_node->is_on_pollfd_list) { + if (!fd2_node->is_on_pollfd_list) + { if ((ec = /**/ - epollfd_ctx__add_self_trigger(epollfd)) != 0) { + epollfd_ctx__add_self_trigger(epollfd)) != 0) + { goto out; } TAILQ_INSERT_TAIL(&epollfd->poll_fds, fd2_node, - pollfd_list_entry); + pollfd_list_entry); fd2_node->is_on_pollfd_list = true; ++epollfd->poll_fds_size; } @@ -941,30 +1084,37 @@ epollfd_ctx__register_events(EpollFDCtx *epollfd, RegisteredFDsNode *fd2_node) goto out; } - for (int i = 0; i < 4; ++i) { - if (kev[i].data != 0) { + for (int i = 0; i < 4; ++i) + { + if (kev[i].data != 0) + { if ((kev[i].data == EPIPE #ifdef __NetBSD__ - || kev[i].data == EBADF + || kev[i].data == EBADF #endif - ) && - i == evfilt_write_index && - fd2_node->node_type == NODE_TYPE_FIFO) { + ) && + i == evfilt_write_index && + fd2_node->node_type == NODE_TYPE_FIFO) + { fd2_node->eof_state = EOF_STATE_READ_EOF | - EOF_STATE_WRITE_EOF; + EOF_STATE_WRITE_EOF; fd2_node->has_evfilt_write = false; - if (evfilt_read_index < 0) { + if (evfilt_read_index < 0) + { if ((ec = registered_fds_node_add_self_trigger( - fd2_node, epollfd)) != 0) { + fd2_node, epollfd)) != 0) + { goto out; } registered_fds_node_trigger_self( - fd2_node, epollfd); + fd2_node, epollfd); } - } else { + } + else + { ec = (int)kev[i].data; goto out; } @@ -999,18 +1149,20 @@ modify_fifo_rights_from_capabilities(RegisteredFDsNode *fd2_node) cap_rights_t rights; memset(&rights, 0, sizeof(rights)); - if (cap_rights_get(fd2_node->fd, &rights) == 0) { + if (cap_rights_get(fd2_node->fd, &rights) == 0) + { cap_rights_t test_rights; cap_rights_init(&test_rights, CAP_READ); bool has_read_rights = cap_rights_contains(&rights, - &test_rights); + &test_rights); cap_rights_init(&test_rights, CAP_WRITE); bool has_write_rights = cap_rights_contains(&rights, - &test_rights); + &test_rights); - if (has_read_rights != has_write_rights) { + if (has_read_rights != has_write_rights) + { fd2_node->node_data.fifo.readable = has_read_rights; fd2_node->node_data.fifo.writable = has_write_rights; } @@ -1020,37 +1172,46 @@ modify_fifo_rights_from_capabilities(RegisteredFDsNode *fd2_node) static errno_t epollfd_ctx_add_node(EpollFDCtx *epollfd, int fd2, struct epoll_event *ev, - struct stat const *statbuf) + struct stat const *statbuf) { RegisteredFDsNode *fd2_node = registered_fds_node_create(fd2); - if (!fd2_node) { + if (!fd2_node) + { return ENOMEM; } - if (S_ISFIFO(statbuf->st_mode)) { + if (S_ISFIFO(statbuf->st_mode)) + { int tmp; if (ioctl(fd2_node->fd, FIONREAD, &tmp) < 0 && - errno == ENOTTY) { + errno == ENOTTY) + { #ifdef __FreeBSD__ /* * On FreeBSD we need to distinguish between kqueues * and native eventfds. */ if (ioctl(fd2_node->fd, FIONBIO, &tmp) < 0 && - errno == ENOTTY) { + errno == ENOTTY) + { fd2_node->node_type = NODE_TYPE_KQUEUE; - } else { + } + else + { fd2_node->node_type = NODE_TYPE_OTHER; } #else fd2_node->node_type = NODE_TYPE_KQUEUE; #endif - } else { + } + else + { fd2_node->node_type = NODE_TYPE_FIFO; int fl = fcntl(fd2, F_GETFL, 0); - if (fl < 0) { + if (fl < 0) + { errno_t ec = errno; registered_fds_node_destroy(fd2_node); return ec; @@ -1058,24 +1219,35 @@ epollfd_ctx_add_node(EpollFDCtx *epollfd, int fd2, struct epoll_event *ev, fl &= O_ACCMODE; - if (fl == O_RDWR) { + if (fl == O_RDWR) + { fd2_node->node_data.fifo.readable = true; fd2_node->node_data.fifo.writable = true; #if defined(__FreeBSD__) modify_fifo_rights_from_capabilities(fd2_node); #endif - } else if (fl == O_WRONLY) { + } + else if (fl == O_WRONLY) + { fd2_node->node_data.fifo.writable = true; - } else if (fl == O_RDONLY) { + } + else if (fl == O_RDONLY) + { fd2_node->node_data.fifo.readable = true; - } else { + } + else + { registered_fds_node_destroy(fd2_node); return EINVAL; } } - } else if (S_ISSOCK(statbuf->st_mode)) { + } + else if (S_ISSOCK(statbuf->st_mode)) + { fd2_node->node_type = NODE_TYPE_SOCKET; - } else { + } + else + { /* May also be NODE_TYPE_POLL, will be checked when registering. */ fd2_node->node_type = NODE_TYPE_OTHER; @@ -1084,13 +1256,14 @@ epollfd_ctx_add_node(EpollFDCtx *epollfd, int fd2, struct epoll_event *ev, registered_fds_node_update_flags_from_epoll_event(fd2_node, ev); void *colliding_node = RB_INSERT(registered_fds_set_, - &epollfd->registered_fds, fd2_node); + &epollfd->registered_fds, fd2_node); (void)colliding_node; assert(colliding_node == NULL); ++epollfd->registered_fds_size; errno_t ec = epollfd_ctx__register_events(epollfd, fd2_node); - if (ec != 0) { + if (ec != 0) + { epollfd_ctx_remove_node(epollfd, fd2_node); return ec; } @@ -1102,14 +1275,15 @@ epollfd_ctx_add_node(EpollFDCtx *epollfd, int fd2, struct epoll_event *ev, static errno_t epollfd_ctx_modify_node(EpollFDCtx *epollfd, RegisteredFDsNode *fd2_node, - struct epoll_event *ev) + struct epoll_event *ev) { registered_fds_node_update_flags_from_epoll_event(fd2_node, ev); assert(fd2_node->is_registered); errno_t ec = epollfd_ctx__register_events(epollfd, fd2_node); - if (ec != 0) { + if (ec != 0) + { epollfd_ctx_remove_node(epollfd, fd2_node); return ec; } @@ -1119,20 +1293,22 @@ epollfd_ctx_modify_node(EpollFDCtx *epollfd, RegisteredFDsNode *fd2_node, static errno_t epollfd_ctx_ctl_impl(EpollFDCtx *epollfd, int op, int fd2, - struct epoll_event *ev) + struct epoll_event *ev) { assert(op == EPOLL_CTL_DEL || ev != NULL); - if (epollfd->kq == fd2) { + if (epollfd->kq == fd2) + { return EINVAL; } if (op != EPOLL_CTL_DEL && - ((ev->events & - ~(uint32_t)(EPOLLIN | EPOLLOUT | EPOLLRDHUP | /**/ - EPOLLPRI | /* unsupported by FreeBSD's kqueue! */ - EPOLLHUP | EPOLLERR | /**/ - EPOLLET | EPOLLONESHOT)))) { + ((ev->events & + ~(uint32_t)(EPOLLIN | EPOLLOUT | EPOLLRDHUP | /**/ + EPOLLPRI | /* unsupported by FreeBSD's kqueue! */ + EPOLLHUP | EPOLLERR | /**/ + EPOLLET | EPOLLONESHOT)))) + { return EINVAL; } @@ -1142,17 +1318,19 @@ epollfd_ctx_ctl_impl(EpollFDCtx *epollfd, int op, int fd2, find.fd = fd2; fd2_node = RB_FIND(registered_fds_set_, /**/ - &epollfd->registered_fds, &find); + &epollfd->registered_fds, &find); } struct stat statbuf; - if (fstat(fd2, &statbuf) < 0) { + if (fstat(fd2, &statbuf) < 0) + { errno_t ec = errno; /* If the fstat fails for any reason we must clear * internal state to avoid EEXIST errors in future * calls to epoll_ctl. */ - if (fd2_node) { + if (fd2_node) + { epollfd_ctx_remove_node(epollfd, fd2_node); } @@ -1161,27 +1339,33 @@ epollfd_ctx_ctl_impl(EpollFDCtx *epollfd, int op, int fd2, errno_t ec; - if (op == EPOLL_CTL_ADD) { + if (op == EPOLL_CTL_ADD) + { ec = fd2_node - ? EEXIST - : epollfd_ctx_add_node(epollfd, fd2, ev, &statbuf); - } else if (op == EPOLL_CTL_DEL) { + ? EEXIST + : epollfd_ctx_add_node(epollfd, fd2, ev, &statbuf); + } + else if (op == EPOLL_CTL_DEL) + { ec = !fd2_node - ? ENOENT - : (epollfd_ctx_remove_node(epollfd, fd2_node), 0); - } else if (op == EPOLL_CTL_MOD) { + ? ENOENT + : (epollfd_ctx_remove_node(epollfd, fd2_node), 0); + } + else if (op == EPOLL_CTL_MOD) + { ec = !fd2_node - ? ENOENT - : epollfd_ctx_modify_node(epollfd, fd2_node, ev); - } else { + ? ENOENT + : epollfd_ctx_modify_node(epollfd, fd2_node, ev); + } + else + { ec = EINVAL; } return ec; } -void -epollfd_ctx_fill_pollfds(EpollFDCtx *epollfd, struct pollfd *pfds) +void epollfd_ctx_fill_pollfds(EpollFDCtx *epollfd, struct pollfd *pfds) { pfds[0] = (struct pollfd){.fd = epollfd->kq, .events = POLLIN}; @@ -1190,10 +1374,10 @@ epollfd_ctx_fill_pollfds(EpollFDCtx *epollfd, struct pollfd *pfds) TAILQ_FOREACH(poll_node, &epollfd->poll_fds, pollfd_list_entry) { pfds[i++] = (struct pollfd){ - .fd = poll_node->fd, - .events = poll_node->node_type == NODE_TYPE_POLL - ? (short)poll_node->events - : POLLPRI, + .fd = poll_node->fd, + .events = poll_node->node_type == NODE_TYPE_POLL + ? (short)poll_node->events + : POLLPRI, }; } } @@ -1212,24 +1396,27 @@ epollfd_ctx_ctl(EpollFDCtx *epollfd, int op, int fd2, struct epoll_event *ev) static errno_t epollfd_ctx_wait_impl(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, - int *actual_cnt) + int *actual_cnt) { errno_t ec; assert(cnt >= 1); ec = epollfd_ctx_make_pfds_space(epollfd); - if (ec != 0) { + if (ec != 0) + { return ec; } epollfd_ctx_fill_pollfds(epollfd, epollfd->pfds); int n = poll(epollfd->pfds, (nfds_t)(1 + epollfd->poll_fds_size), 0); - if (n < 0) { + if (n < 0) + { return errno; } - if (n == 0) { + if (n == 0) + { *actual_cnt = 0; return 0; } @@ -1238,15 +1425,18 @@ epollfd_ctx_wait_impl(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, RegisteredFDsNode *poll_node, *tmp_poll_node; size_t i = 1; TAILQ_FOREACH_SAFE(poll_node, &epollfd->poll_fds, - pollfd_list_entry, tmp_poll_node) + pollfd_list_entry, tmp_poll_node) { struct pollfd *pfd = &epollfd->pfds[i++]; - if (pfd->revents & POLLNVAL) { + if (pfd->revents & POLLNVAL) + { epollfd_ctx_remove_node(epollfd, poll_node); - } else if (pfd->revents) { + } + else if (pfd->revents) + { registered_fds_node_trigger_self(poll_node, - epollfd); + epollfd); } } } @@ -1260,17 +1450,21 @@ again:; * call as well. Add some wiggle room for the 'poll only fd' * notification mechanism. */ - if ((size_t)cnt >= epollfd->registered_fds_size) { - if (__builtin_add_overflow(cnt, 1, &cnt)) { + if ((size_t)cnt >= epollfd->registered_fds_size) + { + if (__builtin_add_overflow(cnt, 1, &cnt)) + { return ENOMEM; } - if (__builtin_mul_overflow(cnt, 3, &cnt)) { + if (__builtin_mul_overflow(cnt, 3, &cnt)) + { return ENOMEM; } } ec = epollfd_ctx_make_kevs_space(epollfd, (size_t)cnt); - if (ec != 0) { + if (ec != 0) + { return ec; } @@ -1278,17 +1472,20 @@ again:; assert(kevs != NULL); n = kevent(epollfd->kq, NULL, 0, kevs, cnt, &(struct timespec){0, 0}); - if (n < 0) { + if (n < 0) + { return errno; } int j = 0; - for (int i = 0; i < n; ++i) { + for (int i = 0; i < n; ++i) + { RegisteredFDsNode *fd2_node = - (RegisteredFDsNode *)kevs[i].udata; + (RegisteredFDsNode *)kevs[i].udata; - if (!fd2_node) { + if (!fd2_node) + { #ifdef EVFILT_USER assert(kevs[i].filter == EVFILT_USER); #else @@ -1300,33 +1497,37 @@ again:; uint32_t old_revents = fd2_node->revents; NeededFilters old_needed_filters = get_needed_filters( - fd2_node); + fd2_node); registered_fds_node_feed_event(fd2_node, epollfd, &kevs[i]); if (fd2_node->node_type != NODE_TYPE_POLL && - !(fd2_node->is_edge_triggered && - fd2_node->eof_state == - (EOF_STATE_READ_EOF | EOF_STATE_WRITE_EOF) && - fd2_node->node_type != NODE_TYPE_FIFO)) { + !(fd2_node->is_edge_triggered && + fd2_node->eof_state == + (EOF_STATE_READ_EOF | EOF_STATE_WRITE_EOF) && + fd2_node->node_type != NODE_TYPE_FIFO)) + { NeededFilters needed_filters = get_needed_filters( - fd2_node); + fd2_node); if (old_needed_filters.evfilt_read != - needed_filters.evfilt_read || - old_needed_filters.evfilt_write != - needed_filters.evfilt_write) { + needed_filters.evfilt_read || + old_needed_filters.evfilt_write != + needed_filters.evfilt_write) + { if (epollfd_ctx__register_events(epollfd, - fd2_node) != 0) { + fd2_node) != 0) + { epollfd_ctx__remove_node_from_kq( - epollfd, fd2_node); + epollfd, fd2_node); } } } - if (fd2_node->revents && !old_revents) { + if (fd2_node->revents && !old_revents) + { ev[j++].data.ptr = fd2_node; } } @@ -1334,22 +1535,25 @@ again:; { int completion_kq = -1; - for (int i = 0; i < j; ++i) { + for (int i = 0; i < j; ++i) + { RegisteredFDsNode *fd2_node = - (RegisteredFDsNode *)ev[i].data.ptr; + (RegisteredFDsNode *)ev[i].data.ptr; - if (n == cnt || fd2_node->is_edge_triggered) { + if (n == cnt || fd2_node->is_edge_triggered) + { registered_fds_node_register_for_completion( - &completion_kq, fd2_node); + &completion_kq, fd2_node); } } registered_fds_node_complete(completion_kq); } - for (int i = 0; i < j; ++i) { + for (int i = 0; i < j; ++i) + { RegisteredFDsNode *fd2_node = - (RegisteredFDsNode *)ev[i].data.ptr; + (RegisteredFDsNode *)ev[i].data.ptr; ev[i].events = fd2_node->revents; ev[i].data = fd2_node->data; @@ -1359,12 +1563,14 @@ again:; fd2_node->got_evfilt_write = false; fd2_node->got_evfilt_except = false; - if (fd2_node->is_oneshot) { + if (fd2_node->is_oneshot) + { epollfd_ctx__remove_node_from_kq(epollfd, fd2_node); } } - if (n && j == 0) { + if (n && j == 0) + { goto again; } @@ -1374,7 +1580,7 @@ again:; errno_t epollfd_ctx_wait(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, - int *actual_cnt) + int *actual_cnt) { errno_t ec; diff --git a/tpws/epoll-shim/src/epollfd_ctx.h b/tpws/epoll-shim/src/epollfd_ctx.h index 1af7195..02868df 100644 --- a/tpws/epoll-shim/src/epollfd_ctx.h +++ b/tpws/epoll-shim/src/epollfd_ctx.h @@ -19,12 +19,14 @@ struct registered_fds_node_; typedef struct registered_fds_node_ RegisteredFDsNode; -typedef enum { +typedef enum +{ EOF_STATE_READ_EOF = 0x01, EOF_STATE_WRITE_EOF = 0x02, } EOFState; -typedef enum { +typedef enum +{ NODE_TYPE_FIFO = 1, NODE_TYPE_SOCKET = 2, NODE_TYPE_KQUEUE = 3, @@ -32,9 +34,12 @@ typedef enum { NODE_TYPE_POLL = 5, } NodeType; -struct registered_fds_node_ { - RB_ENTRY(registered_fds_node_) entry; - TAILQ_ENTRY(registered_fds_node_) pollfd_list_entry; +struct registered_fds_node_ +{ + RB_ENTRY(registered_fds_node_) + entry; + TAILQ_ENTRY(registered_fds_node_) + pollfd_list_entry; int fd; epoll_data_t data; @@ -50,8 +55,10 @@ struct registered_fds_node_ { bool got_evfilt_except; NodeType node_type; - union { - struct { + union + { + struct + { bool readable; bool writable; } fifo; @@ -72,7 +79,8 @@ struct registered_fds_node_ { typedef TAILQ_HEAD(pollfds_list_, registered_fds_node_) PollFDList; typedef RB_HEAD(registered_fds_set_, registered_fds_node_) RegisteredFDsSet; -typedef struct { +typedef struct +{ int kq; // non owning pthread_mutex_t mutex; @@ -101,8 +109,8 @@ errno_t epollfd_ctx_terminate(EpollFDCtx *epollfd); void epollfd_ctx_fill_pollfds(EpollFDCtx *epollfd, struct pollfd *pfds); errno_t epollfd_ctx_ctl(EpollFDCtx *epollfd, int op, int fd2, - struct epoll_event *ev); + struct epoll_event *ev); errno_t epollfd_ctx_wait(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt, - int *actual_cnt); + int *actual_cnt); #endif diff --git a/tpws/epoll-shim/src/eventfd_ctx.h b/tpws/epoll-shim/src/eventfd_ctx.h index 3e5bb55..10df6ca 100644 --- a/tpws/epoll-shim/src/eventfd_ctx.h +++ b/tpws/epoll-shim/src/eventfd_ctx.h @@ -11,7 +11,8 @@ #define EVENTFD_CTX_FLAG_SEMAPHORE (1 << 0) -typedef struct { +typedef struct +{ int kq_; // non owning int flags_; pthread_mutex_t mutex_; @@ -22,7 +23,7 @@ typedef struct { } EventFDCtx; errno_t eventfd_ctx_init(EventFDCtx *eventfd, int kq, unsigned int counter, - int flags); + int flags); errno_t eventfd_ctx_terminate(EventFDCtx *eventfd); errno_t eventfd_ctx_write(EventFDCtx *eventfd, uint64_t value); diff --git a/tpws/epoll-shim/src/fix.c b/tpws/epoll-shim/src/fix.c index 6fbd3f5..46933b1 100644 --- a/tpws/epoll-shim/src/fix.c +++ b/tpws/epoll-shim/src/fix.c @@ -4,7 +4,7 @@ #include -int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const sigset_t *sigmask) +int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask) { // macos does not implement ppoll // this is a hacky ppoll shim. only for tpws which does not require sigmask @@ -13,7 +13,7 @@ int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const si errno = EINVAL; return -1; } - return poll(fds,nfds,tmo_p ? tmo_p->tv_sec*1000 + tmo_p->tv_nsec/1000000 : -1); + return poll(fds, nfds, tmo_p ? tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000 : -1); } #endif diff --git a/tpws/epoll-shim/src/fix.h b/tpws/epoll-shim/src/fix.h index ebefc14..62287b8 100644 --- a/tpws/epoll-shim/src/fix.h +++ b/tpws/epoll-shim/src/fix.h @@ -11,10 +11,11 @@ typedef int errno_t; #include #include -struct itimerspec { - struct timespec it_interval; - struct timespec it_value; +struct itimerspec +{ + struct timespec it_interval; + struct timespec it_value; }; -int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const sigset_t *sigmask); +int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask); #endif diff --git a/tpws/epoll-shim/src/signalfd_ctx.h b/tpws/epoll-shim/src/signalfd_ctx.h index 8623f63..2f694ad 100644 --- a/tpws/epoll-shim/src/signalfd_ctx.h +++ b/tpws/epoll-shim/src/signalfd_ctx.h @@ -7,7 +7,8 @@ #include #include -typedef struct { +typedef struct +{ int kq; // non owning } SignalFDCtx; diff --git a/tpws/epoll-shim/src/timerfd_ctx.h b/tpws/epoll-shim/src/timerfd_ctx.h index 8b41507..084c483 100644 --- a/tpws/epoll-shim/src/timerfd_ctx.h +++ b/tpws/epoll-shim/src/timerfd_ctx.h @@ -11,7 +11,8 @@ #include #include -typedef struct { +typedef struct +{ int kq; // non owning int flags; pthread_mutex_t mutex; @@ -30,7 +31,7 @@ errno_t timerfd_ctx_init(TimerFDCtx *timerfd, int kq, int clockid); errno_t timerfd_ctx_terminate(TimerFDCtx *timerfd); errno_t timerfd_ctx_settime(TimerFDCtx *timerfd, int flags, - struct itimerspec const *new, struct itimerspec *old); + struct itimerspec const *new, struct itimerspec *old); errno_t timerfd_ctx_gettime(TimerFDCtx *timerfd, struct itimerspec *cur); errno_t timerfd_ctx_read(TimerFDCtx *timerfd, uint64_t *value); diff --git a/tpws/gzip.c b/tpws/gzip.c index cb46670..1161b97 100644 --- a/tpws/gzip.c +++ b/tpws/gzip.c @@ -5,7 +5,7 @@ #define ZCHUNK 16384 #define BUFMIN 128 -#define BUFCHUNK (1024*128) +#define BUFCHUNK (1024 * 128) int z_readfile(FILE *F, char **buf, size_t *size) { @@ -21,7 +21,8 @@ int z_readfile(FILE *F, char **buf, size_t *size) bufsize = *size = 0; r = inflateInit2(&zs, 47); - if (r != Z_OK) return r; + if (r != Z_OK) + return r; do { @@ -31,7 +32,8 @@ int z_readfile(FILE *F, char **buf, size_t *size) r = Z_ERRNO; goto zerr; } - if (!zs.avail_in) break; + if (!zs.avail_in) + break; zs.next_in = in; do { @@ -47,9 +49,10 @@ int z_readfile(FILE *F, char **buf, size_t *size) *buf = newbuf; } zs.avail_out = bufsize - *size; - zs.next_out = (unsigned char*)(*buf + *size); + zs.next_out = (unsigned char *)(*buf + *size); r = inflate(&zs, Z_NO_FLUSH); - if (r != Z_OK && r != Z_STREAM_END) goto zerr; + if (r != Z_OK && r != Z_STREAM_END) + goto zerr; *size = bufsize - zs.avail_out; } while (r == Z_OK && zs.avail_in); } while (r == Z_OK); @@ -57,7 +60,8 @@ int z_readfile(FILE *F, char **buf, size_t *size) if (*size < bufsize) { // free extra space - if ((newbuf = realloc(*buf, *size))) *buf = newbuf; + if ((newbuf = realloc(*buf, *size))) + *buf = newbuf; } inflateEnd(&zs); @@ -73,7 +77,7 @@ zerr: return r; } -bool is_gzip(FILE* F) +bool is_gzip(FILE *F) { unsigned char magic[2]; bool b = !fseek(F, 0, SEEK_SET) && fread(magic, 1, 2, F) == 2 && magic[0] == 0x1F && magic[1] == 0x8B; diff --git a/tpws/gzip.h b/tpws/gzip.h index 15e30d2..ffc5c02 100644 --- a/tpws/gzip.h +++ b/tpws/gzip.h @@ -4,5 +4,5 @@ #include #include -int z_readfile(FILE *F,char **buf,size_t *size); -bool is_gzip(FILE* F); +int z_readfile(FILE *F, char **buf, size_t *size); +bool is_gzip(FILE *F); diff --git a/tpws/helpers.c b/tpws/helpers.c index 85954de..880c8c7 100644 --- a/tpws/helpers.c +++ b/tpws/helpers.c @@ -11,7 +11,7 @@ #include #include -char *strncasestr(const char *s,const char *find, size_t slen) +char *strncasestr(const char *s, const char *find, size_t slen) { char c, sc; size_t len; @@ -23,9 +23,11 @@ char *strncasestr(const char *s,const char *find, size_t slen) { do { - if (slen-- < 1 || (sc = *s++) == '\0') return NULL; + if (slen-- < 1 || (sc = *s++) == '\0') + return NULL; } while (toupper(c) != toupper(sc)); - if (len > slen) return NULL; + if (len > slen) + return NULL; } while (strncasecmp(s, find, len) != 0); s--; } @@ -34,71 +36,73 @@ char *strncasestr(const char *s,const char *find, size_t slen) bool append_to_list_file(const char *filename, const char *s) { - FILE *F = fopen(filename,"at"); - if (!F) return false; - bool bOK = fprintf(F,"%s\n",s)>0; + FILE *F = fopen(filename, "at"); + if (!F) + return false; + bool bOK = fprintf(F, "%s\n", s) > 0; fclose(F); return bOK; } void ntop46(const struct sockaddr *sa, char *str, size_t len) { - if (!len) return; - *str=0; + if (!len) + return; + *str = 0; switch (sa->sa_family) { case AF_INET: - inet_ntop(sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr, str, len); + inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, str, len); break; case AF_INET6: - inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, str, len); + inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, str, len); break; default: - snprintf(str,len,"UNKNOWN_FAMILY_%d",sa->sa_family); + snprintf(str, len, "UNKNOWN_FAMILY_%d", sa->sa_family); } } void ntop46_port(const struct sockaddr *sa, char *str, size_t len) { char ip[40]; - ntop46(sa,ip,sizeof(ip)); + ntop46(sa, ip, sizeof(ip)); switch (sa->sa_family) { case AF_INET: - snprintf(str,len,"%s:%u",ip,ntohs(((struct sockaddr_in*)sa)->sin_port)); + snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in *)sa)->sin_port)); break; case AF_INET6: - snprintf(str,len,"[%s]:%u",ip,ntohs(((struct sockaddr_in6*)sa)->sin6_port)); + snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); break; default: - snprintf(str,len,"%s",ip); + snprintf(str, len, "%s", ip); } } void print_sockaddr(const struct sockaddr *sa) { char ip_port[48]; - ntop46_port(sa,ip_port,sizeof(ip_port)); - printf("%s",ip_port); + ntop46_port(sa, ip_port, sizeof(ip_port)); + printf("%s", ip_port); } - // -1 = error, 0 = not local, 1 = local bool check_local_ip(const struct sockaddr *saddr) { - struct ifaddrs *addrs,*a; + struct ifaddrs *addrs, *a; if (is_localnet(saddr)) return true; - if (getifaddrs(&addrs)<0) return false; - a = addrs; + if (getifaddrs(&addrs) < 0) + return false; + a = addrs; - bool bres=false; + bool bres = false; while (a) { - if (a->ifa_addr && sacmp(a->ifa_addr,saddr)) + if (a->ifa_addr && sacmp(a->ifa_addr, saddr)) { - bres=true; + bres = true; break; } a = a->ifa_next; @@ -115,50 +119,48 @@ void print_addrinfo(const struct addrinfo *ai) switch (ai->ai_family) { case AF_INET: - if (inet_ntop(ai->ai_family, &((struct sockaddr_in*)ai->ai_addr)->sin_addr, str, sizeof(str))) + if (inet_ntop(ai->ai_family, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, str, sizeof(str))) printf("%s\n", str); break; case AF_INET6: - if (inet_ntop(ai->ai_family, &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, str, sizeof(str))) - printf( "%s\n", str); + if (inet_ntop(ai->ai_family, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, str, sizeof(str))) + printf("%s\n", str); break; } ai = ai->ai_next; } } - - bool saismapped(const struct sockaddr_in6 *sa) { // ::ffff:1.2.3.4 - return !memcmp(sa->sin6_addr.s6_addr,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff",12); + return !memcmp(sa->sin6_addr.s6_addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff", 12); } -bool samappedcmp(const struct sockaddr_in *sa1,const struct sockaddr_in6 *sa2) +bool samappedcmp(const struct sockaddr_in *sa1, const struct sockaddr_in6 *sa2) { - return saismapped(sa2) && !memcmp(sa2->sin6_addr.s6_addr+12,&sa1->sin_addr.s_addr,4); + return saismapped(sa2) && !memcmp(sa2->sin6_addr.s6_addr + 12, &sa1->sin_addr.s_addr, 4); } -bool sacmp(const struct sockaddr *sa1,const struct sockaddr *sa2) +bool sacmp(const struct sockaddr *sa1, const struct sockaddr *sa2) { - return (sa1->sa_family==AF_INET && sa2->sa_family==AF_INET && !memcmp(&((struct sockaddr_in*)sa1)->sin_addr,&((struct sockaddr_in*)sa2)->sin_addr,sizeof(struct in_addr))) || - (sa1->sa_family==AF_INET6 && sa2->sa_family==AF_INET6 && !memcmp(&((struct sockaddr_in6*)sa1)->sin6_addr,&((struct sockaddr_in6*)sa2)->sin6_addr,sizeof(struct in6_addr))) || - (sa1->sa_family==AF_INET && sa2->sa_family==AF_INET6 && samappedcmp((struct sockaddr_in*)sa1,(struct sockaddr_in6*)sa2)) || - (sa1->sa_family==AF_INET6 && sa2->sa_family==AF_INET && samappedcmp((struct sockaddr_in*)sa2,(struct sockaddr_in6*)sa1)); + return (sa1->sa_family == AF_INET && sa2->sa_family == AF_INET && !memcmp(&((struct sockaddr_in *)sa1)->sin_addr, &((struct sockaddr_in *)sa2)->sin_addr, sizeof(struct in_addr))) || + (sa1->sa_family == AF_INET6 && sa2->sa_family == AF_INET6 && !memcmp(&((struct sockaddr_in6 *)sa1)->sin6_addr, &((struct sockaddr_in6 *)sa2)->sin6_addr, sizeof(struct in6_addr))) || + (sa1->sa_family == AF_INET && sa2->sa_family == AF_INET6 && samappedcmp((struct sockaddr_in *)sa1, (struct sockaddr_in6 *)sa2)) || + (sa1->sa_family == AF_INET6 && sa2->sa_family == AF_INET && samappedcmp((struct sockaddr_in *)sa2, (struct sockaddr_in6 *)sa1)); } uint16_t saport(const struct sockaddr *sa) { - return htons(sa->sa_family==AF_INET ? ((struct sockaddr_in*)sa)->sin_port : - sa->sa_family==AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0); + return htons(sa->sa_family == AF_INET ? ((struct sockaddr_in *)sa)->sin_port : sa->sa_family == AF_INET6 ? ((struct sockaddr_in6 *)sa)->sin6_port + : 0); } bool saconvmapped(struct sockaddr_storage *a) { - if ((a->ss_family == AF_INET6) && saismapped((struct sockaddr_in6*)a)) + if ((a->ss_family == AF_INET6) && saismapped((struct sockaddr_in6 *)a)) { - uint32_t ip4 = IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr); - uint16_t port = ((struct sockaddr_in6*)a)->sin6_port; + uint32_t ip4 = IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr); + uint16_t port = ((struct sockaddr_in6 *)a)->sin6_port; a->ss_family = AF_INET; - ((struct sockaddr_in*)a)->sin_addr.s_addr = ip4; - ((struct sockaddr_in*)a)->sin_port = port; + ((struct sockaddr_in *)a)->sin_addr.s_addr = ip4; + ((struct sockaddr_in *)a)->sin_port = port; return true; } return false; @@ -167,45 +169,43 @@ bool saconvmapped(struct sockaddr_storage *a) bool is_localnet(const struct sockaddr *a) { // match 127.0.0.0/8, 0.0.0.0, ::1, ::0, :ffff:127.0.0.0/104, :ffff:0.0.0.0 - return (a->sa_family==AF_INET && (IN_LOOPBACK(ntohl(((struct sockaddr_in *)a)->sin_addr.s_addr)) || - INADDR_ANY == ntohl((((struct sockaddr_in *)a)->sin_addr.s_addr)))) || - (a->sa_family==AF_INET6 && (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)a)->sin6_addr) || - IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)a)->sin6_addr) || - (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr) && (IN_LOOPBACK(ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr))) || - INADDR_ANY == ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr)))))); + return (a->sa_family == AF_INET && (IN_LOOPBACK(ntohl(((struct sockaddr_in *)a)->sin_addr.s_addr)) || + INADDR_ANY == ntohl((((struct sockaddr_in *)a)->sin_addr.s_addr)))) || + (a->sa_family == AF_INET6 && (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)a)->sin6_addr) || + IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)a)->sin6_addr) || + (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr) && (IN_LOOPBACK(ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr))) || + INADDR_ANY == ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr)))))); } bool is_linklocal(const struct sockaddr_in6 *a) { // fe80::/10 - return a->sin6_addr.s6_addr[0]==0xFE && (a->sin6_addr.s6_addr[1] & 0xC0)==0x80; + return a->sin6_addr.s6_addr[0] == 0xFE && (a->sin6_addr.s6_addr[1] & 0xC0) == 0x80; } -bool is_private6(const struct sockaddr_in6* a) +bool is_private6(const struct sockaddr_in6 *a) { // fc00::/7 return (a->sin6_addr.s6_addr[0] & 0xFE) == 0xFC; } - - bool set_keepalive(int fd) { - int yes=1; - return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int))!=-1; + int yes = 1; + return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int)) != -1; } bool set_ttl(int fd, int ttl) { - return setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))!=-1; + return setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) != -1; } bool set_hl(int fd, int hl) { - return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hl, sizeof(hl))!=-1; + return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hl, sizeof(hl)) != -1; } bool set_ttl_hl(int fd, int ttl) { - bool b1,b2; + bool b1, b2; // try to set both but one may fail if family is wrong - b1=set_ttl(fd, ttl); - b2=set_hl(fd, ttl); + b1 = set_ttl(fd, ttl); + b2 = set_hl(fd, ttl); return b1 || b2; } int get_so_error(int fd) @@ -213,8 +213,8 @@ int get_so_error(int fd) // getsockopt(SO_ERROR) clears error int errn; socklen_t optlen = sizeof(errn); - if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1) - errn=errno; + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1) + errn = errno; return errn; } @@ -224,42 +224,45 @@ int fprint_localtime(FILE *F) time_t now; time(&now); - localtime_r(&now,&t); + localtime_r(&now, &t); return fprintf(F, "%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec); } time_t file_mod_time(const char *filename) { struct stat st; - return stat(filename,&st)==-1 ? 0 : st.st_mtime; + return stat(filename, &st) == -1 ? 0 : st.st_mtime; } bool pf_in_range(uint16_t port, const port_filter *pf) { - return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg); + return port && (((!pf->from && !pf->to) || (port >= pf->from && port <= pf->to)) ^ pf->neg); } bool pf_parse(const char *s, port_filter *pf) { - unsigned int v1,v2; + unsigned int v1, v2; - if (!s) return false; - if (*s=='~') + if (!s) + return false; + if (*s == '~') { - pf->neg=true; + pf->neg = true; s++; } else - pf->neg=false; - if (sscanf(s,"%u-%u",&v1,&v2)==2) + pf->neg = false; + if (sscanf(s, "%u-%u", &v1, &v2) == 2) { - if (!v1 || v1>65535 || v2>65535 || v1>v2) return false; - pf->from=(uint16_t)v1; - pf->to=(uint16_t)v2; + if (!v1 || v1 > 65535 || v2 > 65535 || v1 > v2) + return false; + pf->from = (uint16_t)v1; + pf->to = (uint16_t)v2; } - else if (sscanf(s,"%u",&v1)==1) + else if (sscanf(s, "%u", &v1) == 1) { - if (!v1 || v1>65535) return false; - pf->to=pf->from=(uint16_t)v1; + if (!v1 || v1 > 65535) + return false; + pf->to = pf->from = (uint16_t)v1; } else return false; diff --git a/tpws/helpers.h b/tpws/helpers.h index f1383cb..a0e401c 100644 --- a/tpws/helpers.h +++ b/tpws/helpers.h @@ -8,7 +8,7 @@ #include #include -char *strncasestr(const char *s,const char *find, size_t slen); +char *strncasestr(const char *s, const char *find, size_t slen); bool append_to_list_file(const char *filename, const char *s); @@ -19,15 +19,15 @@ void print_addrinfo(const struct addrinfo *ai); bool check_local_ip(const struct sockaddr *saddr); bool saismapped(const struct sockaddr_in6 *sa); -bool samappedcmp(const struct sockaddr_in *sa1,const struct sockaddr_in6 *sa2); -bool sacmp(const struct sockaddr *sa1,const struct sockaddr *sa2); +bool samappedcmp(const struct sockaddr_in *sa1, const struct sockaddr_in6 *sa2); +bool sacmp(const struct sockaddr *sa1, const struct sockaddr *sa2); uint16_t saport(const struct sockaddr *sa); // true = was converted bool saconvmapped(struct sockaddr_storage *a); bool is_localnet(const struct sockaddr *a); -bool is_linklocal(const struct sockaddr_in6* a); -bool is_private6(const struct sockaddr_in6* a); +bool is_linklocal(const struct sockaddr_in6 *a); +bool is_private6(const struct sockaddr_in6 *a); bool set_keepalive(int fd); bool set_ttl(int fd, int ttl); @@ -36,11 +36,13 @@ bool set_ttl_hl(int fd, int ttl); int get_so_error(int fd); // alignment-safe functions -static inline uint16_t pntoh16(const uint8_t *p) { +static inline uint16_t pntoh16(const uint8_t *p) +{ return ((uint16_t)p[0] << 8) | (uint16_t)p[1]; } -static inline void phton16(uint8_t *p, uint16_t v) { - p[0] = (uint8_t)(v>>8); +static inline void phton16(uint8_t *p, uint16_t v) +{ + p[0] = (uint8_t)(v >> 8); p[1] = (uint8_t)v; } @@ -50,21 +52,20 @@ time_t file_mod_time(const char *filename); typedef struct { - uint16_t from,to; + uint16_t from, to; bool neg; } port_filter; bool pf_in_range(uint16_t port, const port_filter *pf); bool pf_parse(const char *s, port_filter *pf); #ifndef IN_LOOPBACK -#define IN_LOOPBACK(a) ((((uint32_t) (a)) & 0xff000000) == 0x7f000000) +#define IN_LOOPBACK(a) ((((uint32_t)(a)) & 0xff000000) == 0x7f000000) #endif #ifdef __GNUC__ #define IN6_EXTRACT_MAP4(a) \ - (__extension__ \ - ({ const struct in6_addr *__a = (const struct in6_addr *) (a); \ + (__extension__({ const struct in6_addr *__a = (const struct in6_addr *) (a); \ (((const uint32_t *) (__a))[3]); })) #else -#define IN6_EXTRACT_MAP4(a) (((const uint32_t *) (a))[3]) +#define IN6_EXTRACT_MAP4(a) (((const uint32_t *)(a))[3]) #endif diff --git a/tpws/hostlist.c b/tpws/hostlist.c index f4d9d2b..017f782 100644 --- a/tpws/hostlist.c +++ b/tpws/hostlist.c @@ -8,17 +8,19 @@ static bool addpool(strpool **hostlist, char **s, const char *end) { char *p; - + // advance until eol lowering all chars - for (p = *s; pstr)) return false; + if (!AppendHostList(hostlist, file->str)) + return false; } return true; } @@ -114,7 +119,6 @@ bool NonEmptyHostlist(strpool **hostlist) return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4); } - bool SearchHostList(strpool *hostlist, const char *host) { if (hostlist) @@ -125,9 +129,11 @@ bool SearchHostList(strpool *hostlist, const char *host) { bInHostList = StrPoolCheckStr(hostlist, p); VPRINT("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative"); - if (bInHostList) return true; + if (bInHostList) + return true; p = strchr(p, '.'); - if (p) p++; + if (p) + p++; } } return false; @@ -136,13 +142,15 @@ bool SearchHostList(strpool *hostlist, const char *host) // return : true = apply fooling, false = do not apply static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded) { - if (excluded) *excluded = false; + if (excluded) + *excluded = false; if (hostlist_exclude) { VPRINT("Checking exclude hostlist\n"); if (SearchHostList(hostlist_exclude, host)) { - if (excluded) *excluded = true; + if (excluded) + *excluded = true; return false; } } @@ -160,7 +168,7 @@ bool HostlistCheck(const char *host, bool *excluded) if (*params.hostlist_auto_filename) { time_t t = file_mod_time(params.hostlist_auto_filename); - if (t!=params.hostlist_auto_mod_time) + if (t != params.hostlist_auto_mod_time) { DLOG_CONDUP("Autohostlist was modified by another process. Reloading include hostslist.\n"); if (!LoadIncludeHostLists()) diff --git a/tpws/macos/net/pfvar.h b/tpws/macos/net/pfvar.h index e6f6b6e..7aca85f 100644 --- a/tpws/macos/net/pfvar.h +++ b/tpws/macos/net/pfvar.h @@ -6,42 +6,52 @@ // taken from an older apple SDK // some fields are different from BSDs -#define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook) +#define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook) -enum { PF_INOUT, PF_IN, PF_OUT, PF_FWD }; - -struct pf_addr { - union { - struct in_addr v4; - struct in6_addr v6; - u_int8_t addr8[16]; - u_int16_t addr16[8]; - u_int32_t addr32[4]; - } pfa; /* 128-bit address */ -#define v4 pfa.v4 -#define v6 pfa.v6 -#define addr8 pfa.addr8 -#define addr16 pfa.addr16 -#define addr32 pfa.addr32 +enum +{ + PF_INOUT, + PF_IN, + PF_OUT, + PF_FWD }; -union pf_state_xport { - u_int16_t port; - u_int16_t call_id; - u_int32_t spi; +struct pf_addr +{ + union + { + struct in_addr v4; + struct in6_addr v6; + u_int8_t addr8[16]; + u_int16_t addr16[8]; + u_int32_t addr32[4]; + } pfa; /* 128-bit address */ +#define v4 pfa.v4 +#define v6 pfa.v6 +#define addr8 pfa.addr8 +#define addr16 pfa.addr16 +#define addr32 pfa.addr32 }; -struct pfioc_natlook { - struct pf_addr saddr; - struct pf_addr daddr; - struct pf_addr rsaddr; - struct pf_addr rdaddr; - union pf_state_xport sxport; - union pf_state_xport dxport; - union pf_state_xport rsxport; - union pf_state_xport rdxport; - sa_family_t af; - u_int8_t proto; - u_int8_t proto_variant; - u_int8_t direction; +union pf_state_xport +{ + u_int16_t port; + u_int16_t call_id; + u_int32_t spi; +}; + +struct pfioc_natlook +{ + struct pf_addr saddr; + struct pf_addr daddr; + struct pf_addr rsaddr; + struct pf_addr rdaddr; + union pf_state_xport sxport; + union pf_state_xport dxport; + union pf_state_xport rsxport; + union pf_state_xport rdxport; + sa_family_t af; + u_int8_t proto; + u_int8_t proto_variant; + u_int8_t direction; }; diff --git a/tpws/macos/sys/tree.h b/tpws/macos/sys/tree.h index 697fddf..62d5d3c 100644 --- a/tpws/macos/sys/tree.h +++ b/tpws/macos/sys/tree.h @@ -29,8 +29,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _SYS_TREE_H_ -#define _SYS_TREE_H_ +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ #include @@ -61,743 +61,848 @@ * The maximum height of a red-black tree is 2lg (n+1). */ -#define SPLAY_HEAD(name, type) \ -struct name { \ - struct type *sph_root; /* root of the tree */ \ -} +#define SPLAY_HEAD(name, type) \ + struct name \ + { \ + struct type *sph_root; /* root of the tree */ \ + } -#define SPLAY_INITIALIZER(root) \ - { NULL } +#define SPLAY_INITIALIZER(root) \ + {NULL} -#define SPLAY_INIT(root) do { \ - (root)->sph_root = NULL; \ -} while (/*CONSTCOND*/ 0) +#define SPLAY_INIT(root) \ + do \ + { \ + (root)->sph_root = NULL; \ + } while (/*CONSTCOND*/ 0) -#define SPLAY_ENTRY(type) \ -struct { \ - struct type *spe_left; /* left element */ \ - struct type *spe_right; /* right element */ \ -} +#define SPLAY_ENTRY(type) \ + struct \ + { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ + } -#define SPLAY_LEFT(elm, field) (elm)->field.spe_left -#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right -#define SPLAY_ROOT(head) (head)->sph_root -#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ -#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (/*CONSTCOND*/ 0) +#define SPLAY_ROTATE_RIGHT(head, tmp, field) \ + do \ + { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ + } while (/*CONSTCOND*/ 0) -#define SPLAY_LINKLEFT(head, tmp, field) do { \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (/*CONSTCOND*/ 0) +#define SPLAY_ROTATE_LEFT(head, tmp, field) \ + do \ + { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ + } while (/*CONSTCOND*/ 0) -#define SPLAY_LINKRIGHT(head, tmp, field) do { \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (/*CONSTCOND*/ 0) +#define SPLAY_LINKLEFT(head, tmp, field) \ + do \ + { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ + } while (/*CONSTCOND*/ 0) -#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ - SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (/*CONSTCOND*/ 0) +#define SPLAY_LINKRIGHT(head, tmp, field) \ + do \ + { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ + } while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) \ + do \ + { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ + } while (/*CONSTCOND*/ 0) /* Generates prototypes and inline functions */ -#define SPLAY_PROTOTYPE(name, type, field, cmp) \ -void name##_SPLAY(struct name *, struct type *); \ -void name##_SPLAY_MINMAX(struct name *, int); \ -struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ -struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ - \ -/* Finds the node with the same key as elm */ \ -static __inline struct type * \ -name##_SPLAY_FIND(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) \ - return(NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) \ - return (head->sph_root); \ - return (NULL); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_NEXT(struct name *head, struct type *elm) \ -{ \ - name##_SPLAY(head, elm); \ - if (SPLAY_RIGHT(elm, field) != NULL) { \ - elm = SPLAY_RIGHT(elm, field); \ - while (SPLAY_LEFT(elm, field) != NULL) { \ - elm = SPLAY_LEFT(elm, field); \ - } \ - } else \ - elm = NULL; \ - return (elm); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_MIN_MAX(struct name *head, int val) \ -{ \ - name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ -} +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ + void name##_SPLAY(struct name *, struct type *); \ + void name##_SPLAY_MINMAX(struct name *, int); \ + struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ + struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ + /* Finds the node with the same key as elm */ \ + static __inline struct type * \ + name##_SPLAY_FIND(struct name *head, struct type *elm) \ + { \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ + } \ + \ + static __inline struct type * \ + name##_SPLAY_NEXT(struct name *head, struct type *elm) \ + { \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) \ + { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) \ + { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } \ + else \ + elm = NULL; \ + return (elm); \ + } \ + \ + static __inline struct type * \ + name##_SPLAY_MIN_MAX(struct name *head, int val) \ + { \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ + } /* Main splay operation. * Moves node close to the key of elm to top */ -#define SPLAY_GENERATE(name, type, field, cmp) \ -struct type * \ -name##_SPLAY_INSERT(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) { \ - SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ - } else { \ - int __comp; \ - name##_SPLAY(head, elm); \ - __comp = (cmp)(elm, (head)->sph_root); \ - if(__comp < 0) { \ - SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ - SPLAY_RIGHT(elm, field) = (head)->sph_root; \ - SPLAY_LEFT((head)->sph_root, field) = NULL; \ - } else if (__comp > 0) { \ - SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT(elm, field) = (head)->sph_root; \ - SPLAY_RIGHT((head)->sph_root, field) = NULL; \ - } else \ - return ((head)->sph_root); \ - } \ - (head)->sph_root = (elm); \ - return (NULL); \ -} \ - \ -struct type * \ -name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *__tmp; \ - if (SPLAY_EMPTY(head)) \ - return (NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) { \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ - } else { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ - name##_SPLAY(head, elm); \ - SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ - } \ - return (elm); \ - } \ - return (NULL); \ -} \ - \ -void \ -name##_SPLAY(struct name *head, struct type *elm) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - int __comp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) > 0){ \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} \ - \ -/* Splay with either the minimum or the maximum element \ - * Used to find minimum or maximum element in tree. \ - */ \ -void name##_SPLAY_MINMAX(struct name *head, int __comp) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while (1) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp > 0) { \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} +#define SPLAY_GENERATE(name, type, field, cmp) \ + struct type * \ + name##_SPLAY_INSERT(struct name *head, struct type *elm) \ + { \ + if (SPLAY_EMPTY(head)) \ + { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } \ + else \ + { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if (__comp < 0) \ + { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } \ + else if (__comp > 0) \ + { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } \ + else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ + } \ + \ + struct type * \ + name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ + { \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ + } \ + else \ + { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ + } \ + \ + void \ + name##_SPLAY(struct name *head, struct type *elm) \ + { \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) \ + { \ + if (__comp < 0) \ + { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0) \ + { \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } \ + else if (__comp > 0) \ + { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0) \ + { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ + } \ + \ + /* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ + void name##_SPLAY_MINMAX(struct name *head, int __comp) \ + { \ + struct type __node, *__left, *__right, *__tmp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while (1) \ + { \ + if (__comp < 0) \ + { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0) \ + { \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } \ + else if (__comp > 0) \ + { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) \ + { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ + } -#define SPLAY_NEGINF -1 -#define SPLAY_INF 1 +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 -#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) -#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) -#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) -#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) -#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) -#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) -#define SPLAY_FOREACH(x, name, head) \ - for ((x) = SPLAY_MIN(name, head); \ - (x) != NULL; \ - (x) = SPLAY_NEXT(name, head, x)) +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) /* Macros that define a red-black tree */ -#define RB_HEAD(name, type) \ -struct name { \ - struct type *rbh_root; /* root of the tree */ \ -} +#define RB_HEAD(name, type) \ + struct name \ + { \ + struct type *rbh_root; /* root of the tree */ \ + } -#define RB_INITIALIZER(root) \ - { NULL } +#define RB_INITIALIZER(root) \ + {NULL} -#define RB_INIT(root) do { \ - (root)->rbh_root = NULL; \ -} while (/*CONSTCOND*/ 0) +#define RB_INIT(root) \ + do \ + { \ + (root)->rbh_root = NULL; \ + } while (/*CONSTCOND*/ 0) -#define RB_BLACK 0 -#define RB_RED 1 -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ + struct \ + { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ + } -#define RB_LEFT(elm, field) (elm)->field.rbe_left -#define RB_RIGHT(elm, field) (elm)->field.rbe_right -#define RB_PARENT(elm, field) (elm)->field.rbe_parent -#define RB_COLOR(elm, field) (elm)->field.rbe_color -#define RB_ROOT(head) (head)->rbh_root -#define RB_EMPTY(head) (RB_ROOT(head) == NULL) +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) -#define RB_SET(elm, parent, field) do { \ - RB_PARENT(elm, field) = parent; \ - RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ - RB_COLOR(elm, field) = RB_RED; \ -} while (/*CONSTCOND*/ 0) +#define RB_SET(elm, parent, field) \ + do \ + { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ + } while (/*CONSTCOND*/ 0) -#define RB_SET_BLACKRED(black, red, field) do { \ - RB_COLOR(black, field) = RB_BLACK; \ - RB_COLOR(red, field) = RB_RED; \ -} while (/*CONSTCOND*/ 0) +#define RB_SET_BLACKRED(black, red, field) \ + do \ + { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ + } while (/*CONSTCOND*/ 0) #ifndef RB_AUGMENT -#define RB_AUGMENT(x) do {} while (0) +#define RB_AUGMENT(x) \ + do \ + { \ + } while (0) #endif -#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ - (tmp) = RB_RIGHT(elm, field); \ - if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ - RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_LEFT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (/*CONSTCOND*/ 0) +#define RB_ROTATE_LEFT(head, elm, tmp, field) \ + do \ + { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) \ + { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) \ + { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } \ + else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ + } while (/*CONSTCOND*/ 0) -#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ - (tmp) = RB_LEFT(elm, field); \ - if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ - RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_RIGHT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (/*CONSTCOND*/ 0) +#define RB_ROTATE_RIGHT(head, elm, tmp, field) \ + do \ + { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) \ + { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) \ + { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } \ + else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ + } while (/*CONSTCOND*/ 0) /* Generates prototypes and inline functions */ -#define RB_PROTOTYPE(name, type, field, cmp) \ - RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) -#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, ) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) -#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ - RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \ - RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \ - RB_PROTOTYPE_INSERT(name, type, attr); \ - RB_PROTOTYPE_REMOVE(name, type, attr); \ - RB_PROTOTYPE_FIND(name, type, attr); \ - RB_PROTOTYPE_NFIND(name, type, attr); \ - RB_PROTOTYPE_NEXT(name, type, attr); \ - RB_PROTOTYPE_PREV(name, type, attr); \ +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ + RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \ + RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \ + RB_PROTOTYPE_INSERT(name, type, attr); \ + RB_PROTOTYPE_REMOVE(name, type, attr); \ + RB_PROTOTYPE_FIND(name, type, attr); \ + RB_PROTOTYPE_NFIND(name, type, attr); \ + RB_PROTOTYPE_NEXT(name, type, attr); \ + RB_PROTOTYPE_PREV(name, type, attr); \ RB_PROTOTYPE_MINMAX(name, type, attr); -#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \ +#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \ attr void name##_RB_INSERT_COLOR(struct name *, struct type *) -#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \ +#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \ attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *) -#define RB_PROTOTYPE_REMOVE(name, type, attr) \ +#define RB_PROTOTYPE_REMOVE(name, type, attr) \ attr struct type *name##_RB_REMOVE(struct name *, struct type *) -#define RB_PROTOTYPE_INSERT(name, type, attr) \ +#define RB_PROTOTYPE_INSERT(name, type, attr) \ attr struct type *name##_RB_INSERT(struct name *, struct type *) -#define RB_PROTOTYPE_FIND(name, type, attr) \ +#define RB_PROTOTYPE_FIND(name, type, attr) \ attr struct type *name##_RB_FIND(struct name *, struct type *) -#define RB_PROTOTYPE_NFIND(name, type, attr) \ +#define RB_PROTOTYPE_NFIND(name, type, attr) \ attr struct type *name##_RB_NFIND(struct name *, struct type *) -#define RB_PROTOTYPE_NEXT(name, type, attr) \ +#define RB_PROTOTYPE_NEXT(name, type, attr) \ attr struct type *name##_RB_NEXT(struct type *) -#define RB_PROTOTYPE_PREV(name, type, attr) \ +#define RB_PROTOTYPE_PREV(name, type, attr) \ attr struct type *name##_RB_PREV(struct type *) -#define RB_PROTOTYPE_MINMAX(name, type, attr) \ +#define RB_PROTOTYPE_MINMAX(name, type, attr) \ attr struct type *name##_RB_MINMAX(struct name *, int) /* Main rb operation. * Moves node close to the key of elm to top */ -#define RB_GENERATE(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp,) -#define RB_GENERATE_STATIC(name, type, field, cmp) \ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, ) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) -#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ - RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ - RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ - RB_GENERATE_INSERT(name, type, field, cmp, attr) \ - RB_GENERATE_REMOVE(name, type, field, attr) \ - RB_GENERATE_FIND(name, type, field, cmp, attr) \ - RB_GENERATE_NFIND(name, type, field, cmp, attr) \ - RB_GENERATE_NEXT(name, type, field, attr) \ - RB_GENERATE_PREV(name, type, field, attr) \ +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ + RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ + RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ + RB_GENERATE_INSERT(name, type, field, cmp, attr) \ + RB_GENERATE_REMOVE(name, type, field, attr) \ + RB_GENERATE_FIND(name, type, field, cmp, attr) \ + RB_GENERATE_NFIND(name, type, field, cmp, attr) \ + RB_GENERATE_NEXT(name, type, field, attr) \ + RB_GENERATE_PREV(name, type, field, attr) \ RB_GENERATE_MINMAX(name, type, field, attr) -#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ -attr void \ -name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ -{ \ - struct type *parent, *gparent, *tmp; \ - while ((parent = RB_PARENT(elm, field)) != NULL && \ - RB_COLOR(parent, field) == RB_RED) { \ - gparent = RB_PARENT(parent, field); \ - if (parent == RB_LEFT(gparent, field)) { \ - tmp = RB_RIGHT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_RIGHT(parent, field) == elm) { \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_RIGHT(head, gparent, tmp, field); \ - } else { \ - tmp = RB_LEFT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_LEFT(parent, field) == elm) { \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_LEFT(head, gparent, tmp, field); \ - } \ - } \ - RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} +#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ + attr void \ + name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ + { \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ + RB_COLOR(parent, field) == RB_RED) \ + { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) \ + { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) \ + { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) \ + { \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } \ + else \ + { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) \ + { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) \ + { \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ + } -#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ -attr void \ -name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ -{ \ - struct type *tmp; \ - while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ - elm != RB_ROOT(head)) { \ - if (RB_LEFT(parent, field) == elm) { \ - tmp = RB_RIGHT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ - struct type *oleft; \ - if ((oleft = RB_LEFT(tmp, field)) \ - != NULL) \ - RB_COLOR(oleft, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_RIGHT(head, tmp, oleft, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_RIGHT(tmp, field)) \ - RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } else { \ - tmp = RB_LEFT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ - struct type *oright; \ - if ((oright = RB_RIGHT(tmp, field)) \ - != NULL) \ - RB_COLOR(oright, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_LEFT(head, tmp, oright, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_LEFT(tmp, field)) \ - RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } \ - } \ - if (elm) \ - RB_COLOR(elm, field) = RB_BLACK; \ -} +#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ + attr void \ + name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ + { \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) \ + { \ + if (RB_LEFT(parent, field) == elm) \ + { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) \ + { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) \ + { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } \ + else \ + { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) \ + { \ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + else \ + { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) \ + { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) \ + { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } \ + else \ + { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) \ + { \ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) != NULL) \ + RB_COLOR(oright, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ + } -#define RB_GENERATE_REMOVE(name, type, field, attr) \ -attr struct type * \ -name##_RB_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *child, *parent, *old = elm; \ - int color; \ - if (RB_LEFT(elm, field) == NULL) \ - child = RB_RIGHT(elm, field); \ - else if (RB_RIGHT(elm, field) == NULL) \ - child = RB_LEFT(elm, field); \ - else { \ - struct type *left; \ - elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field)) != NULL) \ - elm = left; \ - child = RB_RIGHT(elm, field); \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ - if (RB_PARENT(elm, field) == old) \ - parent = elm; \ - (elm)->field = (old)->field; \ - if (RB_PARENT(old, field)) { \ - if (RB_LEFT(RB_PARENT(old, field), field) == old)\ - RB_LEFT(RB_PARENT(old, field), field) = elm;\ - else \ - RB_RIGHT(RB_PARENT(old, field), field) = elm;\ - RB_AUGMENT(RB_PARENT(old, field)); \ - } else \ - RB_ROOT(head) = elm; \ - RB_PARENT(RB_LEFT(old, field), field) = elm; \ - if (RB_RIGHT(old, field)) \ - RB_PARENT(RB_RIGHT(old, field), field) = elm; \ - if (parent) { \ - left = parent; \ - do { \ - RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field)) != NULL); \ - } \ - goto color; \ - } \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ -color: \ - if (color == RB_BLACK) \ - name##_RB_REMOVE_COLOR(head, parent, child); \ - return (old); \ -} \ +#define RB_GENERATE_REMOVE(name, type, field, attr) \ + attr struct type * \ + name##_RB_REMOVE(struct name *head, struct type *elm) \ + { \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else \ + { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) \ + { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } \ + else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) \ + { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old) \ + RB_LEFT(RB_PARENT(old, field), field) = elm; \ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm; \ + RB_AUGMENT(RB_PARENT(old, field)); \ + } \ + else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) \ + { \ + left = parent; \ + do \ + { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) \ + { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } \ + else \ + RB_ROOT(head) = child; \ + color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ + } -#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ -/* Inserts a node into the RB tree */ \ -attr struct type * \ -name##_RB_INSERT(struct name *head, struct type *elm) \ -{ \ - struct type *tmp; \ - struct type *parent = NULL; \ - int comp = 0; \ - tmp = RB_ROOT(head); \ - while (tmp) { \ - parent = tmp; \ - comp = (cmp)(elm, parent); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - RB_SET(elm, parent, field); \ - if (parent != NULL) { \ - if (comp < 0) \ - RB_LEFT(parent, field) = elm; \ - else \ - RB_RIGHT(parent, field) = elm; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = elm; \ - name##_RB_INSERT_COLOR(head, elm); \ - return (NULL); \ -} +#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ + /* Inserts a node into the RB tree */ \ + attr struct type * \ + name##_RB_INSERT(struct name *head, struct type *elm) \ + { \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) \ + { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) \ + { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } \ + else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ + } -#define RB_GENERATE_FIND(name, type, field, cmp, attr) \ -/* Finds the node with the same key as elm */ \ -attr struct type * \ -name##_RB_FIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (NULL); \ -} +#define RB_GENERATE_FIND(name, type, field, cmp, attr) \ + /* Finds the node with the same key as elm */ \ + attr struct type * \ + name##_RB_FIND(struct name *head, struct type *elm) \ + { \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) \ + { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ + } -#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \ -/* Finds the first node greater than or equal to the search key */ \ -attr struct type * \ -name##_RB_NFIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *res = NULL; \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) { \ - res = tmp; \ - tmp = RB_LEFT(tmp, field); \ - } \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (res); \ -} +#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \ + /* Finds the first node greater than or equal to the search key */ \ + attr struct type * \ + name##_RB_NFIND(struct name *head, struct type *elm) \ + { \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) \ + { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ + } -#define RB_GENERATE_NEXT(name, type, field, attr) \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_NEXT(struct type *elm) \ -{ \ - if (RB_RIGHT(elm, field)) { \ - elm = RB_RIGHT(elm, field); \ - while (RB_LEFT(elm, field)) \ - elm = RB_LEFT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} +#define RB_GENERATE_NEXT(name, type, field, attr) \ + /* ARGSUSED */ \ + attr struct type * \ + name##_RB_NEXT(struct type *elm) \ + { \ + if (RB_RIGHT(elm, field)) \ + { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } \ + else \ + { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else \ + { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ + } -#define RB_GENERATE_PREV(name, type, field, attr) \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_PREV(struct type *elm) \ -{ \ - if (RB_LEFT(elm, field)) { \ - elm = RB_LEFT(elm, field); \ - while (RB_RIGHT(elm, field)) \ - elm = RB_RIGHT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} +#define RB_GENERATE_PREV(name, type, field, attr) \ + /* ARGSUSED */ \ + attr struct type * \ + name##_RB_PREV(struct type *elm) \ + { \ + if (RB_LEFT(elm, field)) \ + { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } \ + else \ + { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else \ + { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ + } -#define RB_GENERATE_MINMAX(name, type, field, attr) \ -attr struct type * \ -name##_RB_MINMAX(struct name *head, int val) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *parent = NULL; \ - while (tmp) { \ - parent = tmp; \ - if (val < 0) \ - tmp = RB_LEFT(tmp, field); \ - else \ - tmp = RB_RIGHT(tmp, field); \ - } \ - return (parent); \ -} +#define RB_GENERATE_MINMAX(name, type, field, attr) \ + attr struct type * \ + name##_RB_MINMAX(struct name *head, int val) \ + { \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) \ + { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ + } -#define RB_NEGINF -1 -#define RB_INF 1 +#define RB_NEGINF -1 +#define RB_INF 1 -#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) -#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) -#define RB_FIND(name, x, y) name##_RB_FIND(x, y) -#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) -#define RB_NEXT(name, x, y) name##_RB_NEXT(y) -#define RB_PREV(name, x, y) name##_RB_PREV(y) -#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) -#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) -#define RB_FOREACH(x, name, head) \ - for ((x) = RB_MIN(name, head); \ - (x) != NULL; \ - (x) = name##_RB_NEXT(x)) +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) -#define RB_FOREACH_FROM(x, name, y) \ - for ((x) = (y); \ - ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ - (x) = (y)) +#define RB_FOREACH_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) -#define RB_FOREACH_SAFE(x, name, head, y) \ - for ((x) = RB_MIN(name, head); \ - ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ - (x) = (y)) +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) -#define RB_FOREACH_REVERSE(x, name, head) \ - for ((x) = RB_MAX(name, head); \ - (x) != NULL; \ - (x) = name##_RB_PREV(x)) +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) -#define RB_FOREACH_REVERSE_FROM(x, name, y) \ - for ((x) = (y); \ - ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ - (x) = (y)) +#define RB_FOREACH_REVERSE_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) -#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ - for ((x) = RB_MAX(name, head); \ - ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ - (x) = (y)) +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) -#endif /* _SYS_TREE_H_ */ +#endif /* _SYS_TREE_H_ */ diff --git a/tpws/params.c b/tpws/params.c index f2741aa..8e66a91 100644 --- a/tpws/params.c +++ b/tpws/params.c @@ -9,33 +9,33 @@ int DLOG_FILE(FILE *F, const char *format, va_list args) } int DLOG_CON(const char *format, int syslog_priority, va_list args) { - return DLOG_FILE(syslog_priority==LOG_ERR ? stderr : stdout, format, args); + return DLOG_FILE(syslog_priority == LOG_ERR ? stderr : stdout, format, args); } int DLOG_FILENAME(const char *filename, const char *format, va_list args) { int r; - FILE *F = fopen(filename,"at"); + FILE *F = fopen(filename, "at"); if (F) { r = DLOG_FILE(F, format, args); fclose(F); } else - r=-1; + r = -1; return r; } static char syslog_buf[1024]; -static size_t syslog_buf_sz=0; +static size_t syslog_buf_sz = 0; static void syslog_buffered(int priority, const char *format, va_list args) { - if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0) + if (vsnprintf(syslog_buf + syslog_buf_sz, sizeof(syslog_buf) - syslog_buf_sz, format, args) > 0) { - syslog_buf_sz=strlen(syslog_buf); + syslog_buf_sz = strlen(syslog_buf); // log when buffer is full or buffer ends with \n - if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n')) + if (syslog_buf_sz >= (sizeof(syslog_buf) - 1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz - 1] == '\n')) { - syslog(priority,"%s",syslog_buf); + syslog(priority, "%s", syslog_buf); syslog_buf_sz = 0; } } @@ -43,31 +43,31 @@ static void syslog_buffered(int priority, const char *format, va_list args) static int DLOG_VA(const char *format, int syslog_priority, bool condup, int level, va_list args) { - int r=0; + int r = 0; va_list args2; - if (condup && !(params.debug>=level && params.debug_target==LOG_TARGET_CONSOLE)) + if (condup && !(params.debug >= level && params.debug_target == LOG_TARGET_CONSOLE)) { - va_copy(args2,args); - DLOG_CON(format,syslog_priority,args2); + va_copy(args2, args); + DLOG_CON(format, syslog_priority, args2); } - if (params.debug>=level) + if (params.debug >= level) { - switch(params.debug_target) + switch (params.debug_target) { - case LOG_TARGET_CONSOLE: - r = DLOG_CON(format,syslog_priority,args); - break; - case LOG_TARGET_FILE: - r = DLOG_FILENAME(params.debug_logfile,format,args); - break; - case LOG_TARGET_SYSLOG: - // skip newlines - syslog_buffered(syslog_priority,format,args); - r = 1; - break; - default: - break; + case LOG_TARGET_CONSOLE: + r = DLOG_CON(format, syslog_priority, args); + break; + case LOG_TARGET_FILE: + r = DLOG_FILENAME(params.debug_logfile, format, args); + break; + case LOG_TARGET_SYSLOG: + // skip newlines + syslog_buffered(syslog_priority, format, args); + r = 1; + break; + default: + break; } } return r; @@ -105,11 +105,10 @@ int DLOG_PERROR(const char *s) return DLOG_ERR("%s: %s\n", s, strerror(errno)); } - int LOG_APPEND(const char *filename, const char *format, va_list args) { int r; - FILE *F = fopen(filename,"at"); + FILE *F = fopen(filename, "at"); if (F) { fprint_localtime(F); @@ -119,7 +118,7 @@ int LOG_APPEND(const char *filename, const char *format, va_list args) fclose(F); } else - r=-1; + r = -1; return r; } diff --git a/tpws/params.h b/tpws/params.h index ba65e82..5e9d9c8 100644 --- a/tpws/params.h +++ b/tpws/params.h @@ -11,21 +11,32 @@ #include "helpers.h" #include "protocol.h" -#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3 -#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 +#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3 +#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 -enum bindll { unwanted=0, no, prefer, force }; - -#define MAX_BINDS 32 -struct bind_s +enum bindll { - char bindaddr[64],bindiface[IF_NAMESIZE]; - bool bind_if6; - enum bindll bindll; - int bind_wait_ifup,bind_wait_ip,bind_wait_ip_ll; + unwanted = 0, + no, + prefer, + force }; -enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; +#define MAX_BINDS 32 +struct bind_s +{ + char bindaddr[64], bindiface[IF_NAMESIZE]; + bool bind_if6; + enum bindll bindll; + int bind_wait_ifup, bind_wait_ip, bind_wait_ip_ll; +}; + +enum log_target +{ + LOG_TARGET_CONSOLE = 0, + LOG_TARGET_FILE, + LOG_TARGET_SYSLOG +}; struct params_s { @@ -41,10 +52,10 @@ struct params_s uid_t uid; gid_t gid; bool daemon; - int maxconn,resolver_threads,maxfiles,max_orphan_time; - int local_rcvbuf,local_sndbuf,remote_rcvbuf,remote_sndbuf; + int maxconn, resolver_threads, maxfiles, max_orphan_time; + int local_rcvbuf, local_sndbuf, remote_rcvbuf, remote_sndbuf; #if defined(__linux__) || defined(__APPLE__) - int tcp_user_timeout_local,tcp_user_timeout_remote; + int tcp_user_timeout_local, tcp_user_timeout_remote; #endif bool tamper; // any tamper option is set @@ -74,8 +85,8 @@ struct params_s time_t hostlist_auto_mod_time; hostfail_pool *hostlist_auto_fail_counters; - bool tamper_start_n,tamper_cutoff_n; - unsigned int tamper_start,tamper_cutoff; + bool tamper_start_n, tamper_cutoff_n; + unsigned int tamper_start, tamper_cutoff; struct sockaddr_in connect_bind4; struct sockaddr_in6 connect_bind6; diff --git a/tpws/pools.c b/tpws/pools.c index 785b04d..9639918 100644 --- a/tpws/pools.c +++ b/tpws/pools.c @@ -5,33 +5,33 @@ #include #define DESTROY_STR_POOL(etype, ppool) \ - etype *elem, *tmp; \ - HASH_ITER(hh, *ppool, elem, tmp) { \ - free(elem->str); \ - HASH_DEL(*ppool, elem); \ - free(elem); \ - } - -#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \ - etype *elem; \ - if (!(elem = (etype*)malloc(sizeof(etype)))) \ - return false; \ - if (!(elem->str = malloc(keystr_len + 1))) \ - { \ - free(elem); \ - return false; \ - } \ - memcpy(elem->str, keystr, keystr_len); \ - elem->str[keystr_len] = 0; \ - oom = false; \ - HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \ - if (oom) \ - { \ - free(elem->str); \ - free(elem); \ - return false; \ + etype *elem, *tmp; \ + HASH_ITER(hh, *ppool, elem, tmp) \ + { \ + free(elem->str); \ + HASH_DEL(*ppool, elem); \ + free(elem); \ } +#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \ + etype *elem; \ + if (!(elem = (etype *)malloc(sizeof(etype)))) \ + return false; \ + if (!(elem->str = malloc(keystr_len + 1))) \ + { \ + free(elem); \ + return false; \ + } \ + memcpy(elem->str, keystr, keystr_len); \ + elem->str[keystr_len] = 0; \ + oom = false; \ + HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \ + if (oom) \ + { \ + free(elem->str); \ + free(elem); \ + return false; \ + } #undef uthash_nonfatal_oom #define uthash_nonfatal_oom(elt) ut_oom_recover(elt) @@ -65,13 +65,8 @@ void StrPoolDestroy(strpool **pp) DESTROY_STR_POOL(strpool, pp) } - - -void HostFailPoolDestroy(hostfail_pool **pp) -{ - DESTROY_STR_POOL(hostfail_pool, pp) -} -hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time) +void HostFailPoolDestroy(hostfail_pool **pp){ + DESTROY_STR_POOL(hostfail_pool, pp)} hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time) { size_t slen = strlen(s); ADD_STR_POOL(hostfail_pool, pp, s, slen) @@ -79,7 +74,7 @@ hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time) elem->counter = 0; return elem; } -hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s) +hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s) { hostfail_pool *elem; HASH_FIND_STR(p, s, elem); @@ -104,7 +99,7 @@ void HostFailPoolPurge(hostfail_pool **pp) } } } -static time_t host_fail_purge_prev=0; +static time_t host_fail_purge_prev = 0; void HostFailPoolPurgeRateLimited(hostfail_pool **pp) { time_t now = time(NULL); @@ -120,14 +115,14 @@ void HostFailPoolDump(hostfail_pool *p) hostfail_pool *elem, *tmp; time_t now = time(NULL); HASH_ITER(hh, p, elem, tmp) - printf("host=%s counter=%d time_left=%lld\n",elem->str,elem->counter,(long long int)elem->expire-now); + printf("host=%s counter=%d time_left=%lld\n", elem->str, elem->counter, (long long int)elem->expire - now); } - bool strlist_add(struct str_list_head *head, const char *filename) { struct str_list *entry = malloc(sizeof(struct str_list)); - if (!entry) return false; + if (!entry) + return false; entry->str = strdup(filename); if (!entry->str) { @@ -139,7 +134,8 @@ bool strlist_add(struct str_list_head *head, const char *filename) } static void strlist_entry_destroy(struct str_list *entry) { - if (entry->str) free(entry->str); + if (entry->str) + free(entry->str); free(entry); } void strlist_destroy(struct str_list_head *head) diff --git a/tpws/pools.h b/tpws/pools.h index ab58968..b61245c 100644 --- a/tpws/pools.h +++ b/tpws/pools.h @@ -5,38 +5,41 @@ #include #include -//#define HASH_BLOOM 20 +// #define HASH_BLOOM 20 #define HASH_NONFATAL_OOM 1 #define HASH_FUNCTION HASH_BER #include "uthash.h" -typedef struct strpool { - char *str; /* key */ - UT_hash_handle hh; /* makes this structure hashable */ +typedef struct strpool +{ + char *str; /* key */ + UT_hash_handle hh; /* makes this structure hashable */ } strpool; void StrPoolDestroy(strpool **pp); -bool StrPoolAddStr(strpool **pp,const char *s); -bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen); -bool StrPoolCheckStr(strpool *p,const char *s); +bool StrPoolAddStr(strpool **pp, const char *s); +bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen); +bool StrPoolCheckStr(strpool *p, const char *s); -struct str_list { - char *str; - LIST_ENTRY(str_list) next; +struct str_list +{ + char *str; + LIST_ENTRY(str_list) + next; }; LIST_HEAD(str_list_head, str_list); - -typedef struct hostfail_pool { - char *str; /* key */ - int counter; /* value */ - time_t expire; /* when to expire record (unixtime) */ - UT_hash_handle hh; /* makes this structure hashable */ +typedef struct hostfail_pool +{ + char *str; /* key */ + int counter; /* value */ + time_t expire; /* when to expire record (unixtime) */ + UT_hash_handle hh; /* makes this structure hashable */ } hostfail_pool; void HostFailPoolDestroy(hostfail_pool **pp); -hostfail_pool *HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time); -hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s); +hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time); +hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s); void HostFailPoolDel(hostfail_pool **pp, hostfail_pool *elem); void HostFailPoolPurge(hostfail_pool **pp); void HostFailPoolPurgeRateLimited(hostfail_pool **pp); diff --git a/tpws/protocol.c b/tpws/protocol.c index 22e89c5..526ad68 100644 --- a/tpws/protocol.c +++ b/tpws/protocol.c @@ -7,8 +7,7 @@ #include #include - -const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL }; +const char *http_methods[] = {"GET /", "POST /", "HEAD /", "OPTIONS /", "PUT /", "DELETE /", "CONNECT /", "TRACE /", NULL}; const char *HttpMethod(const uint8_t *data, size_t len) { const char **method; @@ -23,56 +22,63 @@ const char *HttpMethod(const uint8_t *data, size_t len) } bool IsHttp(const uint8_t *data, size_t len) { - return !!HttpMethod(data,len); + return !!HttpMethod(data, len); } // pHost points to "Host: ..." -bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs) +bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs) { if (!*pHost) { *pHost = memmem(buf, bs, "\nHost:", 6); - if (*pHost) (*pHost)++; + if (*pHost) + (*pHost)++; } return !!*pHost; } -bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs) +bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs) { if (!*pHost) { *pHost = memmem(buf, bs, "\nHost:", 6); - if (*pHost) (*pHost)++; + if (*pHost) + (*pHost)++; } return !!*pHost; } bool IsHttpReply(const uint8_t *data, size_t len) { // HTTP/1.x 200\r\n - return len>14 && !memcmp(data,"HTTP/1.",7) && (data[7]=='0' || data[7]=='1') && data[8]==' ' && - data[9]>='0' && data[9]<='9' && - data[10]>='0' && data[10]<='9' && - data[11]>='0' && data[11]<='9'; + return len > 14 && !memcmp(data, "HTTP/1.", 7) && (data[7] == '0' || data[7] == '1') && data[8] == ' ' && + data[9] >= '0' && data[9] <= '9' && + data[10] >= '0' && data[10] <= '9' && + data[11] >= '0' && data[11] <= '9'; } int HttpReplyCode(const uint8_t *data, size_t len) { - return (data[9]-'0')*100 + (data[10]-'0')*10 + (data[11]-'0'); + return (data[9] - '0') * 100 + (data[10] - '0') * 10 + (data[11] - '0'); } bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf) { const uint8_t *p, *s, *e = data + len; - p = (uint8_t*)strncasestr((char*)data, header, len); - if (!p) return false; + p = (uint8_t *)strncasestr((char *)data, header, len); + if (!p) + return false; p += strlen(header); - while (p < e && (*p == ' ' || *p == '\t')) p++; + while (p < e && (*p == ' ' || *p == '\t')) + p++; s = p; - while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t')) s++; + while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t')) + s++; if (s > p) { size_t slen = s - p; if (buf && len_buf) { - if (slen >= len_buf) slen = len_buf - 1; - for (size_t i = 0; i < slen; i++) buf[i] = tolower(p[i]); + if (slen >= len_buf) + slen = len_buf - 1; + for (size_t i = 0; i < slen; i++) + buf[i] = tolower(p[i]); buf[slen] = 0; } return true; @@ -85,85 +91,98 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos } const char *HttpFind2ndLevelDomain(const char *host) { - const char *p=NULL; + const char *p = NULL; if (*host) { - for (p = host + strlen(host)-1; p>host && *p!='.'; p--); - if (*p=='.') for (p--; p>host && *p!='.'; p--); - if (*p=='.') p++; + for (p = host + strlen(host) - 1; p > host && *p != '.'; p--) + ; + if (*p == '.') + for (p--; p > host && *p != '.'; p--) + ; + if (*p == '.') + p++; } return p; } // DPI redirects are global redirects to another domain bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host) { - char loc[256],*redirect_host, *p; + char loc[256], *redirect_host, *p; int code; - - if (!host || !*host) return false; - - code = HttpReplyCode(data,len); - - if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false; + + if (!host || !*host) + return false; + + code = HttpReplyCode(data, len); + + if ((code != 302 && code != 307) || !HttpExtractHeader(data, len, "\nLocation:", loc, sizeof(loc))) + return false; // something like : https://censor.net/badpage.php?reason=denied&source=RKN - - if (!strncmp(loc,"http://",7)) - redirect_host=loc+7; - else if (!strncmp(loc,"https://",8)) - redirect_host=loc+8; + + if (!strncmp(loc, "http://", 7)) + redirect_host = loc + 7; + else if (!strncmp(loc, "https://", 8)) + redirect_host = loc + 8; else return false; - + // somethinkg like : censor.net/badpage.php?reason=denied&source=RKN - - for(p=redirect_host; *p && *p!='/' ; p++); - *p=0; - if (!*redirect_host) return false; + + for (p = redirect_host; *p && *p != '/'; p++) + ; + *p = 0; + if (!*redirect_host) + return false; // somethinkg like : censor.net - + // extract 2nd level domains const char *dhost = HttpFind2ndLevelDomain(host); const char *drhost = HttpFind2ndLevelDomain(redirect_host); - - return strcasecmp(dhost, drhost)!=0; + + return strcasecmp(dhost, drhost) != 0; } size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz) { const uint8_t *method, *host; int i; - - switch(tpos_type) + + switch (tpos_type) { - case httpreqpos_method: - // recognize some tpws pre-applied hacks - method=http; - if (sz<10) break; - if (*method=='\n' || *method=='\r') method++; - if (*method=='\n' || *method=='\r') method++; - for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++; - if (i<3 || *method!=' ') break; - return method-http-1; - case httpreqpos_host: - if (HttpFindHostConst(&host,http,sz) && (host-http+7)= 'A' && *method <= 'Z') + method++; + if (i < 3 || *method != ' ') break; - default: - return 0; + return method - http - 1; + case httpreqpos_host: + if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz) + { + host += 5; + if (*host == ' ') + host++; + return host - http; + } + break; + case httpreqpos_pos: + break; + default: + return 0; } - return hpos_pos= 4) { uint16_t etype = pntoh16(data); size_t elen = pntoh16(data + 2); - data += 4; l -= 4; - if (l < elen) break; + data += 4; + l -= 4; + if (l < elen) + break; if (etype == type) { if (ext && len_ext) @@ -245,7 +275,8 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const } return true; } - data += elen; l -= elen; + data += elen; + l -= elen; } return false; @@ -257,9 +288,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t ** // u16 Version: TLS1.0 // u16 Length size_t reclen; - if (!IsTLSClientHello(data, len, bPartialIsOK)) return false; - reclen=TLSRecordLen(data); - if (reclen= len_host) slen = len_host - 1; - for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]); + if (slen >= len_host) + slen = len_host - 1; + for (size_t i = 0; i < slen; i++) + host[i] = tolower(ext[i]); host[slen] = 0; } return true; @@ -284,7 +322,8 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len const uint8_t *ext; size_t elen; - if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK)) return false; + if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK)) + return false; return TLSExtractHostFromExt(ext, elen, host, len_host); } bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK) @@ -292,23 +331,24 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos const uint8_t *ext; size_t elen; - if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false; + if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) + return false; return TLSExtractHostFromExt(ext, elen, host, len_host); } size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type) { size_t elen; const uint8_t *ext; - switch(tpos_type) + switch (tpos_type) { - case tlspos_sni: - case tlspos_sniext: - if (TLSFindExt(tls,sz,0,&ext,&elen,false)) - return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1; - // fall through - case tlspos_pos: - return tpos_pos - #ifndef IP6T_SO_ORIGINAL_DST - #define IP6T_SO_ORIGINAL_DST 80 - #endif +#include +#ifndef IP6T_SO_ORIGINAL_DST +#define IP6T_SO_ORIGINAL_DST 80 +#endif #endif - #if defined(BSD) #include #include -static int redirector_fd=-1; +static int redirector_fd = -1; void redir_close(void) { - if (redirector_fd!=-1) + if (redirector_fd != -1) { close(redirector_fd); redirector_fd = -1; @@ -43,7 +42,7 @@ static bool redir_open_private(const char *fname, int flags) DLOG_PERROR("redir_openv_private"); return false; } - DBGPRINT("opened redirector %s\n",fname); + DBGPRINT("opened redirector %s\n", fname); return true; } bool redir_init(void) @@ -56,74 +55,79 @@ static bool destination_from_pf(const struct sockaddr *accept_sa, struct sockadd struct pfioc_natlook nl; struct sockaddr_storage asa2; - if (redirector_fd==-1) return false; + if (redirector_fd == -1) + return false; - if (params.debug>=2) + if (params.debug >= 2) { - char s[48],s2[48]; - *s=0; ntop46_port(accept_sa, s, sizeof(s)); - *s2=0; ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2)); - DBGPRINT("destination_from_pf %s %s\n",s,s2); + char s[48], s2[48]; + *s = 0; + ntop46_port(accept_sa, s, sizeof(s)); + *s2 = 0; + ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2)); + DBGPRINT("destination_from_pf %s %s\n", s, s2); } saconvmapped(orig_dst); - if (accept_sa->sa_family==AF_INET6 && orig_dst->ss_family==AF_INET) + if (accept_sa->sa_family == AF_INET6 && orig_dst->ss_family == AF_INET) { - memcpy(&asa2,accept_sa,sizeof(struct sockaddr_in6)); + memcpy(&asa2, accept_sa, sizeof(struct sockaddr_in6)); saconvmapped(&asa2); - accept_sa = (struct sockaddr*)&asa2; + accept_sa = (struct sockaddr *)&asa2; } - if (params.debug>=2) + if (params.debug >= 2) { - char s[48],s2[48]; - *s=0; ntop46_port(accept_sa, s, sizeof(s)); - *s2=0; ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2)); - DBGPRINT("destination_from_pf (saconvmapped) %s %s\n",s,s2); + char s[48], s2[48]; + *s = 0; + ntop46_port(accept_sa, s, sizeof(s)); + *s2 = 0; + ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2)); + DBGPRINT("destination_from_pf (saconvmapped) %s %s\n", s, s2); } - if (accept_sa->sa_family!=orig_dst->ss_family) + if (accept_sa->sa_family != orig_dst->ss_family) { DBGPRINT("accept_sa and orig_dst sa_family mismatch : %d %d\n", accept_sa->sa_family, orig_dst->ss_family); return false; } memset(&nl, 0, sizeof(nl)); - nl.proto = IPPROTO_TCP; - nl.direction = PF_OUT; + nl.proto = IPPROTO_TCP; + nl.direction = PF_OUT; nl.af = orig_dst->ss_family; - switch(orig_dst->ss_family) + switch (orig_dst->ss_family) { case AF_INET: - { + { struct sockaddr_in *sin = (struct sockaddr_in *)orig_dst; nl.daddr.v4.s_addr = sin->sin_addr.s_addr; - nl.saddr.v4.s_addr = ((struct sockaddr_in*)accept_sa)->sin_addr.s_addr; + nl.saddr.v4.s_addr = ((struct sockaddr_in *)accept_sa)->sin_addr.s_addr; #ifdef __APPLE__ - nl.sxport.port = ((struct sockaddr_in*)accept_sa)->sin_port; - nl.dxport.port = sin->sin_port; + nl.sxport.port = ((struct sockaddr_in *)accept_sa)->sin_port; + nl.dxport.port = sin->sin_port; #else - nl.sport = ((struct sockaddr_in*)accept_sa)->sin_port; - nl.dport = sin->sin_port; + nl.sport = ((struct sockaddr_in *)accept_sa)->sin_port; + nl.dport = sin->sin_port; #endif - } - break; + } + break; case AF_INET6: - { + { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)orig_dst; nl.daddr.v6 = sin6->sin6_addr; - nl.saddr.v6 = ((struct sockaddr_in6*)accept_sa)->sin6_addr; + nl.saddr.v6 = ((struct sockaddr_in6 *)accept_sa)->sin6_addr; #ifdef __APPLE__ - nl.sxport.port = ((struct sockaddr_in6*)accept_sa)->sin6_port; + nl.sxport.port = ((struct sockaddr_in6 *)accept_sa)->sin6_port; nl.dxport.port = sin6->sin6_port; #else - nl.sport = ((struct sockaddr_in6*)accept_sa)->sin6_port; + nl.sport = ((struct sockaddr_in6 *)accept_sa)->sin6_port; nl.dport = sin6->sin6_port; #endif - } - break; + } + break; default: - DBGPRINT("destination_from_pf : unexpected address family %d\n",orig_dst->ss_family); + DBGPRINT("destination_from_pf : unexpected address family %d\n", orig_dst->ss_family); return false; } @@ -134,45 +138,42 @@ static bool destination_from_pf(const struct sockaddr *accept_sa, struct sockadd } DBGPRINT("destination_from_pf : got orig dest addr from pf\n"); - switch(nl.af) + switch (nl.af) { case AF_INET: orig_dst->ss_family = nl.af; #ifdef __APPLE__ - ((struct sockaddr_in*)orig_dst)->sin_port = nl.rdxport.port; + ((struct sockaddr_in *)orig_dst)->sin_port = nl.rdxport.port; #else - ((struct sockaddr_in*)orig_dst)->sin_port = nl.rdport; + ((struct sockaddr_in *)orig_dst)->sin_port = nl.rdport; #endif - ((struct sockaddr_in*)orig_dst)->sin_addr = nl.rdaddr.v4; + ((struct sockaddr_in *)orig_dst)->sin_addr = nl.rdaddr.v4; break; case AF_INET6: orig_dst->ss_family = nl.af; #ifdef __APPLE__ - ((struct sockaddr_in6*)orig_dst)->sin6_port = nl.rdxport.port; + ((struct sockaddr_in6 *)orig_dst)->sin6_port = nl.rdxport.port; #else - ((struct sockaddr_in6*)orig_dst)->sin6_port = nl.rdport; + ((struct sockaddr_in6 *)orig_dst)->sin6_port = nl.rdport; #endif - ((struct sockaddr_in6*)orig_dst)->sin6_addr = nl.rdaddr.v6; + ((struct sockaddr_in6 *)orig_dst)->sin6_addr = nl.rdaddr.v6; break; default: - DBGPRINT("destination_from_pf : DIOCNATLOOK returned unexpected address family %d\n",nl.af); + DBGPRINT("destination_from_pf : DIOCNATLOOK returned unexpected address family %d\n", nl.af); return false; } return true; } - #else -bool redir_init(void) {return true;} +bool redir_init(void) { return true; } void redir_close(void) {}; #endif - - -//Store the original destination address in orig_dst +// Store the original destination address in orig_dst bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr_storage *orig_dst) { char orig_dst_str[INET6_ADDRSTRLEN]; @@ -181,28 +182,28 @@ bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr memset(orig_dst, 0, addrlen); - //For UDP transparent proxying: - //Set IP_RECVORIGDSTADDR socket option for getting the original - //destination of a datagram + // For UDP transparent proxying: + // Set IP_RECVORIGDSTADDR socket option for getting the original + // destination of a datagram #ifdef __linux__ // DNAT - r=getsockopt(sockfd, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr*) orig_dst, &addrlen); - if (r<0) - r = getsockopt(sockfd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, (struct sockaddr*) orig_dst, &addrlen); - if (r<0) + r = getsockopt(sockfd, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr *)orig_dst, &addrlen); + if (r < 0) + r = getsockopt(sockfd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, (struct sockaddr *)orig_dst, &addrlen); + if (r < 0) { DBGPRINT("both SO_ORIGINAL_DST and IP6T_SO_ORIGINAL_DST failed !\n"); #endif // TPROXY : socket is bound to original destination - r=getsockname(sockfd, (struct sockaddr*) orig_dst, &addrlen); - if (r<0) + r = getsockname(sockfd, (struct sockaddr *)orig_dst, &addrlen); + if (r < 0) { DLOG_PERROR("getsockname"); return false; } - if (orig_dst->ss_family==AF_INET6) - ((struct sockaddr_in6*)orig_dst)->sin6_scope_id=0; // or MacOS will not connect() + if (orig_dst->ss_family == AF_INET6) + ((struct sockaddr_in6 *)orig_dst)->sin6_scope_id = 0; // or macOS will not connect() #ifdef BSD if (params.pf_enable && !destination_from_pf(accept_sa, orig_dst)) DBGPRINT("pf filter destination_from_pf failed\n"); @@ -217,13 +218,13 @@ bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr { if (orig_dst->ss_family == AF_INET) { - inet_ntop(AF_INET, &(((struct sockaddr_in*) orig_dst)->sin_addr), orig_dst_str, INET_ADDRSTRLEN); - VPRINT("Original destination for socket fd=%d : %s:%d\n", sockfd,orig_dst_str, htons(((struct sockaddr_in*) orig_dst)->sin_port)); + inet_ntop(AF_INET, &(((struct sockaddr_in *)orig_dst)->sin_addr), orig_dst_str, INET_ADDRSTRLEN); + VPRINT("Original destination for socket fd=%d : %s:%d\n", sockfd, orig_dst_str, htons(((struct sockaddr_in *)orig_dst)->sin_port)); } else if (orig_dst->ss_family == AF_INET6) { - inet_ntop(AF_INET6,&(((struct sockaddr_in6*) orig_dst)->sin6_addr), orig_dst_str, INET6_ADDRSTRLEN); - VPRINT("Original destination for socket fd=%d : [%s]:%d\n", sockfd,orig_dst_str, htons(((struct sockaddr_in6*) orig_dst)->sin6_port)); + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)orig_dst)->sin6_addr), orig_dst_str, INET6_ADDRSTRLEN); + VPRINT("Original destination for socket fd=%d : [%s]:%d\n", sockfd, orig_dst_str, htons(((struct sockaddr_in6 *)orig_dst)->sin6_port)); } } return true; diff --git a/tpws/resolver.c b/tpws/resolver.c index b9c204f..2176432 100644 --- a/tpws/resolver.c +++ b/tpws/resolver.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -17,7 +17,7 @@ #define SIG_BREAK SIGUSR1 #ifdef __APPLE__ - static const char *sem_name="/tpws_resolver"; +static const char *sem_name = "/tpws_resolver"; #endif TAILQ_HEAD(resolve_tailhead, resolve_item); @@ -35,7 +35,7 @@ typedef struct pthread_t *thread; bool bInit, bStop; } t_resolver; -static t_resolver resolver = { .bInit = false }; +static t_resolver resolver = {.bInit = false}; #define rlist_lock pthread_mutex_lock(&resolver.resolve_list_lock) #define rlist_unlock pthread_mutex_unlock(&resolver.resolve_list_lock) @@ -47,7 +47,8 @@ static void resolver_clear_list(void) for (;;) { ri = TAILQ_FIRST(&resolver.resolve_list); - if (!ri) break; + if (!ri) + break; TAILQ_REMOVE(&resolver.resolve_list, ri, next); free(ri); } @@ -57,7 +58,7 @@ int resolver_thread_count(void) { return resolver.bInit ? resolver.threads : 0; } - + static void *resolver_thread(void *arg) { int r; @@ -66,15 +67,17 @@ static void *resolver_thread(void *arg) sigemptyset(&signal_mask); sigaddset(&signal_mask, SIG_BREAK); - //printf("resolver_thread %d start\n",syscall(SYS_gettid)); - for(;;) + // printf("resolver_thread %d start\n",syscall(SYS_gettid)); + for (;;) { - if (resolver.bStop) break; + if (resolver.bStop) + break; r = sem_wait(resolver.sem); - if (resolver.bStop) break; + if (resolver.bStop) + break; if (r) { - if (errno!=EINTR) + if (errno != EINTR) { DLOG_PERROR("sem_wait (resolver_thread)"); break; // fatal err @@ -87,36 +90,37 @@ static void *resolver_thread(void *arg) rlist_lock; ri = TAILQ_FIRST(&resolver.resolve_list); - if (ri) TAILQ_REMOVE(&resolver.resolve_list, ri, next); + if (ri) + TAILQ_REMOVE(&resolver.resolve_list, ri, next); rlist_unlock; if (ri) { - struct addrinfo *ai,hints; + struct addrinfo *ai, hints; char sport[6]; - //printf("THREAD %d GOT JOB %s\n", syscall(SYS_gettid), ri->dom); - snprintf(sport,sizeof(sport),"%u",ri->port); + // printf("THREAD %d GOT JOB %s\n", syscall(SYS_gettid), ri->dom); + snprintf(sport, sizeof(sport), "%u", ri->port); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; // unfortunately getaddrinfo cannot be interrupted with a signal. we cannot cancel a query - ri->ga_res = getaddrinfo(ri->dom,sport,&hints,&ai); + ri->ga_res = getaddrinfo(ri->dom, sport, &hints, &ai); if (!ri->ga_res) { memcpy(&ri->ss, ai->ai_addr, ai->ai_addrlen); freeaddrinfo(ai); } - //printf("THREAD %d END JOB %s FIRST=%p\n", syscall(SYS_gettid), ri->dom, TAILQ_FIRST(&resolver.resolve_list)); + // printf("THREAD %d END JOB %s FIRST=%p\n", syscall(SYS_gettid), ri->dom, TAILQ_FIRST(&resolver.resolve_list)); // never interrupt this pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); - wr = write(resolver.fd_signal_pipe,&ri,sizeof(void*)); - if (wr<0) + wr = write(resolver.fd_signal_pipe, &ri, sizeof(void *)); + if (wr < 0) { free(ri); DLOG_PERROR("write resolve_pipe"); } - else if (wr!=sizeof(void*)) + else if (wr != sizeof(void *)) { // partial pointer write is FATAL. in any case it will cause pointer corruption and coredump free(ri); @@ -127,7 +131,7 @@ static void *resolver_thread(void *arg) } } } - //printf("resolver_thread %d exit\n",syscall(SYS_gettid)); + // printf("resolver_thread %d exit\n",syscall(SYS_gettid)); return NULL; } @@ -149,19 +153,19 @@ void resolver_deinit(void) pthread_kill(resolver.thread[t], SIGUSR1); pthread_join(resolver.thread[t], NULL); } - + pthread_mutex_destroy(&resolver.resolve_list_lock); free(resolver.thread); - #ifdef __APPLE__ - sem_close(resolver.sem); - #else - sem_destroy(resolver.sem); - #endif +#ifdef __APPLE__ + sem_close(resolver.sem); +#else + sem_destroy(resolver.sem); +#endif resolver_clear_list(); - memset(&resolver,0,sizeof(resolver)); + memset(&resolver, 0, sizeof(resolver)); } } @@ -170,18 +174,19 @@ bool resolver_init(int threads, int fd_signal_pipe) int t; struct sigaction action; - if (threads<1 || resolver.bInit) return false; + if (threads < 1 || resolver.bInit) + return false; - memset(&resolver,0,sizeof(resolver)); + memset(&resolver, 0, sizeof(resolver)); resolver.bInit = true; #ifdef __APPLE__ // MacOS does not support unnamed semaphores char sn[64]; - snprintf(sn,sizeof(sn),"%s_%d",sem_name,getpid()); - resolver.sem = sem_open(sn,O_CREAT,0600,0); - if (resolver.sem==SEM_FAILED) + snprintf(sn, sizeof(sn), "%s_%d", sem_name, getpid()); + resolver.sem = sem_open(sn, O_CREAT, 0600, 0); + if (resolver.sem == SEM_FAILED) { DLOG_PERROR("sem_open"); goto ex; @@ -189,48 +194,51 @@ bool resolver_init(int threads, int fd_signal_pipe) // unlink immediately to remove tails sem_unlink(sn); #else - if (sem_init(&resolver._sem,0,0)==-1) - { + if (sem_init(&resolver._sem, 0, 0) == -1) + { DLOG_PERROR("sem_init"); goto ex; } resolver.sem = &resolver._sem; #endif - if (pthread_mutex_init(&resolver.resolve_list_lock, NULL)) goto ex; + if (pthread_mutex_init(&resolver.resolve_list_lock, NULL)) + goto ex; resolver.fd_signal_pipe = fd_signal_pipe; TAILQ_INIT(&resolver.resolve_list); // start as many threads as we can up to specified number - resolver.thread = malloc(sizeof(pthread_t)*threads); - if (!resolver.thread) goto ex; + resolver.thread = malloc(sizeof(pthread_t) * threads); + if (!resolver.thread) + goto ex; - memset(&action,0,sizeof(action)); + memset(&action, 0, sizeof(action)); action.sa_handler = sigbreak; sigaction(SIG_BREAK, &action, NULL); - pthread_attr_t attr; - if (pthread_attr_init(&attr)) goto ex; + if (pthread_attr_init(&attr)) + goto ex; // set minimum thread stack size - if (pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN>20480 ? PTHREAD_STACK_MIN : 20480)) + if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN > 20480 ? PTHREAD_STACK_MIN : 20480)) { pthread_attr_destroy(&attr); goto ex; } - for(t=0, resolver.threads=threads ; tdom,dom,sizeof(ri->dom)); - ri->dom[sizeof(ri->dom)-1] = 0; + strncpy(ri->dom, dom, sizeof(ri->dom)); + ri->dom[sizeof(ri->dom) - 1] = 0; ri->port = port; ri->ptr = ptr; rlist_lock; TAILQ_INSERT_TAIL(&resolver.resolve_list, ri, next); rlist_unlock; - if (sem_post(resolver.sem)<0) + if (sem_post(resolver.sem) < 0) { DLOG_PERROR("resolver_queue sem_post"); free(ri); diff --git a/tpws/resolver.h b/tpws/resolver.h index 3151717..9537fb7 100644 --- a/tpws/resolver.h +++ b/tpws/resolver.h @@ -8,12 +8,13 @@ struct resolve_item { - char dom[256]; // request dom + char dom[256]; // request dom struct sockaddr_storage ss; // resolve result - int ga_res; // getaddrinfo result code - uint16_t port; // request port + int ga_res; // getaddrinfo result code + uint16_t port; // request port void *ptr; - TAILQ_ENTRY(resolve_item) next; + TAILQ_ENTRY(resolve_item) + next; }; struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr); diff --git a/tpws/sec.c b/tpws/sec.c index 873c875..93acc35 100644 --- a/tpws/sec.c +++ b/tpws/sec.c @@ -23,103 +23,102 @@ // block most of the undesired syscalls to harden against code execution static long blocked_syscalls[] = { #ifdef SYS_execv -SYS_execv, + SYS_execv, #endif -SYS_execve, + SYS_execve, #ifdef SYS_execveat -SYS_execveat, + SYS_execveat, #endif #ifdef SYS_exec_with_loader -SYS_exec_with_loader, + SYS_exec_with_loader, #endif #ifdef SYS_osf_execve -SYS_osf_execve, + SYS_osf_execve, #endif #ifdef SYS_uselib -SYS_uselib, + SYS_uselib, #endif #ifdef SYS_unlink -SYS_unlink, + SYS_unlink, #endif -SYS_unlinkat, + SYS_unlinkat, #ifdef SYS_chmod -SYS_chmod, + SYS_chmod, #endif -SYS_fchmod,SYS_fchmodat, + SYS_fchmod, SYS_fchmodat, #ifdef SYS_chown -SYS_chown, + SYS_chown, #endif #ifdef SYS_chown32 -SYS_chown32, + SYS_chown32, #endif -SYS_fchown, + SYS_fchown, #ifdef SYS_fchown32 -SYS_fchown32, + SYS_fchown32, #endif #ifdef SYS_lchown -SYS_lchown, + SYS_lchown, #endif #ifdef SYS_lchown32 -SYS_lchown32, + SYS_lchown32, #endif -SYS_fchownat, + SYS_fchownat, #ifdef SYS_symlink -SYS_symlink, + SYS_symlink, #endif -SYS_symlinkat, + SYS_symlinkat, #ifdef SYS_link -SYS_link, + SYS_link, #endif -SYS_linkat, -SYS_truncate, + SYS_linkat, + SYS_truncate, #ifdef SYS_truncate64 -SYS_truncate64, + SYS_truncate64, #endif -SYS_ftruncate, + SYS_ftruncate, #ifdef SYS_ftruncate64 -SYS_ftruncate64, + SYS_ftruncate64, #endif #ifdef SYS_mknod -SYS_mknod, + SYS_mknod, #endif -SYS_mknodat, + SYS_mknodat, #ifdef SYS_mkdir -SYS_mkdir, + SYS_mkdir, #endif -SYS_mkdirat, + SYS_mkdirat, #ifdef SYS_rmdir -SYS_rmdir, + SYS_rmdir, #endif #ifdef SYS_rename -SYS_rename, + SYS_rename, #endif #ifdef SYS_renameat2 -SYS_renameat2, + SYS_renameat2, #endif #ifdef SYS_renameat -SYS_renameat, + SYS_renameat, #endif #ifdef SYS_readdir -SYS_readdir, + SYS_readdir, #endif #ifdef SYS_getdents -SYS_getdents, + SYS_getdents, #endif #ifdef SYS_getdents64 -SYS_getdents64, + SYS_getdents64, #endif #ifdef SYS_process_vm_readv -SYS_process_vm_readv, + SYS_process_vm_readv, #endif #ifdef SYS_process_vm_writev -SYS_process_vm_writev, + SYS_process_vm_writev, #endif #ifdef SYS_process_madvise -SYS_process_madvise, + SYS_process_madvise, #endif -SYS_kill, SYS_ptrace -}; -#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls)) + SYS_kill, SYS_ptrace}; +#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls)) static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k) { @@ -132,13 +131,13 @@ static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, static bool set_seccomp(void) { #ifdef __X32_SYSCALL_BIT - #define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT) +#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT) #else - #define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT) +#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT) #endif struct sock_filter sockf[SECCOMP_PROG_SIZE]; - struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE, .filter = sockf }; - int i,idx=0; + struct sock_fprog prog = {.len = SECCOMP_PROG_SIZE, .filter = sockf}; + int i, idx = 0; set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr); #ifdef __X32_SYSCALL_BIT @@ -151,19 +150,19 @@ static bool set_seccomp(void) set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); #endif -/* - // ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr - set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call - set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd - set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad - set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr -*/ - for(i=0 ; i= 0; } @@ -174,42 +173,41 @@ bool sec_harden(void) DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)"); return false; } -#if ARCH_NR!=0 +#if ARCH_NR != 0 if (!set_seccomp()) { DLOG_PERROR("seccomp"); - if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n"); + if (errno == EINVAL) + DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n"); return false; } #endif return true; } - - - bool checkpcap(uint64_t caps) { - if (!caps) return true; // no special caps reqd + if (!caps) + return true; // no special caps reqd struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()}; struct __user_cap_data_struct cd[2]; uint32_t c0 = (uint32_t)caps; - uint32_t c1 = (uint32_t)(caps>>32); + uint32_t c1 = (uint32_t)(caps >> 32); - return !capget(&ch,cd) && (cd[0].effective & c0)==c0 && (cd[1].effective & c1)==c1; + return !capget(&ch, cd) && (cd[0].effective & c0) == c0 && (cd[1].effective & c1) == c1; } bool setpcap(uint64_t caps) { struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()}; struct __user_cap_data_struct cd[2]; - + cd[0].effective = cd[0].permitted = (uint32_t)caps; cd[0].inheritable = 0; - cd[1].effective = cd[1].permitted = (uint32_t)(caps>>32); + cd[1].effective = cd[1].permitted = (uint32_t)(caps >> 32); cd[1].inheritable = 0; - return !capset(&ch,cd); + return !capset(&ch, cd); } int getmaxcap(void) { @@ -221,18 +219,17 @@ int getmaxcap(void) fclose(F); } return maxcap; - } bool dropcaps(void) { uint64_t caps = 0; int maxcap = getmaxcap(); - if (setpcap(caps|(1< #include -#pragma pack(push,1) +#pragma pack(push, 1) -#define S4_CMD_CONNECT 1 -#define S4_CMD_BIND 2 +#define S4_CMD_CONNECT 1 +#define S4_CMD_BIND 2 typedef struct { - uint8_t ver,cmd; + uint8_t ver, cmd; uint16_t port; uint32_t ip; } s4_req; -#define S4_REQ_HEADER_VALID(r,l) (l>=sizeof(s4_req) && r->ver==4) -#define S4_REQ_CONNECT_VALID(r,l) (S4_REQ_HEADER_VALID(r,l) && r->cmd==S4_CMD_CONNECT) +#define S4_REQ_HEADER_VALID(r, l) (l >= sizeof(s4_req) && r->ver == 4) +#define S4_REQ_CONNECT_VALID(r, l) (S4_REQ_HEADER_VALID(r, l) && r->cmd == S4_CMD_CONNECT) -#define S4_REP_OK 90 -#define S4_REP_FAILED 91 +#define S4_REP_OK 90 +#define S4_REP_FAILED 91 typedef struct { - uint8_t zero,rep; + uint8_t zero, rep; uint16_t port; uint32_t ip; } s4_rep; - - -#define S5_AUTH_NONE 0 -#define S5_AUTH_GSSAPI 1 -#define S5_AUTH_USERPASS 2 -#define S5_AUTH_UNACCEPTABLE 0xFF +#define S5_AUTH_NONE 0 +#define S5_AUTH_GSSAPI 1 +#define S5_AUTH_USERPASS 2 +#define S5_AUTH_UNACCEPTABLE 0xFF typedef struct { - uint8_t ver,nmethods,methods[255]; + uint8_t ver, nmethods, methods[255]; } s5_handshake; -#define S5_REQ_HANDHSHAKE_VALID(r,l) (l>=3 && r->ver==5 && r->nmethods && l>=(2+r->nmethods)) +#define S5_REQ_HANDHSHAKE_VALID(r, l) (l >= 3 && r->ver == 5 && r->nmethods && l >= (2 + r->nmethods)) typedef struct { - uint8_t ver,method; + uint8_t ver, method; } s5_handshake_ack; -#define S5_CMD_CONNECT 1 -#define S5_CMD_BIND 2 -#define S5_CMD_UDP_ASSOC 3 -#define S5_ATYP_IP4 1 -#define S5_ATYP_DOM 3 -#define S5_ATYP_IP6 4 +#define S5_CMD_CONNECT 1 +#define S5_CMD_BIND 2 +#define S5_CMD_UDP_ASSOC 3 +#define S5_ATYP_IP4 1 +#define S5_ATYP_DOM 3 +#define S5_ATYP_IP6 4 typedef struct { - uint8_t ver,cmd,rsv,atyp; - union { - struct { + uint8_t ver, cmd, rsv, atyp; + union + { + struct + { struct in_addr addr; uint16_t port; } d4; - struct { + struct + { struct in6_addr addr; uint16_t port; } d6; - struct { + struct + { uint8_t len; - char domport[255+2]; // max hostname + binary port + char domport[255 + 2]; // max hostname + binary port } dd; }; } s5_req; -#define S5_REQ_HEADER_VALID(r,l) (l>=4 && r->ver==5) -#define S5_IP46_VALID(r,l) ((r->atyp==S5_ATYP_IP4 && l>=(4+sizeof(r->d4))) || (r->atyp==S5_ATYP_IP6 && l>=(4+sizeof(r->d6)))) -#define S5_REQ_CONNECT_VALID(r,l) (S5_REQ_HEADER_VALID(r,l) && r->cmd==S5_CMD_CONNECT && (S5_IP46_VALID(r,l) || (r->atyp==S5_ATYP_DOM && l>=5 && l>=(5+r->dd.len)))) -#define S5_PORT_FROM_DD(r,l) (l>=(4+r->dd.len+2) ? ntohs(*(uint16_t*)(r->dd.domport+r->dd.len)) : 0) +#define S5_REQ_HEADER_VALID(r, l) (l >= 4 && r->ver == 5) +#define S5_IP46_VALID(r, l) ((r->atyp == S5_ATYP_IP4 && l >= (4 + sizeof(r->d4))) || (r->atyp == S5_ATYP_IP6 && l >= (4 + sizeof(r->d6)))) +#define S5_REQ_CONNECT_VALID(r, l) (S5_REQ_HEADER_VALID(r, l) && r->cmd == S5_CMD_CONNECT && (S5_IP46_VALID(r, l) || (r->atyp == S5_ATYP_DOM && l >= 5 && l >= (5 + r->dd.len)))) +#define S5_PORT_FROM_DD(r, l) (l >= (4 + r->dd.len + 2) ? ntohs(*(uint16_t *)(r->dd.domport + r->dd.len)) : 0) -#define S5_REP_OK 0 -#define S5_REP_GENERAL_FAILURE 1 -#define S5_REP_NOT_ALLOWED_BY_RULESET 2 -#define S5_REP_NETWORK_UNREACHABLE 3 -#define S5_REP_HOST_UNREACHABLE 4 -#define S5_REP_CONN_REFUSED 5 -#define S5_REP_TTL_EXPIRED 6 -#define S5_REP_COMMAND_NOT_SUPPORTED 7 -#define S5_REP_ADDR_TYPE_NOT_SUPPORTED 8 +#define S5_REP_OK 0 +#define S5_REP_GENERAL_FAILURE 1 +#define S5_REP_NOT_ALLOWED_BY_RULESET 2 +#define S5_REP_NETWORK_UNREACHABLE 3 +#define S5_REP_HOST_UNREACHABLE 4 +#define S5_REP_CONN_REFUSED 5 +#define S5_REP_TTL_EXPIRED 6 +#define S5_REP_COMMAND_NOT_SUPPORTED 7 +#define S5_REP_ADDR_TYPE_NOT_SUPPORTED 8 typedef struct { - uint8_t ver,rep,rsv,atyp; - union { - struct { + uint8_t ver, rep, rsv, atyp; + union + { + struct + { struct in_addr addr; uint16_t port; } d4; diff --git a/tpws/tamper.c b/tpws/tamper.c index c70e6cc..ccf2dd1 100644 --- a/tpws/tamper.c +++ b/tpws/tamper.c @@ -9,36 +9,40 @@ #include // segment buffer has at least 5 extra bytes to extend data block -void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags) +void tamper_out(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size, size_t *split_pos, uint8_t *split_flags) { uint8_t *p, *pp, *pHost = NULL; size_t method_len = 0, pos; const char *method; bool bBypass = false, bHaveHost = false, bHostExcluded = false; char *pc, Host[256]; - + DBGPRINT("tamper_out\n"); - *split_pos=0; - *split_flags=0; + *split_pos = 0; + *split_flags = 0; - if ((method = HttpMethod(segment,*size))) + if ((method = HttpMethod(segment, *size))) { - method_len = strlen(method)-2; - VPRINT("Data block looks like http request start : %s\n", method); - if (!ctrack->l7proto) ctrack->l7proto=HTTP; + method_len = strlen(method) - 2; + VPRINT("Data block looks like HTTP request start : %s\n", method); + if (!ctrack->l7proto) + ctrack->l7proto = HTTP; // cpu saving : we search host only if and when required. we do not research host every time we need its position - if ((params.hostlist || params.hostlist_exclude) && HttpFindHost(&pHost,segment,*size)) + if ((params.hostlist || params.hostlist_exclude) && HttpFindHost(&pHost, segment, *size)) { p = pHost + 5; - while (p < (segment + *size) && (*p == ' ' || *p == '\t')) p++; + while (p < (segment + *size) && (*p == ' ' || *p == '\t')) + p++; pp = p; - while (pp < (segment + *size) && (pp - p) < (sizeof(Host) - 1) && *pp != '\r' && *pp != '\n') pp++; + while (pp < (segment + *size) && (pp - p) < (sizeof(Host) - 1) && *pp != '\r' && *pp != '\n') + pp++; memcpy(Host, p, pp - p); Host[pp - p] = '\0'; bHaveHost = true; VPRINT("Requested Host is : %s\n", Host); - for(pc = Host; *pc; pc++) *pc=tolower(*pc); + for (pc = Host; *pc; pc++) + *pc = tolower(*pc); bBypass = !HostlistCheck(Host, &bHostExcluded); } if (!bBypass) @@ -48,7 +52,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si p = pp = segment; while ((p = memmem(p, segment + *size - p, "\r\n", 2))) { - *p = '\n'; p++; + *p = '\n'; + p++; memmove(p, p + 1, segment + *size - p - 1); (*size)--; if (pp == (p - 1)) @@ -61,13 +66,14 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si } pHost = NULL; // invalidate } - if (params.methodeol && (*size+1+!params.unixeol)<=segment_buffer_size) + if (params.methodeol && (*size + 1 + !params.unixeol) <= segment_buffer_size) { VPRINT("Adding EOL before method\n"); if (params.unixeol) { memmove(segment + 1, segment, *size); - (*size)++;; + (*size)++; + ; segment[0] = '\n'; } else @@ -79,39 +85,41 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si } pHost = NULL; // invalidate } - if (params.methodspace && *size '%c%c%c%c:' at pos %td\n", params.hostspell[0], params.hostspell[1], params.hostspell[2], params.hostspell[3], pHost - segment); memcpy(pHost, params.hostspell, 4); } - if (params.hostpad && HttpFindHost(&pHost,segment,*size)) + if (params.hostpad && HttpFindHost(&pHost, segment, *size)) { // add : XXXXX: segment_buffer_size) + if ((hsize + *size) > segment_buffer_size) VPRINT("could not add host padding : buffer too small\n"); else { - if ((hostpad+*size)>segment_buffer_size) + if ((hostpad + *size) > segment_buffer_size) { - hostpad=segment_buffer_size-*size; + hostpad = segment_buffer_size - *size; VPRINT("host padding reduced to %zu bytes : buffer too small\n", hostpad); } else VPRINT("host padding with %zu bytes\n", hostpad); - + p = pHost; pos = p - segment; memmove(p + hostpad, p, *size - pos); (*size) += hostpad; - while(hostpad) + while (hostpad) { - #define MAX_HDR_SIZE 2048 - size_t padsize = hostpad > hsize ? hostpad-hsize : 0; - if (padsize>MAX_HDR_SIZE) padsize=MAX_HDR_SIZE; +#define MAX_HDR_SIZE 2048 + size_t padsize = hostpad > hsize ? hostpad - hsize : 0; + if (padsize > MAX_HDR_SIZE) + padsize = MAX_HDR_SIZE; // if next header would be too small then add extra padding to the current one - if ((hostpad-padsize-hsize)l7proto) ctrack->l7proto=TLS; + size_t tpos = 0, spos = 0; + + if (!ctrack->l7proto) + ctrack->l7proto = TLS; VPRINT("packet contains TLS ClientHello\n"); // we need host only if hostlist is present - if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false)) + if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t *)segment, *size, Host, sizeof(Host), false)) { - VPRINT("hostname: %s\n",Host); + VPRINT("hostname: %s\n", Host); bHaveHost = true; bBypass = !HostlistCheck(Host, &bHostExcluded); } @@ -202,52 +215,59 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si { spos = TLSPos(params.split_tls, params.split_pos, segment, *size, 0); - if ((5+*size)<=segment_buffer_size) + if ((5 + *size) <= segment_buffer_size) { - tpos = TLSPos(params.tlsrec, params.tlsrec_pos+5, segment, *size, 0); - if (tpos>5) + tpos = TLSPos(params.tlsrec, params.tlsrec_pos + 5, segment, *size, 0); + if (tpos > 5) { // construct 2 TLS records from one - uint16_t l = pntoh16(segment+3); // length - if (l>=2) + uint16_t l = pntoh16(segment + 3); // length + if (l >= 2) { // length is checked in IsTLSClientHello and cannot exceed buffer size - if ((tpos-5)>=l) tpos=5+1; - VPRINT("making 2 TLS records at pos %zu\n",tpos); - memmove(segment+tpos+5,segment+tpos,*size-tpos); + if ((tpos - 5) >= l) + tpos = 5 + 1; + VPRINT("making 2 TLS records at pos %zu\n", tpos); + memmove(segment + tpos + 5, segment + tpos, *size - tpos); segment[tpos] = segment[0]; - segment[tpos+1] = segment[1]; - segment[tpos+2] = segment[2]; - phton16(segment+tpos+3,l-(tpos-5)); - phton16(segment+3,tpos-5); + segment[tpos + 1] = segment[1]; + segment[tpos + 2] = segment[2]; + phton16(segment + tpos + 3, l - (tpos - 5)); + phton16(segment + 3, tpos - 5); *size += 5; // split pos present and it is not before tlsrec split. increase split pos by tlsrec header size (5 bytes) - if (spos && spos>=tpos) spos+=5; + if (spos && spos >= tpos) + spos += 5; } } } if (spos && spos < *size) { - VPRINT("split pos %zu\n",spos); + VPRINT("split pos %zu\n", spos); *split_pos = spos; } - if (params.disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER; - if (params.oob_tls) *split_flags |= SPLIT_FLAG_OOB; + if (params.disorder_tls) + *split_flags |= SPLIT_FLAG_DISORDER; + if (params.oob_tls) + *split_flags |= SPLIT_FLAG_OOB; } } else if (params.split_any_protocol && params.split_pos < *size) *split_pos = params.split_pos; - + if (bHaveHost && bBypass && !bHostExcluded && *params.hostlist_auto_filename) { DBGPRINT("tamper_out put hostname : %s\n", Host); - if (ctrack->hostname) free(ctrack->hostname); - ctrack->hostname=strdup(Host); + if (ctrack->hostname) + free(ctrack->hostname); + ctrack->hostname = strdup(Host); } - if (params.disorder) *split_flags |= SPLIT_FLAG_DISORDER; - if (params.oob) *split_flags |= SPLIT_FLAG_OOB; + if (params.disorder) + *split_flags |= SPLIT_FLAG_DISORDER; + if (params.oob) + *split_flags |= SPLIT_FLAG_OOB; } static void auto_hostlist_reset_fail_counter(const char *hostname) @@ -255,7 +275,7 @@ static void auto_hostlist_reset_fail_counter(const char *hostname) if (hostname) { hostfail_pool *fail_counter; - + fail_counter = HostFailPoolFind(params.hostlist_auto_fail_counters, hostname); if (fail_counter) { @@ -287,9 +307,9 @@ static void auto_hostlist_failed(const char *hostname) { VPRINT("auto hostlist : fail threshold reached. adding %s to auto hostlist\n", hostname); HostFailPoolDel(¶ms.hostlist_auto_fail_counters, fail_counter); - + VPRINT("auto hostlist : rechecking %s to avoid duplicates\n", hostname); - bool bExcluded=false; + bool bExcluded = false; if (!HostlistCheck(hostname, &bExcluded) && !bExcluded) { VPRINT("auto hostlist : adding %s\n", hostname); @@ -314,9 +334,9 @@ static void auto_hostlist_failed(const char *hostname) } } -void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size) +void tamper_in(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size) { - bool bFail=false; + bool bFail = false; DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname); @@ -324,9 +344,9 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz { HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters); - if (ctrack->l7proto==HTTP && ctrack->hostname) + if (ctrack->l7proto == HTTP && ctrack->hostname) { - if (IsHttpReply(segment,*size)) + if (IsHttpReply(segment, *size)) { VPRINT("incoming HTTP reply detected for hostname %s\n", ctrack->hostname); bFail = HttpReplyLooksLikeDPIRedirect(segment, *size, ctrack->hostname); @@ -343,11 +363,11 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz // received not http reply. do not monitor this connection anymore VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname); } - if (bFail) auto_hostlist_failed(ctrack->hostname); - + if (bFail) + auto_hostlist_failed(ctrack->hostname); } - if (!bFail) auto_hostlist_reset_fail_counter(ctrack->hostname); - + if (!bFail) + auto_hostlist_reset_fail_counter(ctrack->hostname); } ctrack->bTamperInCutoff = true; } @@ -356,7 +376,8 @@ void rst_in(t_ctrack *ctrack) { DBGPRINT("rst_in hostname=%s\n", ctrack->hostname); - if (!*params.hostlist_auto_filename) return; + if (!*params.hostlist_auto_filename) + return; HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters); @@ -371,7 +392,8 @@ void hup_out(t_ctrack *ctrack) { DBGPRINT("hup_out hostname=%s\n", ctrack->hostname); - if (!*params.hostlist_auto_filename) return; + if (!*params.hostlist_auto_filename) + return; HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters); diff --git a/tpws/tamper.h b/tpws/tamper.h index 7f4172e..e02ce0a 100644 --- a/tpws/tamper.h +++ b/tpws/tamper.h @@ -4,10 +4,15 @@ #include #include -#define SPLIT_FLAG_DISORDER 0x01 -#define SPLIT_FLAG_OOB 0x02 +#define SPLIT_FLAG_DISORDER 0x01 +#define SPLIT_FLAG_OOB 0x02 -typedef enum {UNKNOWN=0, HTTP, TLS} t_l7proto; +typedef enum +{ + UNKNOWN = 0, + HTTP, + TLS +} t_l7proto; typedef struct { // common state @@ -17,8 +22,8 @@ typedef struct char *hostname; } t_ctrack; -void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags); -void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size); +void tamper_out(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size, size_t *split_pos, uint8_t *split_flags); +void tamper_in(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size); // connection reset by remote leg void rst_in(t_ctrack *ctrack); // local leg closed connection (timeout waiting response ?) diff --git a/tpws/tpws.c b/tpws/tpws.c index 9e017c5..9231bc1 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -28,7 +28,7 @@ #include "tpws.h" #ifdef BSD - #include +#include #endif #include "tpws_conn.h" @@ -71,24 +71,26 @@ static void onusr2(int sig) printf("\n"); } - static int8_t block_sigpipe(void) { sigset_t sigset; memset(&sigset, 0, sizeof(sigset)); - //Get the old sigset, add SIGPIPE and update sigset - if (sigprocmask(SIG_BLOCK, NULL, &sigset) == -1) { + // Get the old sigset, add SIGPIPE and update sigset + if (sigprocmask(SIG_BLOCK, NULL, &sigset) == -1) + { DLOG_PERROR("sigprocmask (get)"); return -1; } - if (sigaddset(&sigset, SIGPIPE) == -1) { + if (sigaddset(&sigset, SIGPIPE) == -1) + { DLOG_PERROR("sigaddset"); return -1; } - if (sigprocmask(SIG_BLOCK, &sigset, NULL) == -1) { + if (sigprocmask(SIG_BLOCK, &sigset, NULL) == -1) + { DLOG_PERROR("sigprocmask (set)"); return -1; } @@ -96,35 +98,33 @@ static int8_t block_sigpipe(void) return 0; } - static bool is_interface_online(const char *ifname) { struct ifreq ifr; int sock; - - if ((sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP))==-1) + + if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) return false; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = 0; + ifr.ifr_name[IFNAMSIZ - 1] = 0; ioctl(sock, SIOCGIFFLAGS, &ifr); close(sock); return !!(ifr.ifr_flags & IFF_UP); } static int get_default_ttl(void) { - int sock,ttl=0; - socklen_t optlen=sizeof(ttl); - - if ((sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP))!=-1) + int sock, ttl = 0; + socklen_t optlen = sizeof(ttl); + + if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) != -1) { - getsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, &optlen); - close(sock); + getsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, &optlen); + close(sock); } return ttl; } - static void exithelp(void) { printf( @@ -208,10 +208,9 @@ static void exithelp(void) " --tamper-start=[n]\t\t; start tampering only from specified outbound stream position. default is 0. 'n' means data block number.\n" " --tamper-cutoff=[n]\t\t; do not tamper anymore after specified outbound stream position. default is unlimited.\n", #if defined(__linux__) || defined(__APPLE__) - DEFAULT_TCP_USER_TIMEOUT_LOCAL,DEFAULT_TCP_USER_TIMEOUT_REMOTE, + DEFAULT_TCP_USER_TIMEOUT_LOCAL, DEFAULT_TCP_USER_TIMEOUT_REMOTE, #endif - HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT - ); + HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT); exit(1); } static void cleanup_params(void) @@ -235,32 +234,31 @@ static void exit_clean(int code) static void nextbind_clean(void) { params.binds_last++; - if (params.binds_last>=MAX_BINDS) + if (params.binds_last >= MAX_BINDS) { - DLOG_ERR("maximum of %d binds are supported\n",MAX_BINDS); + DLOG_ERR("maximum of %d binds are supported\n", MAX_BINDS); exit_clean(1); } } static void checkbind_clean(void) { - if (params.binds_last<0) + if (params.binds_last < 0) { DLOG_ERR("start new bind with --bind-addr,--bind-iface*\n"); exit_clean(1); } } - void save_default_ttl(void) { if (!params.ttl_default) { - params.ttl_default = get_default_ttl(); - if (!params.ttl_default) - { - DLOG_ERR("could not get default ttl\n"); - exit_clean(1); - } + params.ttl_default = get_default_ttl(); + if (!params.ttl_default) + { + DLOG_ERR("could not get default TTL\n"); + exit_clean(1); + } } } @@ -285,7 +283,6 @@ bool parse_tlspos(const char *s, enum tlspos *pos) return true; } - void parse_params(int argc, char *argv[]) { int option_index = 0; @@ -310,87 +307,87 @@ void parse_params(int argc, char *argv[]) #endif if (can_drop_root()) { - params.uid = params.gid = 0x7FFFFFFF; // default uid:gid - params.droproot = true; + params.uid = params.gid = 0x7FFFFFFF; // default uid:gid + params.droproot = true; } const struct option long_options[] = { - { "help",no_argument,0,0 },// optidx=0 - { "h",no_argument,0,0 },// optidx=1 - { "bind-addr",required_argument,0,0 },// optidx=2 - { "bind-iface4",required_argument,0,0 },// optidx=3 - { "bind-iface6",required_argument,0,0 },// optidx=4 - { "bind-linklocal",required_argument,0,0 },// optidx=5 - { "bind-wait-ifup",required_argument,0,0 },// optidx=6 - { "bind-wait-ip",required_argument,0,0 },// optidx=7 - { "bind-wait-ip-linklocal",required_argument,0,0 },// optidx=8 - { "bind-wait-only",no_argument,0,0 },// optidx=9 - { "port",required_argument,0,0 },// optidx=10 - { "daemon",no_argument,0,0 },// optidx=11 - { "user",required_argument,0,0 },// optidx=12 - { "uid",required_argument,0,0 },// optidx=13 - { "maxconn",required_argument,0,0 },// optidx=14 - { "maxfiles",required_argument,0,0 },// optidx=15 - { "max-orphan-time",required_argument,0,0 },// optidx=16 - { "hostcase",no_argument,0,0 },// optidx=17 - { "hostspell",required_argument,0,0 },// optidx=18 - { "hostdot",no_argument,0,0 },// optidx=19 - { "hostnospace",no_argument,0,0 },// optidx=20 - { "hostpad",required_argument,0,0 },// optidx=21 - { "domcase",no_argument,0,0 },// optidx=22 - { "split-http-req",required_argument,0,0 },// optidx=23 - { "split-tls",required_argument,0,0 },// optidx=24 - { "split-pos",required_argument,0,0 },// optidx=25 - { "split-any-protocol",optional_argument,0,0},// optidx=26 - { "disorder",optional_argument,0,0 },// optidx=27 - { "oob",optional_argument,0,0 },// optidx=28 - { "oob-data",required_argument,0,0 },// optidx=29 - { "methodspace",no_argument,0,0 },// optidx=30 - { "methodeol",no_argument,0,0 },// optidx=31 - { "hosttab",no_argument,0,0 },// optidx=32 - { "unixeol",no_argument,0,0 },// optidx=33 - { "tlsrec",required_argument,0,0 },// optidx=34 - { "tlsrec-pos",required_argument,0,0 },// optidx=35 - { "hostlist",required_argument,0,0 },// optidx=36 - { "hostlist-exclude",required_argument,0,0 },// optidx=37 - { "hostlist-auto",required_argument,0,0}, // optidx=38 - { "hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=39 - { "hostlist-auto-fail-time",required_argument,0,0}, // optidx=40 - { "hostlist-auto-debug",required_argument,0,0}, // optidx=41 - { "pidfile",required_argument,0,0 },// optidx=42 - { "debug",optional_argument,0,0 },// optidx=43 - { "debug-level",required_argument,0,0 },// optidx=44 - { "local-rcvbuf",required_argument,0,0 },// optidx=45 - { "local-sndbuf",required_argument,0,0 },// optidx=46 - { "remote-rcvbuf",required_argument,0,0 },// optidx=47 - { "remote-sndbuf",required_argument,0,0 },// optidx=48 - { "socks",no_argument,0,0 },// optidx=40 - { "no-resolve",no_argument,0,0 },// optidx=50 - { "resolver-threads",required_argument,0,0 },// optidx=51 - { "skip-nodelay",no_argument,0,0 },// optidx=52 - { "tamper-start",required_argument,0,0 },// optidx=53 - { "tamper-cutoff",required_argument,0,0 },// optidx=54 - { "connect-bind-addr",required_argument,0,0 },// optidx=55 + {"help", no_argument, 0, 0}, // optidx=0 + {"h", no_argument, 0, 0}, // optidx=1 + {"bind-addr", required_argument, 0, 0}, // optidx=2 + {"bind-iface4", required_argument, 0, 0}, // optidx=3 + {"bind-iface6", required_argument, 0, 0}, // optidx=4 + {"bind-linklocal", required_argument, 0, 0}, // optidx=5 + {"bind-wait-ifup", required_argument, 0, 0}, // optidx=6 + {"bind-wait-ip", required_argument, 0, 0}, // optidx=7 + {"bind-wait-ip-linklocal", required_argument, 0, 0}, // optidx=8 + {"bind-wait-only", no_argument, 0, 0}, // optidx=9 + {"port", required_argument, 0, 0}, // optidx=10 + {"daemon", no_argument, 0, 0}, // optidx=11 + {"user", required_argument, 0, 0}, // optidx=12 + {"uid", required_argument, 0, 0}, // optidx=13 + {"maxconn", required_argument, 0, 0}, // optidx=14 + {"maxfiles", required_argument, 0, 0}, // optidx=15 + {"max-orphan-time", required_argument, 0, 0}, // optidx=16 + {"hostcase", no_argument, 0, 0}, // optidx=17 + {"hostspell", required_argument, 0, 0}, // optidx=18 + {"hostdot", no_argument, 0, 0}, // optidx=19 + {"hostnospace", no_argument, 0, 0}, // optidx=20 + {"hostpad", required_argument, 0, 0}, // optidx=21 + {"domcase", no_argument, 0, 0}, // optidx=22 + {"split-http-req", required_argument, 0, 0}, // optidx=23 + {"split-tls", required_argument, 0, 0}, // optidx=24 + {"split-pos", required_argument, 0, 0}, // optidx=25 + {"split-any-protocol", optional_argument, 0, 0}, // optidx=26 + {"disorder", optional_argument, 0, 0}, // optidx=27 + {"oob", optional_argument, 0, 0}, // optidx=28 + {"oob-data", required_argument, 0, 0}, // optidx=29 + {"methodspace", no_argument, 0, 0}, // optidx=30 + {"methodeol", no_argument, 0, 0}, // optidx=31 + {"hosttab", no_argument, 0, 0}, // optidx=32 + {"unixeol", no_argument, 0, 0}, // optidx=33 + {"tlsrec", required_argument, 0, 0}, // optidx=34 + {"tlsrec-pos", required_argument, 0, 0}, // optidx=35 + {"hostlist", required_argument, 0, 0}, // optidx=36 + {"hostlist-exclude", required_argument, 0, 0}, // optidx=37 + {"hostlist-auto", required_argument, 0, 0}, // optidx=38 + {"hostlist-auto-fail-threshold", required_argument, 0, 0}, // optidx=39 + {"hostlist-auto-fail-time", required_argument, 0, 0}, // optidx=40 + {"hostlist-auto-debug", required_argument, 0, 0}, // optidx=41 + {"pidfile", required_argument, 0, 0}, // optidx=42 + {"debug", optional_argument, 0, 0}, // optidx=43 + {"debug-level", required_argument, 0, 0}, // optidx=44 + {"local-rcvbuf", required_argument, 0, 0}, // optidx=45 + {"local-sndbuf", required_argument, 0, 0}, // optidx=46 + {"remote-rcvbuf", required_argument, 0, 0}, // optidx=47 + {"remote-sndbuf", required_argument, 0, 0}, // optidx=48 + {"socks", no_argument, 0, 0}, // optidx=40 + {"no-resolve", no_argument, 0, 0}, // optidx=50 + {"resolver-threads", required_argument, 0, 0}, // optidx=51 + {"skip-nodelay", no_argument, 0, 0}, // optidx=52 + {"tamper-start", required_argument, 0, 0}, // optidx=53 + {"tamper-cutoff", required_argument, 0, 0}, // optidx=54 + {"connect-bind-addr", required_argument, 0, 0}, // optidx=55 #if defined(__FreeBSD__) - { "enable-pf",no_argument,0,0 },// optidx=56 + {"enable-pf", no_argument, 0, 0}, // optidx=56 #elif defined(__APPLE__) - { "local-tcp-user-timeout",required_argument,0,0 },// optidx=56 - { "remote-tcp-user-timeout",required_argument,0,0 },// optidx=57 + {"local-tcp-user-timeout", required_argument, 0, 0}, // optidx=56 + {"remote-tcp-user-timeout", required_argument, 0, 0}, // optidx=57 #elif defined(__linux__) - { "local-tcp-user-timeout",required_argument,0,0 },// optidx=56 - { "remote-tcp-user-timeout",required_argument,0,0 },// optidx=57 - { "mss",required_argument,0,0 },// optidx=58 - { "mss-pf",required_argument,0,0 },// optidx=59 + {"local-tcp-user-timeout", required_argument, 0, 0}, // optidx=56 + {"remote-tcp-user-timeout", required_argument, 0, 0}, // optidx=57 + {"mss", required_argument, 0, 0}, // optidx=58 + {"mss-pf", required_argument, 0, 0}, // optidx=59 #ifdef SPLICE_PRESENT - { "nosplice",no_argument,0,0 },// optidx=60 + {"nosplice", no_argument, 0, 0}, // optidx=60 #endif #endif - { "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility - { NULL,0,NULL,0 } - }; + {"hostlist-auto-retrans-threshold", optional_argument, 0, 0}, // ignored. for nfqws command line compatibility + {NULL, 0, NULL, 0}}; while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { - if (v) exithelp_clean(); + if (v) + exithelp_clean(); switch (option_index) { case 0: @@ -400,11 +397,11 @@ void parse_params(int argc, char *argv[]) case 2: /* bind-addr */ nextbind_clean(); { - char *p = strchr(optarg,'%'); + char *p = strchr(optarg, '%'); if (p) { - *p=0; - strncpy(params.binds[params.binds_last].bindiface, p+1, sizeof(params.binds[params.binds_last].bindiface)); + *p = 0; + strncpy(params.binds[params.binds_last].bindiface, p + 1, sizeof(params.binds[params.binds_last].bindiface)); } strncpy(params.binds[params.binds_last].bindaddr, optarg, sizeof(params.binds[params.binds_last].bindaddr)); } @@ -412,13 +409,13 @@ void parse_params(int argc, char *argv[]) break; case 3: /* bind-iface4 */ nextbind_clean(); - params.binds[params.binds_last].bind_if6=false; + params.binds[params.binds_last].bind_if6 = false; strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface)); params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0; break; case 4: /* bind-iface6 */ nextbind_clean(); - params.binds[params.binds_last].bind_if6=true; + params.binds[params.binds_last].bind_if6 = true; strncpy(params.binds[params.binds_last].bindiface, optarg, sizeof(params.binds[params.binds_last].bindiface)); params.binds[params.binds_last].bindiface[sizeof(params.binds[params.binds_last].bindiface) - 1] = 0; break; @@ -426,16 +423,16 @@ void parse_params(int argc, char *argv[]) checkbind_clean(); params.binds[params.binds_last].bindll = true; if (!strcmp(optarg, "no")) - params.binds[params.binds_last].bindll=no; + params.binds[params.binds_last].bindll = no; else if (!strcmp(optarg, "prefer")) - params.binds[params.binds_last].bindll=prefer; + params.binds[params.binds_last].bindll = prefer; else if (!strcmp(optarg, "force")) - params.binds[params.binds_last].bindll=force; + params.binds[params.binds_last].bindll = force; else if (!strcmp(optarg, "unwanted")) - params.binds[params.binds_last].bindll=unwanted; + params.binds[params.binds_last].bindll = unwanted; else { - DLOG_ERR("invalid parameter in bind-linklocal : %s\n",optarg); + DLOG_ERR("invalid parameter in bind-linklocal : %s\n", optarg); exit_clean(1); } break; @@ -479,10 +476,10 @@ void parse_params(int argc, char *argv[]) params.droproot = true; break; } - case 13: /* uid */ - params.gid=0x7FFFFFFF; // default git. drop gid=0 + case 13: /* uid */ + params.gid = 0x7FFFFFFF; // default git. drop gid=0 params.droproot = true; - if (sscanf(optarg,"%u:%u",¶ms.uid,¶ms.gid)<1) + if (sscanf(optarg, "%u:%u", ¶ms.uid, ¶ms.gid) < 1) { DLOG_ERR("--uid should be : uid[:gid]\n"); exit_clean(1); @@ -560,7 +557,7 @@ void parse_params(int argc, char *argv[]) break; case 25: /* split-pos */ i = atoi(optarg); - if (i>0) + if (i > 0) params.split_pos = i; else { @@ -575,8 +572,10 @@ void parse_params(int argc, char *argv[]) case 27: /* disorder */ if (optarg) { - if (!strcmp(optarg,"http")) params.disorder_http=true; - else if (!strcmp(optarg,"tls")) params.disorder_tls=true; + if (!strcmp(optarg, "http")) + params.disorder_http = true; + else if (!strcmp(optarg, "tls")) + params.disorder_tls = true; else { DLOG_ERR("Invalid argument for disorder\n"); @@ -590,8 +589,10 @@ void parse_params(int argc, char *argv[]) case 28: /* oob */ if (optarg) { - if (!strcmp(optarg,"http")) params.oob_http=true; - else if (!strcmp(optarg,"tls")) params.oob_tls=true; + if (!strcmp(optarg, "http")) + params.oob_http = true; + else if (!strcmp(optarg, "tls")) + params.oob_tls = true; else { DLOG_ERR("Invalid argument for oob\n"); @@ -602,18 +603,20 @@ void parse_params(int argc, char *argv[]) params.oob = true; break; case 29: /* oob-data */ + { + size_t l = strlen(optarg); + unsigned int bt; + if (l == 1) + params.oob_byte = (uint8_t)*optarg; + else if (l != 4 || sscanf(optarg, "0x%02X", &bt) != 1) { - size_t l = strlen(optarg); - unsigned int bt; - if (l==1) params.oob_byte = (uint8_t)*optarg; - else if (l!=4 || sscanf(optarg,"0x%02X",&bt)!=1) - { - DLOG_ERR("Invalid argument for oob-data\n"); - exit_clean(1); - } - else params.oob_byte = (uint8_t)bt; + DLOG_ERR("Invalid argument for oob-data\n"); + exit_clean(1); } - break; + else + params.oob_byte = (uint8_t)bt; + } + break; case 30: /* methodspace */ params.methodspace = true; params.tamper = true; @@ -639,7 +642,7 @@ void parse_params(int argc, char *argv[]) params.tamper = true; break; case 35: /* tlsrec-pos */ - if ((params.tlsrec_pos = atoi(optarg))>0) + if ((params.tlsrec_pos = atoi(optarg)) > 0) params.tlsrec = tlspos_pos; else { @@ -671,7 +674,7 @@ void parse_params(int argc, char *argv[]) exit_clean(1); } { - FILE *F = fopen(optarg,"a+t"); + FILE *F = fopen(optarg, "a+t"); if (!F) { DLOG_ERR("cannot create %s\n", optarg); @@ -698,7 +701,7 @@ void parse_params(int argc, char *argv[]) break; case 39: /* hostlist-auto-fail-threshold */ params.hostlist_auto_fail_threshold = (uint8_t)atoi(optarg); - if (params.hostlist_auto_fail_threshold<1 || params.hostlist_auto_fail_threshold>20) + if (params.hostlist_auto_fail_threshold < 1 || params.hostlist_auto_fail_threshold > 20) { DLOG_ERR("auto hostlist fail threshold must be within 1..20\n"); exit_clean(1); @@ -706,39 +709,39 @@ void parse_params(int argc, char *argv[]) break; case 40: /* hostlist-auto-fail-time */ params.hostlist_auto_fail_time = (uint8_t)atoi(optarg); - if (params.hostlist_auto_fail_time<1) + if (params.hostlist_auto_fail_time < 1) { DLOG_ERR("auto hostlist fail time is not valid\n"); exit_clean(1); } break; case 41: /* hostlist-auto-debug */ + { + FILE *F = fopen(optarg, "a+t"); + if (!F) { - FILE *F = fopen(optarg,"a+t"); - if (!F) - { - DLOG_ERR("cannot create %s\n", optarg); - exit_clean(1); - } - fclose(F); - if (params.droproot && chown(optarg, params.uid, -1)) - DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", optarg); - strncpy(params.hostlist_auto_debuglog, optarg, sizeof(params.hostlist_auto_debuglog)); - params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0'; + DLOG_ERR("cannot create %s\n", optarg); + exit_clean(1); } - break; + fclose(F); + if (params.droproot && chown(optarg, params.uid, -1)) + DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", optarg); + strncpy(params.hostlist_auto_debuglog, optarg, sizeof(params.hostlist_auto_debuglog)); + params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0'; + } + break; case 42: /* pidfile */ - strncpy(params.pidfile,optarg,sizeof(params.pidfile)); - params.pidfile[sizeof(params.pidfile)-1]='\0'; + strncpy(params.pidfile, optarg, sizeof(params.pidfile)); + params.pidfile[sizeof(params.pidfile) - 1] = '\0'; break; case 43: /* debug */ if (optarg) { - if (*optarg=='@') + if (*optarg == '@') { - strncpy(params.debug_logfile,optarg+1,sizeof(params.debug_logfile)); - params.debug_logfile[sizeof(params.debug_logfile)-1] = 0; - FILE *F = fopen(params.debug_logfile,"wt"); + strncpy(params.debug_logfile, optarg + 1, sizeof(params.debug_logfile)); + params.debug_logfile[sizeof(params.debug_logfile) - 1] = 0; + FILE *F = fopen(params.debug_logfile, "wt"); if (!F) { fprintf(stderr, "cannot create %s\n", params.debug_logfile); @@ -746,14 +749,16 @@ void parse_params(int argc, char *argv[]) } if (params.droproot && chown(params.debug_logfile, params.uid, -1)) fprintf(stderr, "could not chown %s. log file may not be writable after privilege drop\n", params.debug_logfile); - if (!params.debug) params.debug = 1; + if (!params.debug) + params.debug = 1; params.debug_target = LOG_TARGET_FILE; } - else if (!strcmp(optarg,"syslog")) + else if (!strcmp(optarg, "syslog")) { - if (!params.debug) params.debug = 1; + if (!params.debug) + params.debug = 1; params.debug_target = LOG_TARGET_SYSLOG; - openlog("tpws",LOG_PID,LOG_USER); + openlog("tpws", LOG_PID, LOG_USER); } else { @@ -772,28 +777,28 @@ void parse_params(int argc, char *argv[]) break; case 45: /* local-rcvbuf */ #ifdef __linux__ - params.local_rcvbuf = atoi(optarg)/2; + params.local_rcvbuf = atoi(optarg) / 2; #else params.local_rcvbuf = atoi(optarg); #endif break; case 46: /* local-sndbuf */ #ifdef __linux__ - params.local_sndbuf = atoi(optarg)/2; + params.local_sndbuf = atoi(optarg) / 2; #else params.local_sndbuf = atoi(optarg); #endif break; case 47: /* remote-rcvbuf */ #ifdef __linux__ - params.remote_rcvbuf = atoi(optarg)/2; + params.remote_rcvbuf = atoi(optarg) / 2; #else params.remote_rcvbuf = atoi(optarg); #endif break; case 48: /* remote-sndbuf */ #ifdef __linux__ - params.remote_sndbuf = atoi(optarg)/2; + params.remote_sndbuf = atoi(optarg) / 2; #else params.remote_sndbuf = atoi(optarg); #endif @@ -806,7 +811,7 @@ void parse_params(int argc, char *argv[]) break; case 51: /* resolver-threads */ params.resolver_threads = atoi(optarg); - if (params.resolver_threads<1 || params.resolver_threads>300) + if (params.resolver_threads < 1 || params.resolver_threads > 300) { DLOG_ERR("resolver-threads must be within 1..300\n"); exit_clean(1); @@ -816,57 +821,57 @@ void parse_params(int argc, char *argv[]) params.skip_nodelay = true; break; case 53: /* tamper-start */ + { + const char *p = optarg; + if (*p == 'n') { - const char *p=optarg; - if (*p=='n') - { - params.tamper_start_n=true; - p++; - } - else - params.tamper_start_n=false; - params.tamper_start = atoi(p); + params.tamper_start_n = true; + p++; } - break; + else + params.tamper_start_n = false; + params.tamper_start = atoi(p); + } + break; case 54: /* tamper-cutoff */ + { + const char *p = optarg; + if (*p == 'n') { - const char *p=optarg; - if (*p=='n') - { - params.tamper_cutoff_n=true; - p++; - } - else - params.tamper_cutoff_n=false; - params.tamper_cutoff = atoi(p); + params.tamper_cutoff_n = true; + p++; } - break; + else + params.tamper_cutoff_n = false; + params.tamper_cutoff = atoi(p); + } + break; case 55: /* connect-bind-addr */ + { + char *p = strchr(optarg, '%'); + if (p) + *p++ = 0; + if (inet_pton(AF_INET, optarg, ¶ms.connect_bind4.sin_addr)) { - char *p = strchr(optarg,'%'); - if (p) *p++=0; - if (inet_pton(AF_INET, optarg, ¶ms.connect_bind4.sin_addr)) + params.connect_bind4.sin_family = AF_INET; + } + else if (inet_pton(AF_INET6, optarg, ¶ms.connect_bind6.sin6_addr)) + { + params.connect_bind6.sin6_family = AF_INET6; + if (p && *p) { - params.connect_bind4.sin_family = AF_INET; - } - else if (inet_pton(AF_INET6, optarg, ¶ms.connect_bind6.sin6_addr)) - { - params.connect_bind6.sin6_family = AF_INET6; - if (p && *p) - { - // copy interface name for delayed resolution - strncpy(params.connect_bind6_ifname,p,sizeof(params.connect_bind6_ifname)); - params.connect_bind6_ifname[sizeof(params.connect_bind6_ifname)-1]=0; - } - - } - else - { - DLOG_ERR("bad bind addr : %s\n", optarg); - exit_clean(1); + // copy interface name for delayed resolution + strncpy(params.connect_bind6_ifname, p, sizeof(params.connect_bind6_ifname)); + params.connect_bind6_ifname[sizeof(params.connect_bind6_ifname) - 1] = 0; } } - break; + else + { + DLOG_ERR("bad bind addr : %s\n", optarg); + exit_clean(1); + } + } + break; #if defined(__FreeBSD__) case 56: /* enable-pf */ @@ -875,7 +880,7 @@ void parse_params(int argc, char *argv[]) #elif defined(__linux__) || defined(__APPLE__) case 56: /* local-tcp-user-timeout */ params.tcp_user_timeout_local = atoi(optarg); - if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400) + if (params.tcp_user_timeout_local < 0 || params.tcp_user_timeout_local > 86400) { DLOG_ERR("Invalid argument for tcp user timeout. must be 0..86400\n"); exit_clean(1); @@ -883,7 +888,7 @@ void parse_params(int argc, char *argv[]) break; case 57: /* remote-tcp-user-timeout */ params.tcp_user_timeout_remote = atoi(optarg); - if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400) + if (params.tcp_user_timeout_remote < 0 || params.tcp_user_timeout_remote > 86400) { DLOG_ERR("Invalid argument for tcp user timeout. must be 0..86400\n"); exit_clean(1); @@ -895,14 +900,14 @@ void parse_params(int argc, char *argv[]) case 58: /* mss */ // this option does not work in any BSD and MacOS. OS may accept but it changes nothing params.mss = atoi(optarg); - if (params.mss<88 || params.mss>32767) + if (params.mss < 88 || params.mss > 32767) { DLOG_ERR("Invalid value for MSS. Linux accepts MSS 88-32767.\n"); exit_clean(1); } break; case 59: /* mss-pf */ - if (!pf_parse(optarg,¶ms.mss_pf)) + if (!pf_parse(optarg, ¶ms.mss_pf)) { DLOG_ERR("Invalid MSS port filter.\n"); exit_clean(1); @@ -921,26 +926,31 @@ void parse_params(int argc, char *argv[]) DLOG_ERR("Need port number\n"); exit_clean(1); } - if (params.binds_last<=0) + if (params.binds_last <= 0) { - params.binds_last=0; // default bind to all + params.binds_last = 0; // default bind to all } if (params.skip_nodelay && (params.split_http_req || params.split_pos)) { DLOG_ERR("Cannot split with --skip-nodelay\n"); exit_clean(1); } - if (!params.resolver_threads) params.resolver_threads = 5 + params.maxconn/50; - if (params.split_tls==tlspos_none && params.split_pos) params.split_tls=tlspos_pos; - if (params.split_http_req==httpreqpos_none && params.split_pos) params.split_http_req=httpreqpos_pos; + if (!params.resolver_threads) + params.resolver_threads = 5 + params.maxconn / 50; + if (params.split_tls == tlspos_none && params.split_pos) + params.split_tls = tlspos_pos; + if (params.split_http_req == httpreqpos_none && params.split_pos) + params.split_http_req = httpreqpos_pos; - if (*params.hostlist_auto_filename) params.hostlist_auto_mod_time = file_mod_time(params.hostlist_auto_filename); + if (*params.hostlist_auto_filename) + params.hostlist_auto_mod_time = file_mod_time(params.hostlist_auto_filename); if (!LoadIncludeHostLists()) { DLOG_ERR("Include hostlist load failed\n"); exit_clean(1); } - if (*params.hostlist_auto_filename) NonEmptyHostlist(¶ms.hostlist); + if (*params.hostlist_auto_filename) + NonEmptyHostlist(¶ms.hostlist); if (!LoadExcludeHostLists()) { DLOG_ERR("Exclude hostlist load failed\n"); @@ -948,49 +958,46 @@ void parse_params(int argc, char *argv[]) } } - static bool find_listen_addr(struct sockaddr_storage *salisten, const char *bindiface, bool bind_if6, enum bindll bindll, int *if_index) { - struct ifaddrs *addrs,*a; - bool found=false; - - if (getifaddrs(&addrs)<0) + struct ifaddrs *addrs, *a; + bool found = false; + + if (getifaddrs(&addrs) < 0) return false; // for ipv6 preference order // bind-linklocal-1 : link-local,any // bind-linklocal=0 : private,global,link-local - for(int pass=0;pass<3;pass++) + for (int pass = 0; pass < 3; pass++) { - a = addrs; + a = addrs; while (a) { if (a->ifa_addr) { - if (a->ifa_addr->sa_family==AF_INET && - *bindiface && !bind_if6 && !strcmp(a->ifa_name, bindiface)) + if (a->ifa_addr->sa_family == AF_INET && + *bindiface && !bind_if6 && !strcmp(a->ifa_name, bindiface)) { salisten->ss_family = AF_INET; - memcpy(&((struct sockaddr_in*)salisten)->sin_addr, &((struct sockaddr_in*)a->ifa_addr)->sin_addr, sizeof(struct in_addr)); - found=true; + memcpy(&((struct sockaddr_in *)salisten)->sin_addr, &((struct sockaddr_in *)a->ifa_addr)->sin_addr, sizeof(struct in_addr)); + found = true; goto ex; } - // ipv6 links locals are fe80::/10 - else if (a->ifa_addr->sa_family==AF_INET6 - && - ((!*bindiface && (bindll==prefer || bindll==force)) || - (*bindiface && bind_if6 && !strcmp(a->ifa_name, bindiface))) - && - ((bindll==force && is_linklocal((struct sockaddr_in6*)a->ifa_addr)) || - (bindll==prefer && ((pass==0 && is_linklocal((struct sockaddr_in6*)a->ifa_addr)) || (pass==1 && is_private6((struct sockaddr_in6*)a->ifa_addr)) || pass==2)) || - (bindll==no && ((pass==0 && is_private6((struct sockaddr_in6*)a->ifa_addr)) || (pass==1 && !is_linklocal((struct sockaddr_in6*)a->ifa_addr)))) || - (bindll==unwanted && ((pass==0 && is_private6((struct sockaddr_in6*)a->ifa_addr)) || (pass==1 && !is_linklocal((struct sockaddr_in6*)a->ifa_addr)) || pass==2))) - ) + // IPv6 links locals are fe80::/10 + else if (a->ifa_addr->sa_family == AF_INET6 && + ((!*bindiface && (bindll == prefer || bindll == force)) || + (*bindiface && bind_if6 && !strcmp(a->ifa_name, bindiface))) && + ((bindll == force && is_linklocal((struct sockaddr_in6 *)a->ifa_addr)) || + (bindll == prefer && ((pass == 0 && is_linklocal((struct sockaddr_in6 *)a->ifa_addr)) || (pass == 1 && is_private6((struct sockaddr_in6 *)a->ifa_addr)) || pass == 2)) || + (bindll == no && ((pass == 0 && is_private6((struct sockaddr_in6 *)a->ifa_addr)) || (pass == 1 && !is_linklocal((struct sockaddr_in6 *)a->ifa_addr)))) || + (bindll == unwanted && ((pass == 0 && is_private6((struct sockaddr_in6 *)a->ifa_addr)) || (pass == 1 && !is_linklocal((struct sockaddr_in6 *)a->ifa_addr)) || pass == 2)))) { salisten->ss_family = AF_INET6; - memcpy(&((struct sockaddr_in6*)salisten)->sin6_addr, &((struct sockaddr_in6*)a->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); - if (if_index) *if_index = if_nametoindex(a->ifa_name); - found=true; + memcpy(&((struct sockaddr_in6 *)salisten)->sin6_addr, &((struct sockaddr_in6 *)a->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); + if (if_index) + *if_index = if_nametoindex(a->ifa_name); + found = true; goto ex; } } @@ -1008,17 +1015,18 @@ static bool read_system_maxfiles(rlim_t *maxfile) FILE *F; int n; uintmax_t um; - if (!(F=fopen("/proc/sys/fs/file-max","r"))) + if (!(F = fopen("/proc/sys/fs/file-max", "r"))) return false; - n=fscanf(F,"%ju",&um); + n = fscanf(F, "%ju", &um); fclose(F); - if (!n) return false; + if (!n) + return false; *maxfile = (rlim_t)um; return true; #elif defined(BSD) - int maxfiles,mib[2]={CTL_KERN, KERN_MAXFILES}; + int maxfiles, mib[2] = {CTL_KERN, KERN_MAXFILES}; size_t len = sizeof(maxfiles); - if (sysctl(mib,2,&maxfiles,&len,NULL,0)==-1) + if (sysctl(mib, 2, &maxfiles, &len, NULL, 0) == -1) return false; *maxfile = (rlim_t)maxfiles; return true; @@ -1031,14 +1039,14 @@ static bool write_system_maxfiles(rlim_t maxfile) #ifdef __linux__ FILE *F; int n; - if (!(F=fopen("/proc/sys/fs/file-max","w"))) + if (!(F = fopen("/proc/sys/fs/file-max", "w"))) return false; - n=fprintf(F,"%ju",(uintmax_t)maxfile); + n = fprintf(F, "%ju", (uintmax_t)maxfile); fclose(F); return !!n; #elif defined(BSD) - int maxfiles=(int)maxfile,mib[2]={CTL_KERN, KERN_MAXFILES}; - if (sysctl(mib,2,NULL,0,&maxfiles,sizeof(maxfiles))==-1) + int maxfiles = (int)maxfile, mib[2] = {CTL_KERN, KERN_MAXFILES}; + if (sysctl(mib, 2, NULL, 0, &maxfiles, sizeof(maxfiles)) == -1) return false; return true; #else @@ -1048,7 +1056,7 @@ static bool write_system_maxfiles(rlim_t maxfile) static bool set_ulimit(void) { - rlim_t fdmax,fdmin_system,cur_lim=0; + rlim_t fdmax, fdmin_system, cur_lim = 0; int n; if (!params.maxfiles) @@ -1061,19 +1069,19 @@ static bool set_ulimit(void) #else fdmax = 2 * params.maxconn; #endif - fdmax += fdmax/2 + 16; + fdmax += fdmax / 2 + 16; } else fdmax = params.maxfiles; fdmin_system = fdmax + 4096; - DBGPRINT("set_ulimit : fdmax=%ju fdmin_system=%ju\n",(uintmax_t)fdmax,(uintmax_t)fdmin_system); + DBGPRINT("set_ulimit : fdmax=%ju fdmin_system=%ju\n", (uintmax_t)fdmax, (uintmax_t)fdmin_system); if (!read_system_maxfiles(&cur_lim)) return false; - DBGPRINT("set_ulimit : current system file-max=%ju\n",(uintmax_t)cur_lim); - if (cur_lim 0) { - int sec=0; + int sec = 0; if (!is_interface_online(params.binds[i].bindiface)) { - DLOG_CONDUP("waiting for ifup of %s for up to %d second(s)...\n",params.binds[i].bindiface,params.binds[i].bind_wait_ifup); + DLOG_CONDUP("waiting for ifup of %s for up to %d second(s)...\n", params.binds[i].bindiface, params.binds[i].bind_wait_ifup); do { sleep(1); sec++; - } - while (!is_interface_online(params.binds[i].bindiface) && sec=params.binds[i].bind_wait_ifup) + } while (!is_interface_online(params.binds[i].bindiface) && sec < params.binds[i].bind_wait_ifup); + if (sec >= params.binds[i].bind_wait_ifup) { DLOG_CONDUP("wait timed out\n"); goto exiterr; } } } - if (!(if_index = if_nametoindex(params.binds[i].bindiface)) && params.binds[i].bind_wait_ip<=0) + if (!(if_index = if_nametoindex(params.binds[i].bindiface)) && params.binds[i].bind_wait_ip <= 0) { - DLOG_CONDUP("bad iface %s\n",params.binds[i].bindiface); + DLOG_CONDUP("bad iface %s\n", params.binds[i].bindiface); goto exiterr; } } list[i].bind_wait_ip_left = params.binds[i].bind_wait_ip; if (*params.binds[i].bindaddr) { - if (inet_pton(AF_INET, params.binds[i].bindaddr, &((struct sockaddr_in*)(&list[i].salisten))->sin_addr)) + if (inet_pton(AF_INET, params.binds[i].bindaddr, &((struct sockaddr_in *)(&list[i].salisten))->sin_addr)) { list[i].salisten.ss_family = AF_INET; } - else if (inet_pton(AF_INET6, params.binds[i].bindaddr, &((struct sockaddr_in6*)(&list[i].salisten))->sin6_addr)) + else if (inet_pton(AF_INET6, params.binds[i].bindaddr, &((struct sockaddr_in6 *)(&list[i].salisten))->sin6_addr)) { list[i].salisten.ss_family = AF_INET6; list[i].ipv6_only = 1; @@ -1172,42 +1182,42 @@ int main(int argc, char *argv[]) { bool found; enum bindll bindll_1; - int sec=0; + int sec = 0; if (params.binds[i].bind_wait_ip > 0) { DLOG_CONDUP("waiting for ip on %s for up to %d second(s)...\n", *params.binds[i].bindiface ? params.binds[i].bindiface : "", params.binds[i].bind_wait_ip); - if (params.binds[i].bind_wait_ip_ll>0) + if (params.binds[i].bind_wait_ip_ll > 0) { - if (params.binds[i].bindll==prefer) + if (params.binds[i].bindll == prefer) DLOG_CONDUP("during the first %d second(s) accepting only link locals...\n", params.binds[i].bind_wait_ip_ll); - else if (params.binds[i].bindll==unwanted) - DLOG_CONDUP("during the first %d second(s) accepting only ipv6 globals...\n", params.binds[i].bind_wait_ip_ll); + else if (params.binds[i].bindll == unwanted) + DLOG_CONDUP("during the first %d second(s) accepting only IPv6 globals...\n", params.binds[i].bind_wait_ip_ll); } } - for(;;) + for (;;) { // allow, no, prefer, force - bindll_1 = (params.binds[i].bindll==prefer && sec=params.binds[i].bind_wait_ip) + if (sec >= params.binds[i].bind_wait_ip) break; sleep(1); sec++; - } + } if (!found) { @@ -1215,7 +1225,7 @@ int main(int argc, char *argv[]) goto exiterr; } list[i].bind_wait_ip_left = params.binds[i].bind_wait_ip - sec; - list[i].ipv6_only=1; + list[i].ipv6_only = 1; } else { @@ -1226,14 +1236,14 @@ int main(int argc, char *argv[]) if (list[i].salisten.ss_family == AF_INET6) { list[i].salisten_len = sizeof(struct sockaddr_in6); - ((struct sockaddr_in6*)(&list[i].salisten))->sin6_port = htons(params.port); - if (is_linklocal((struct sockaddr_in6*)(&list[i].salisten))) - ((struct sockaddr_in6*)(&list[i].salisten))->sin6_scope_id = if_index; + ((struct sockaddr_in6 *)(&list[i].salisten))->sin6_port = htons(params.port); + if (is_linklocal((struct sockaddr_in6 *)(&list[i].salisten))) + ((struct sockaddr_in6 *)(&list[i].salisten))->sin6_scope_id = if_index; } else { list[i].salisten_len = sizeof(struct sockaddr_in); - ((struct sockaddr_in*)(&list[i].salisten))->sin_port = htons(params.port); + ((struct sockaddr_in *)(&list[i].salisten))->sin_port = htons(params.port); } } @@ -1244,27 +1254,28 @@ int main(int argc, char *argv[]) goto exiterr; } - if (params.proxy_type==CONN_TYPE_TRANSPARENT && !redir_init()) + if (params.proxy_type == CONN_TYPE_TRANSPARENT && !redir_init()) { DLOG_ERR("could not initialize redirector !!!\n"); goto exiterr; } - for(i=0;i<=params.binds_last;i++) + for (i = 0; i <= params.binds_last; i++) { if (params.debug) { ntop46_port((struct sockaddr *)&list[i].salisten, ip_port, sizeof(ip_port)); - VPRINT("Binding %d to %s\n",i,ip_port); + VPRINT("Binding %d to %s\n", i, ip_port); } - if ((listen_fd[i] = socket(list[i].salisten.ss_family, SOCK_STREAM, 0)) == -1) { + if ((listen_fd[i] = socket(list[i].salisten.ss_family, SOCK_STREAM, 0)) == -1) + { DLOG_PERROR("socket"); goto exiterr; } #ifndef __OpenBSD__ -// in OpenBSD always IPV6_ONLY for wildcard sockets + // in OpenBSD always IPV6_ONLY for wildcard sockets if ((list[i].salisten.ss_family == AF_INET6) && setsockopt(listen_fd[i], IPPROTO_IPV6, IPV6_V6ONLY, &list[i].ipv6_only, sizeof(int)) == -1) { DLOG_PERROR("setsockopt (IPV6_ONLY)"); @@ -1277,24 +1288,24 @@ int main(int argc, char *argv[]) DLOG_PERROR("setsockopt (SO_REUSEADDR)"); goto exiterr; } - - //Mark that this socket can be used for transparent proxying - //This allows the socket to accept connections for non-local IPs - if (params.proxy_type==CONN_TYPE_TRANSPARENT) + + // Mark that this socket can be used for transparent proxying + // This allows the socket to accept connections for non-local IPs + if (params.proxy_type == CONN_TYPE_TRANSPARENT) { - #ifdef __linux__ +#ifdef __linux__ if (setsockopt(listen_fd[i], SOL_IP, IP_TRANSPARENT, &yes, sizeof(yes)) == -1) { DLOG_PERROR("setsockopt (IP_TRANSPARENT)"); goto exiterr; } - #elif defined(BSD) && defined(SO_BINDANY) +#elif defined(BSD) && defined(SO_BINDANY) if (setsockopt(listen_fd[i], SOL_SOCKET, SO_BINDANY, &yes, sizeof(yes)) == -1) { DLOG_PERROR("setsockopt (SO_BINDANY)"); goto exiterr; } - #endif +#endif } if (!set_socket_buffers(listen_fd[i], params.local_rcvbuf, params.local_sndbuf)) @@ -1303,29 +1314,29 @@ int main(int argc, char *argv[]) { // HACK : dont know why but if dont set RCVBUF explicitly RCVBUF of accept()-ed socket can be very large. may be linux bug ? int v; - socklen_t sz=sizeof(int); - if (!getsockopt(listen_fd[i],SOL_SOCKET,SO_RCVBUF,&v,&sz)) + socklen_t sz = sizeof(int); + if (!getsockopt(listen_fd[i], SOL_SOCKET, SO_RCVBUF, &v, &sz)) { - v/=2; - setsockopt(listen_fd[i],SOL_SOCKET,SO_RCVBUF,&v,sizeof(int)); + v /= 2; + setsockopt(listen_fd[i], SOL_SOCKET, SO_RCVBUF, &v, sizeof(int)); } } - bool bBindBug=false; - for(;;) + bool bBindBug = false; + for (;;) { if (bind(listen_fd[i], (struct sockaddr *)&list[i].salisten, list[i].salisten_len) == -1) { // in linux strange behaviour was observed // just after ifup and address assignment there's short window when bind() can't bind to addresses got from getifaddrs() // it does not happen to transparent sockets because they can bind to any non-existend ip - // also only ipv6 seem to be buggy this way - if (errno==EADDRNOTAVAIL && params.proxy_type!=CONN_TYPE_TRANSPARENT && list[i].bind_wait_ip_left) + // also only IPv6 seem to be buggy this way + if (errno == EADDRNOTAVAIL && params.proxy_type != CONN_TYPE_TRANSPARENT && list[i].bind_wait_ip_left) { if (!bBindBug) { ntop46_port((struct sockaddr *)&list[i].salisten, ip_port, sizeof(ip_port)); - DLOG_CONDUP("address %s is not available. will retry for %d sec\n",ip_port,list[i].bind_wait_ip_left); - bBindBug=true; + DLOG_CONDUP("address %s is not available. will retry for %d sec\n", ip_port, list[i].bind_wait_ip_left); + bBindBug = true; } sleep(1); list[i].bind_wait_ip_left--; @@ -1346,30 +1357,34 @@ int main(int argc, char *argv[]) set_ulimit(); sec_harden(); - if (params.droproot && !droproot(params.uid,params.gid)) + if (params.droproot && !droproot(params.uid, params.gid)) goto exiterr; print_id(); - //splice() causes the process to receive the SIGPIPE-signal if one part (for - //example a socket) is closed during splice(). I would rather have splice() - //fail and return -1, so blocking SIGPIPE. - if (block_sigpipe() == -1) { + // splice() causes the process to receive the SIGPIPE-signal if one part (for + // example a socket) is closed during splice(). I would rather have splice() + // fail and return -1, so blocking SIGPIPE. + if (block_sigpipe() == -1) + { DLOG_ERR("Could not block SIGPIPE signal\n"); goto exiterr; } - DLOG_CONDUP(params.proxy_type==CONN_TYPE_SOCKS ? "socks mode\n" : "transparent proxy mode\n"); - if (!params.tamper) DLOG_CONDUP("TCP proxy mode (no tampering)\n"); + DLOG_CONDUP(params.proxy_type == CONN_TYPE_SOCKS ? "SOCKS mode\n" : "transparent proxy mode\n"); + if (!params.tamper) + DLOG_CONDUP("TCP proxy mode (no tampering)\n"); - signal(SIGHUP, onhup); + signal(SIGHUP, onhup); signal(SIGUSR2, onusr2); - retval = event_loop(listen_fd,params.binds_last+1); + retval = event_loop(listen_fd, params.binds_last + 1); exit_v = retval < 0 ? EXIT_FAILURE : EXIT_SUCCESS; DLOG_CONDUP("Exiting\n"); - + exiterr: redir_close(); - for(i=0;i<=params.binds_last;i++) if (listen_fd[i]!=-1) close(listen_fd[i]); + for (i = 0; i <= params.binds_last; i++) + if (listen_fd[i] != -1) + close(listen_fd[i]); cleanup_params(); return exit_v; } diff --git a/tpws/tpws.h b/tpws/tpws.h index fa4eb30..dd72549 100644 --- a/tpws/tpws.h +++ b/tpws/tpws.h @@ -1,7 +1,7 @@ #pragma once #ifdef __linux__ - #define SPLICE_PRESENT +#define SPLICE_PRESENT #endif #include diff --git a/tpws/tpws_conn.c b/tpws/tpws_conn.c index 07e6d49..59bbebd 100644 --- a/tpws/tpws_conn.c +++ b/tpws/tpws_conn.c @@ -24,7 +24,6 @@ #include "helpers.h" #include "hostlist.h" - // keep separate legs counter. counting every time thousands of legs can consume cpu static int legs_local, legs_remote; /* @@ -35,7 +34,7 @@ static void count_legs(struct tailhead *conn_list) legs_local = legs_remote = 0; TAILQ_FOREACH(conn, conn_list, conn_ptrs) conn->remote ? legs_remote++ : legs_local++; - + } */ static void print_legs(void) @@ -43,34 +42,37 @@ static void print_legs(void) VPRINT("Legs : local:%d remote:%d\n", legs_local, legs_remote); } - -static bool socks5_send_rep(int fd,uint8_t rep) +static bool socks5_send_rep(int fd, uint8_t rep) { s5_rep s5rep; - memset(&s5rep,0,sizeof(s5rep)); + memset(&s5rep, 0, sizeof(s5rep)); s5rep.ver = 5; s5rep.rep = rep; s5rep.atyp = S5_ATYP_IP4; - return send(fd,&s5rep,sizeof(s5rep),MSG_DONTWAIT)==sizeof(s5rep); + return send(fd, &s5rep, sizeof(s5rep), MSG_DONTWAIT) == sizeof(s5rep); } -static bool socks5_send_rep_errno(int fd,int errn) +static bool socks5_send_rep_errno(int fd, int errn) { uint8_t rep; - switch(errn) + switch (errn) { - case 0: - rep=S5_REP_OK; break; - case ECONNREFUSED: - rep=S5_REP_CONN_REFUSED; break; - case ENETUNREACH: - rep=S5_REP_NETWORK_UNREACHABLE; break; - case ETIMEDOUT: - case EHOSTUNREACH: - rep=S5_REP_HOST_UNREACHABLE; break; - default: - rep=S5_REP_GENERAL_FAILURE; + case 0: + rep = S5_REP_OK; + break; + case ECONNREFUSED: + rep = S5_REP_CONN_REFUSED; + break; + case ENETUNREACH: + rep = S5_REP_NETWORK_UNREACHABLE; + break; + case ETIMEDOUT: + case EHOSTUNREACH: + rep = S5_REP_HOST_UNREACHABLE; + break; + default: + rep = S5_REP_GENERAL_FAILURE; } - return socks5_send_rep(fd,rep); + return socks5_send_rep(fd, rep); } static bool socks4_send_rep(int fd, uint8_t rep) { @@ -85,37 +87,35 @@ static bool socks4_send_rep_errno(int fd, int errn) } static bool socks_send_rep(uint8_t ver, int fd, uint8_t rep5) { - return ver==5 ? socks5_send_rep(fd, rep5) : socks4_send_rep(fd, rep5 ? S4_REP_FAILED : S4_REP_OK); + return ver == 5 ? socks5_send_rep(fd, rep5) : socks4_send_rep(fd, rep5 ? S4_REP_FAILED : S4_REP_OK); } static bool socks_send_rep_errno(uint8_t ver, int fd, int errn) { - return ver==5 ? socks5_send_rep_errno(fd,errn) : socks4_send_rep_errno(fd, errn); + return ver == 5 ? socks5_send_rep_errno(fd, errn) : socks4_send_rep_errno(fd, errn); } - ssize_t send_with_ttl(int fd, const void *buf, size_t len, int flags, int ttl) { - ssize_t wr; + ssize_t wr; if (ttl) { - DBGPRINT("send_with_ttl %d fd=%d\n",ttl,fd); + DBGPRINT("send_with_ttl %d fd=%d\n", ttl, fd); if (!set_ttl_hl(fd, ttl)) - //DLOG_ERR("could not set ttl %d to fd=%d\n",ttl,fd); - DLOG_ERR("could not set ttl %d to fd=%d\n",ttl,fd); + // DLOG_ERR("could not set TTL %d to fd=%d\n",ttl,fd); + DLOG_ERR("could not set TTL %d to fd=%d\n", ttl, fd); } wr = send(fd, buf, len, flags); if (ttl) { - int e=errno; + int e = errno; if (!set_ttl_hl(fd, params.ttl_default)) - DLOG_ERR("could not set ttl %d to fd=%d\n",params.ttl_default,fd); - errno=e; + DLOG_ERR("could not set TTL %d to fd=%d\n", params.ttl_default, fd); + errno = e; } return wr; } - static bool send_buffer_create(send_buffer_t *sb, const void *data, size_t len, size_t extra_bytes, int flags, int ttl) { if (sb->data) @@ -129,7 +129,8 @@ static bool send_buffer_create(send_buffer_t *sb, const void *data, size_t len, DBGPRINT("send_buffer_create failed\n"); return false; } - if (data) memcpy(sb->data,data,len); + if (data) + memcpy(sb->data, data, len); sb->len = len; sb->pos = 0; sb->ttl = ttl; @@ -140,7 +141,7 @@ static bool send_buffer_realloc(send_buffer_t *sb, size_t extra_bytes) { if (sb->data) { - uint8_t *p = (uint8_t*)realloc(sb->data, sb->len + extra_bytes); + uint8_t *p = (uint8_t *)realloc(sb->data, sb->len + extra_bytes); if (p) { sb->data = p; @@ -165,12 +166,12 @@ static void send_buffer_free(send_buffer_t *sb) } static void send_buffers_free(send_buffer_t *sb_array, int count) { - for (int i=0;iwr_buf,sizeof(conn->wr_buf)/sizeof(conn->wr_buf[0])); + send_buffers_free(conn->wr_buf, sizeof(conn->wr_buf) / sizeof(conn->wr_buf[0])); } static bool send_buffer_present(send_buffer_t *sb) { @@ -178,8 +179,8 @@ static bool send_buffer_present(send_buffer_t *sb) } static bool send_buffers_present(send_buffer_t *sb_array, int count) { - for(int i=0;idata + sb->pos, sb->len - sb->pos, sb->flags, sb->ttl); - DBGPRINT("send_buffer_send len=%zu pos=%zu wr=%zd err=%d\n",sb->len,sb->pos,wr,errno); - if (wr>0) + DBGPRINT("send_buffer_send len=%zu pos=%zu wr=%zd err=%d\n", sb->len, sb->pos, wr, errno); + if (wr > 0) { sb->pos += wr; if (sb->pos >= sb->len) @@ -197,51 +198,54 @@ static ssize_t send_buffer_send(send_buffer_t *sb, int fd) send_buffer_free(sb); } } - else if (wr<0 && errno==EAGAIN) wr=0; - + else if (wr < 0 && errno == EAGAIN) + wr = 0; + return wr; } static ssize_t send_buffers_send(send_buffer_t *sb_array, int count, int fd, size_t *real_wr) { - ssize_t wr,twr=0; + ssize_t wr, twr = 0; - for (int i=0;iconn_type==CONN_TYPE_SOCKS && conn->socks_state!=S_TCP); + return !(conn->conn_type == CONN_TYPE_SOCKS && conn->socks_state != S_TCP); } static bool conn_partner_alive(tproxy_conn_t *conn) { - return conn->partner && conn->partner->state!=CONN_CLOSED; + return conn->partner && conn->partner->state != CONN_CLOSED; } static bool conn_buffers_present(tproxy_conn_t *conn) { - return send_buffers_present(conn->wr_buf,sizeof(conn->wr_buf)/sizeof(conn->wr_buf[0])); + return send_buffers_present(conn->wr_buf, sizeof(conn->wr_buf) / sizeof(conn->wr_buf[0])); } static ssize_t conn_buffers_send(tproxy_conn_t *conn) { - size_t wr,real_twr; - wr = send_buffers_send(conn->wr_buf,sizeof(conn->wr_buf)/sizeof(conn->wr_buf[0]), conn->fd, &real_twr); + size_t wr, real_twr; + wr = send_buffers_send(conn->wr_buf, sizeof(conn->wr_buf) / sizeof(conn->wr_buf[0]), conn->fd, &real_twr); conn->twr += real_twr; return wr; } @@ -251,7 +255,7 @@ static bool conn_has_unsent(tproxy_conn_t *conn) } static int conn_bytes_unread(tproxy_conn_t *conn) { - int numbytes=-1; + int numbytes = -1; ioctl(conn->fd, FIONREAD, &numbytes); return numbytes; } @@ -263,7 +267,7 @@ static bool conn_has_unsent_pair(tproxy_conn_t *conn) static bool conn_shutdown(tproxy_conn_t *conn) { conn->bShutdown = true; - if (shutdown(conn->fd,SHUT_WR)<0) + if (shutdown(conn->fd, SHUT_WR) < 0) { DLOG_PERROR("shutdown"); return false; @@ -273,15 +277,16 @@ static bool conn_shutdown(tproxy_conn_t *conn) static ssize_t send_or_buffer(send_buffer_t *sb, int fd, const void *buf, size_t len, int flags, int ttl) { - ssize_t wr=0; + ssize_t wr = 0; if (len) { wr = send_with_ttl(fd, buf, len, flags, ttl); - if (wr<0 && errno==EAGAIN) wr=0; - if (wr>=0 && wr= 0 && wr < len) { - if (!send_buffer_create(sb, buf+wr, len-wr, 0, flags, ttl)) - wr=-1; + if (!send_buffer_create(sb, buf + wr, len - wr, 0, flags, ttl)) + wr = -1; } } return wr; @@ -289,29 +294,29 @@ static ssize_t send_or_buffer(send_buffer_t *sb, int fd, const void *buf, size_t static void dbgprint_socket_buffers(int fd) { - if (params.debug>=2) + if (params.debug >= 2) { int v; socklen_t sz; - sz=sizeof(int); - if (!getsockopt(fd,SOL_SOCKET,SO_RCVBUF,&v,&sz)) - DBGPRINT("fd=%d SO_RCVBUF=%d\n",fd,v); - sz=sizeof(int); - if (!getsockopt(fd,SOL_SOCKET,SO_SNDBUF,&v,&sz)) - DBGPRINT("fd=%d SO_SNDBUF=%d\n",fd,v); + sz = sizeof(int); + if (!getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &v, &sz)) + DBGPRINT("fd=%d SO_RCVBUF=%d\n", fd, v); + sz = sizeof(int); + if (!getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &v, &sz)) + DBGPRINT("fd=%d SO_SNDBUF=%d\n", fd, v); } } bool set_socket_buffers(int fd, int rcvbuf, int sndbuf) { - DBGPRINT("set_socket_buffers fd=%d rcvbuf=%d sndbuf=%d\n",fd,rcvbuf,sndbuf); - if (rcvbuf && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) <0) + DBGPRINT("set_socket_buffers fd=%d rcvbuf=%d sndbuf=%d\n", fd, rcvbuf, sndbuf); + if (rcvbuf && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) < 0) { DLOG_PERROR("setsockopt (SO_RCVBUF)"); close(fd); return false; } - if (sndbuf && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) <0) + if (sndbuf && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0) { DLOG_PERROR("setsockopt (SO_SNDBUF)"); close(fd); @@ -325,18 +330,19 @@ static bool proxy_remote_conn_ack(tproxy_conn_t *conn, int sock_err) { // if proxy mode acknowledge connection request // conn = remote. conn->partner = local - if (!conn->remote || !conn_partner_alive(conn)) return false; + if (!conn->remote || !conn_partner_alive(conn)) + return false; bool bres = true; - switch(conn->partner->conn_type) + switch (conn->partner->conn_type) { - case CONN_TYPE_SOCKS: - if (conn->partner->socks_state==S_WAIT_CONNECTION) - { - conn->partner->socks_state=S_TCP; - bres = socks_send_rep_errno(conn->partner->socks_ver,conn->partner->fd,sock_err); - DBGPRINT("socks connection acknowledgement. bres=%d remote_errn=%d remote_fd=%d local_fd=%d\n",bres,sock_err,conn->fd,conn->partner->fd); - } - break; + case CONN_TYPE_SOCKS: + if (conn->partner->socks_state == S_WAIT_CONNECTION) + { + conn->partner->socks_state = S_TCP; + bres = socks_send_rep_errno(conn->partner->socks_ver, conn->partner->fd, sock_err); + DBGPRINT("SOCKS connection acknowledgement. bres=%d remote_errn=%d remote_fd=%d local_fd=%d\n", bres, sock_err, conn->fd, conn->partner->fd); + } + break; } return bres; } @@ -346,41 +352,39 @@ static bool proxy_remote_conn_ack(tproxy_conn_t *conn, int sock_err) static void set_user_timeout(int fd, int timeout) { #ifdef __linux__ - if (timeout>0) + if (timeout > 0) { - int msec = 1000*timeout; - if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &msec, sizeof(int)) <0) + int msec = 1000 * timeout; + if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &msec, sizeof(int)) < 0) DLOG_PERROR("setsockopt (TCP_USER_TIMEOUT)"); } #elif defined(__APPLE__) - if (timeout>0 && setsockopt(fd, IPPROTO_TCP, TCP_RXT_CONNDROPTIME, &timeout, sizeof(int)) <0) + if (timeout > 0 && setsockopt(fd, IPPROTO_TCP, TCP_RXT_CONNDROPTIME, &timeout, sizeof(int)) < 0) DLOG_PERROR("setsockopt (TCP_RXT_CONNDROPTIME)"); #endif } #else -#define set_user_timeout(fd,timeout) +#define set_user_timeout(fd, timeout) #endif - -//Createas a socket and initiates the connection to the host specified by -//remote_addr. -//Returns -1 if something fails, >0 on success (socket fd). +// Creates a socket and initiates the connection to the host specified by +// remote_addr. +// Returns -1 if something fails, >0 on success (socket fd). static int connect_remote(const struct sockaddr *remote_addr, bool bApplyConnectionFooling) { int remote_fd = 0, yes = 1, no = 0; - - - if((remote_fd = socket(remote_addr->sa_family, SOCK_STREAM, 0)) < 0) - { + + if ((remote_fd = socket(remote_addr->sa_family, SOCK_STREAM, 0)) < 0) + { DLOG_PERROR("socket (connect_remote)"); return -1; } // Use NONBLOCK to avoid slow connects affecting the performance of other connections - // separate fcntl call to comply with macos - if (fcntl(remote_fd, F_SETFL, O_NONBLOCK)<0) + // separate fcntl call to comply with macOS + if (fcntl(remote_fd, F_SETFL, O_NONBLOCK) < 0) { DLOG_PERROR("socket set O_NONBLOCK (connect_remote)"); close(remote_fd); @@ -400,7 +404,7 @@ static int connect_remote(const struct sockaddr *remote_addr, bool bApplyConnect close(remote_fd); return -1; } - if (setsockopt(remote_fd, IPPROTO_TCP, TCP_NODELAY, params.skip_nodelay ? &no : &yes, sizeof(int)) <0) + if (setsockopt(remote_fd, IPPROTO_TCP, TCP_NODELAY, params.skip_nodelay ? &no : &yes, sizeof(int)) < 0) { DLOG_PERROR("setsockopt (TCP_NODELAY, connect_remote)"); close(remote_fd); @@ -409,10 +413,10 @@ static int connect_remote(const struct sockaddr *remote_addr, bool bApplyConnect if (bApplyConnectionFooling && params.mss) { uint16_t port = saport(remote_addr); - if (pf_in_range(port,¶ms.mss_pf)) + if (pf_in_range(port, ¶ms.mss_pf)) { - VPRINT("Setting MSS %d\n",params.mss); - if (setsockopt(remote_fd, IPPROTO_TCP, TCP_MAXSEG, ¶ms.mss, sizeof(int)) <0) + VPRINT("Setting MSS %d\n", params.mss); + if (setsockopt(remote_fd, IPPROTO_TCP, TCP_MAXSEG, ¶ms.mss, sizeof(int)) < 0) { DLOG_PERROR("setsockopt (TCP_MAXSEG, connect_remote)"); close(remote_fd); @@ -421,12 +425,12 @@ static int connect_remote(const struct sockaddr *remote_addr, bool bApplyConnect } else { - VPRINT("Not setting MSS. Port %u is out of MSS port range.\n",port); + VPRINT("Not setting MSS. Port %u is out of MSS port range.\n", port); } } // if no bind address specified - address family will be 0 in params_connect_bindX - if(remote_addr->sa_family == params.connect_bind4.sin_family) + if (remote_addr->sa_family == params.connect_bind4.sin_family) { if (bind(remote_fd, (struct sockaddr *)¶ms.connect_bind4, sizeof(struct sockaddr_in)) == -1) { @@ -435,11 +439,11 @@ static int connect_remote(const struct sockaddr *remote_addr, bool bApplyConnect return -1; } } - else if(remote_addr->sa_family == params.connect_bind6.sin6_family) + else if (remote_addr->sa_family == params.connect_bind6.sin6_family) { if (*params.connect_bind6_ifname && !params.connect_bind6.sin6_scope_id) { - params.connect_bind6.sin6_scope_id=if_nametoindex(params.connect_bind6_ifname); + params.connect_bind6.sin6_scope_id = if_nametoindex(params.connect_bind6_ifname); if (!params.connect_bind6.sin6_scope_id) { DLOG_ERR("interface name not found : %s\n", params.connect_bind6_ifname); @@ -460,41 +464,45 @@ static int connect_remote(const struct sockaddr *remote_addr, bool bApplyConnect if (connect(remote_fd, remote_addr, remote_addr->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) < 0) { - if(errno != EINPROGRESS) + if (errno != EINPROGRESS) { DLOG_PERROR("connect (connect_remote)"); close(remote_fd); return -1; } } - DBGPRINT("Connecting remote fd=%d\n",remote_fd); + DBGPRINT("Connecting remote fd=%d\n", remote_fd); return remote_fd; } - -//Free resources occupied by this connection +// Free resources occupied by this connection static void free_conn(tproxy_conn_t *conn) { - if (!conn) return; - if (conn->fd) close(conn->fd); + if (!conn) + return; + if (conn->fd) + close(conn->fd); if (conn->splice_pipe[0]) { close(conn->splice_pipe[0]); close(conn->splice_pipe[1]); } conn_free_buffers(conn); - if (conn->partner) conn->partner->partner=NULL; - if (conn->track.hostname) free(conn->track.hostname); - if (conn->socks_ri) conn->socks_ri->ptr = NULL; // detach conn + if (conn->partner) + conn->partner->partner = NULL; + if (conn->track.hostname) + free(conn->track.hostname); + if (conn->socks_ri) + conn->socks_ri->ptr = NULL; // detach conn free(conn); } static tproxy_conn_t *new_conn(int fd, bool remote) { tproxy_conn_t *conn; - //Create connection object and fill in information - if((conn = (tproxy_conn_t*) malloc(sizeof(tproxy_conn_t))) == NULL) + // Create connection object and fill in information + if ((conn = (tproxy_conn_t *)malloc(sizeof(tproxy_conn_t))) == NULL) { DLOG_ERR("Could not allocate memory for connection\n"); return NULL; @@ -508,14 +516,14 @@ static tproxy_conn_t *new_conn(int fd, bool remote) #ifdef SPLICE_PRESENT // if dont tamper - both legs are spliced, create 2 pipes // otherwise create pipe only in local leg - if (!params.nosplice && ( !remote || !params.tamper || params.tamper_start || params.tamper_cutoff ) && pipe2(conn->splice_pipe, O_NONBLOCK) != 0) + if (!params.nosplice && (!remote || !params.tamper || params.tamper_start || params.tamper_cutoff) && pipe2(conn->splice_pipe, O_NONBLOCK) != 0) { DLOG_ERR("Could not create the splice pipe\n"); free_conn(conn); return NULL; } #endif - + return conn; } @@ -525,10 +533,10 @@ static bool epoll_set(tproxy_conn_t *conn, uint32_t events) memset(&ev, 0, sizeof(ev)); ev.events = events; - ev.data.ptr = (void*) conn; - DBGPRINT("epoll_set fd=%d events=%08X\n",conn->fd,events); - if(epoll_ctl(conn->efd, EPOLL_CTL_MOD, conn->fd, &ev)==-1 && - epoll_ctl(conn->efd, EPOLL_CTL_ADD, conn->fd, &ev)==-1) + ev.data.ptr = (void *)conn; + DBGPRINT("epoll_set fd=%d events=%08X\n", conn->fd, events); + if (epoll_ctl(conn->efd, EPOLL_CTL_MOD, conn->fd, &ev) == -1 && + epoll_ctl(conn->efd, EPOLL_CTL_ADD, conn->fd, &ev) == -1) { DLOG_PERROR("epoll_ctl (add/mod)"); return false; @@ -541,8 +549,8 @@ static bool epoll_del(tproxy_conn_t *conn) memset(&ev, 0, sizeof(ev)); - DBGPRINT("epoll_del fd=%d\n",conn->fd); - if(epoll_ctl(conn->efd, EPOLL_CTL_DEL, conn->fd, &ev)==-1) + DBGPRINT("epoll_del fd=%d\n", conn->fd); + if (epoll_ctl(conn->efd, EPOLL_CTL_DEL, conn->fd, &ev) == -1) { DLOG_PERROR("epoll_ctl (del)"); return false; @@ -552,15 +560,15 @@ static bool epoll_del(tproxy_conn_t *conn) static bool epoll_update_flow(tproxy_conn_t *conn) { - if (conn->bFlowInPrev==conn->bFlowIn && conn->bFlowOutPrev==conn->bFlowOut && conn->bPrevRdhup==(conn->state==CONN_RDHUP)) + if (conn->bFlowInPrev == conn->bFlowIn && conn->bFlowOutPrev == conn->bFlowOut && conn->bPrevRdhup == (conn->state == CONN_RDHUP)) return true; // unchanged, no need to syscall - DBGPRINT("SET FLOW fd=%d to in=%d out=%d state_rdhup=%d\n",conn->fd,conn->bFlowIn,conn->bFlowOut,conn->state==CONN_RDHUP); - uint32_t evtmask = (conn->state==CONN_RDHUP ? 0 : EPOLLRDHUP)|(conn->bFlowIn?EPOLLIN:0)|(conn->bFlowOut?EPOLLOUT:0); + DBGPRINT("SET FLOW fd=%d to in=%d out=%d state_rdhup=%d\n", conn->fd, conn->bFlowIn, conn->bFlowOut, conn->state == CONN_RDHUP); + uint32_t evtmask = (conn->state == CONN_RDHUP ? 0 : EPOLLRDHUP) | (conn->bFlowIn ? EPOLLIN : 0) | (conn->bFlowOut ? EPOLLOUT : 0); if (!epoll_set(conn, evtmask)) return false; conn->bFlowInPrev = conn->bFlowIn; conn->bFlowOutPrev = conn->bFlowOut; - conn->bPrevRdhup = (conn->state==CONN_RDHUP); + conn->bPrevRdhup = (conn->state == CONN_RDHUP); return true; } static bool epoll_set_flow(tproxy_conn_t *conn, bool bFlowIn, bool bFlowOut) @@ -570,23 +578,23 @@ static bool epoll_set_flow(tproxy_conn_t *conn, bool bFlowIn, bool bFlowOut) return epoll_update_flow(conn); } -//Acquires information, initiates a connect and initialises a new connection -//object. Return NULL if anything fails, pointer to object otherwise -static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int local_fd, const struct sockaddr *accept_sa, uint16_t listen_port, conn_type_t proxy_type) +// Acquires information, initiates a connect and initialises a new connection +// object. Return NULL if anything fails, pointer to object otherwise +static tproxy_conn_t *add_tcp_connection(int efd, struct tailhead *conn_list, int local_fd, const struct sockaddr *accept_sa, uint16_t listen_port, conn_type_t proxy_type) { struct sockaddr_storage orig_dst; tproxy_conn_t *conn; - int remote_fd=0; + int remote_fd = 0; - if (proxy_type==CONN_TYPE_TRANSPARENT) + if (proxy_type == CONN_TYPE_TRANSPARENT) { - if(!get_dest_addr(local_fd, accept_sa, &orig_dst)) + if (!get_dest_addr(local_fd, accept_sa, &orig_dst)) { DLOG_ERR("Could not get destination address\n"); close(local_fd); return NULL; } - if (check_local_ip((struct sockaddr*)&orig_dst) && saport((struct sockaddr*)&orig_dst)==listen_port) + if (check_local_ip((struct sockaddr *)&orig_dst) && saport((struct sockaddr *)&orig_dst) == listen_port) { VPRINT("Dropping connection to local address to the same port to avoid loop\n"); close(local_fd); @@ -597,14 +605,14 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int // socket buffers inherited from listen_fd dbgprint_socket_buffers(local_fd); - if(!set_keepalive(local_fd)) + if (!set_keepalive(local_fd)) { DLOG_PERROR("set_keepalive"); close(local_fd); return 0; } - if (proxy_type==CONN_TYPE_TRANSPARENT) + if (proxy_type == CONN_TYPE_TRANSPARENT) { if ((remote_fd = connect_remote((struct sockaddr *)&orig_dst, true)) < 0) { @@ -614,9 +622,10 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int } } - if(!(conn = new_conn(local_fd, false))) + if (!(conn = new_conn(local_fd, false))) { - if (remote_fd) close(remote_fd); + if (remote_fd) + close(remote_fd); close(local_fd); return NULL; } @@ -624,9 +633,9 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int conn->state = CONN_AVAILABLE; // accepted connection is immediately available conn->efd = efd; - if (proxy_type==CONN_TYPE_TRANSPARENT) + if (proxy_type == CONN_TYPE_TRANSPARENT) { - if(!(conn->partner = new_conn(remote_fd, true))) + if (!(conn->partner = new_conn(remote_fd, true))) { free_conn(conn); close(remote_fd); @@ -635,8 +644,8 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int conn->partner->partner = conn; conn->partner->efd = efd; - //remote_fd is connecting. Non-blocking connects are signaled as done by - //socket being marked as ready for writing + // remote_fd is connecting. Non-blocking connects are signaled as done by + // socket being marked as ready for writing if (!epoll_set(conn->partner, EPOLLOUT)) { free_conn(conn->partner); @@ -645,15 +654,15 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int } } - //Transparent proxy mode : - // Local socket can be closed while waiting for connection attempt. I need - // to detect this when waiting for connect() to complete. However, I dont - // want to get EPOLLIN-events, as I dont want to receive any data before - // remote connection is established - //Proxy mode : I need to service proxy protocol - // remote connection not started until proxy handshake is complete + // Transparent proxy mode : + // Local socket can be closed while waiting for connection attempt. I need + // to detect this when waiting for connect() to complete. However, I don't + // want to get EPOLLIN-events, as I don't want to receive any data before + // remote connection is established + // Proxy mode : I need to service proxy protocol + // remote connection not started until proxy handshake is complete - if (!epoll_set(conn, proxy_type==CONN_TYPE_TRANSPARENT ? EPOLLRDHUP : (EPOLLIN|EPOLLRDHUP))) + if (!epoll_set(conn, proxy_type == CONN_TYPE_TRANSPARENT ? EPOLLRDHUP : (EPOLLIN | EPOLLRDHUP))) { free_conn(conn->partner); free_conn(conn); @@ -668,16 +677,16 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int legs_remote++; } return conn; -} +} -//Checks if a connection attempt was successful or not -//Returns true if successfull, false if not +// Checks if a connection attempt was successful or not +// Returns true if successfull, false if not static bool check_connection_attempt(tproxy_conn_t *conn, int efd) { int errn = 0; socklen_t optlen = sizeof(errn); - if (conn->state!=CONN_UNAVAILABLE || !conn->remote) + if (conn->state != CONN_UNAVAILABLE || !conn->remote) { // locals are connected since accept // remote need to be checked only once @@ -685,23 +694,23 @@ static bool check_connection_attempt(tproxy_conn_t *conn, int efd) } // check the connection was sucessfull. it means its not in in SO_ERROR state - if(getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1) + if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1) { DLOG_PERROR("getsockopt (SO_ERROR)"); return false; } if (!errn) { - if (params.debug>=1) + if (params.debug >= 1) { struct sockaddr_storage sa; - socklen_t salen=sizeof(sa); + socklen_t salen = sizeof(sa); char ip_port[48]; - if (getsockname(conn->fd,(struct sockaddr *)&sa,&salen)) - *ip_port=0; + if (getsockname(conn->fd, (struct sockaddr *)&sa, &salen)) + *ip_port = 0; else - ntop46_port((struct sockaddr*)&sa,ip_port,sizeof(ip_port)); + ntop46_port((struct sockaddr *)&sa, ip_port, sizeof(ip_port)); VPRINT("Socket fd=%d (remote) connected from : %s\n", conn->fd, ip_port); } if (!epoll_set_flow(conn, true, false) || (conn_partner_alive(conn) && !epoll_set_flow(conn->partner, true, false))) @@ -710,20 +719,17 @@ static bool check_connection_attempt(tproxy_conn_t *conn, int efd) } conn->state = CONN_AVAILABLE; } - proxy_remote_conn_ack(conn,get_so_error(conn->fd)); + proxy_remote_conn_ack(conn, get_so_error(conn->fd)); return !errn; } - - - static bool epoll_set_flow_pair(tproxy_conn_t *conn) { bool bHasUnsent = conn_has_unsent(conn); bool bHasUnsentPartner = conn_partner_alive(conn) ? conn_has_unsent(conn->partner) : false; - DBGPRINT("epoll_set_flow_pair fd=%d remote=%d partner_fd=%d bHasUnsent=%d bHasUnsentPartner=%d state_rdhup=%d\n", - conn->fd , conn->remote, conn_partner_alive(conn) ? conn->partner->fd : 0, bHasUnsent, bHasUnsentPartner, conn->state==CONN_RDHUP); + DBGPRINT("epoll_set_flow_pair fd=%d remote=%d partner_fd=%d bHasUnsent=%d bHasUnsentPartner=%d state_rdhup=%d\n", + conn->fd, conn->remote, conn_partner_alive(conn) ? conn->partner->fd : 0, bHasUnsent, bHasUnsentPartner, conn->state == CONN_RDHUP); if (!epoll_set_flow(conn, !bHasUnsentPartner && (conn->state != CONN_RDHUP), bHasUnsent)) return false; if (conn_partner_alive(conn)) @@ -738,17 +744,19 @@ static bool handle_unsent(tproxy_conn_t *conn) { ssize_t wr; - DBGPRINT("+handle_unsent, fd=%d has_unsent=%d has_unsent_partner=%d\n",conn->fd,conn_has_unsent(conn),conn_partner_alive(conn) ? conn_has_unsent(conn->partner) : false); - + DBGPRINT("+handle_unsent, fd=%d has_unsent=%d has_unsent_partner=%d\n", conn->fd, conn_has_unsent(conn), conn_partner_alive(conn) ? conn_has_unsent(conn->partner) : false); + #ifdef SPLICE_PRESENT if (!params.nosplice && conn->wr_unsent) { wr = splice(conn->splice_pipe[0], NULL, conn->fd, NULL, conn->wr_unsent, SPLICE_F_MOVE | SPLICE_F_NONBLOCK); - DBGPRINT("splice unsent=%zd wr=%zd err=%d\n",conn->wr_unsent,wr,errno); - if (wr<0) + DBGPRINT("splice unsent=%zd wr=%zd err=%d\n", conn->wr_unsent, wr, errno); + if (wr < 0) { - if (errno==EAGAIN) wr=0; - else return false; + if (errno == EAGAIN) + wr = 0; + else + return false; } conn->twr += wr; conn->wr_unsent -= wr; @@ -756,11 +764,12 @@ static bool handle_unsent(tproxy_conn_t *conn) #endif if (!conn->wr_unsent && conn_buffers_present(conn)) { - wr=conn_buffers_send(conn); - DBGPRINT("conn_buffers_send wr=%zd\n",wr); - if (wr<0) return false; + wr = conn_buffers_send(conn); + DBGPRINT("conn_buffers_send wr=%zd\n", wr); + if (wr < 0) + return false; } - if (!conn_has_unsent(conn) && conn_partner_alive(conn) && conn->partner->state==CONN_RDHUP) + if (!conn_has_unsent(conn) && conn_partner_alive(conn) && conn->partner->state == CONN_RDHUP) { if (!conn->bShutdown) { @@ -771,7 +780,7 @@ static bool handle_unsent(tproxy_conn_t *conn) return false; } } - if (conn->state==CONN_RDHUP && !conn_has_unsent(conn->partner)) + if (conn->state == CONN_RDHUP && !conn_has_unsent(conn->partner)) { DBGPRINT("both partners are in RDHUP state and have no unsent. closing.\n"); return false; @@ -781,16 +790,15 @@ static bool handle_unsent(tproxy_conn_t *conn) return epoll_set_flow_pair(conn); } - bool proxy_mode_connect_remote(const struct sockaddr *sa, tproxy_conn_t *conn, struct tailhead *conn_list) { int remote_fd; - if (params.debug>=1) + if (params.debug >= 1) { char ip_port[48]; - ntop46_port(sa,ip_port,sizeof(ip_port)); - VPRINT("socks target for fd=%d is : %s\n", conn->fd, ip_port); + ntop46_port(sa, ip_port, sizeof(ip_port)); + VPRINT("SOCKS target for fd=%d is : %s\n", conn->fd, ip_port); } if (check_local_ip((struct sockaddr *)sa)) { @@ -799,10 +807,10 @@ bool proxy_mode_connect_remote(const struct sockaddr *sa, tproxy_conn_t *conn, s return false; } - bool bConnFooling=true; + bool bConnFooling = true; if (conn->track.hostname && params.mss) { - bConnFooling=HostlistCheck(conn->track.hostname, NULL); + bConnFooling = HostlistCheck(conn->track.hostname, NULL); if (!bConnFooling) VPRINT("0-phase desync hostlist check negative. not acting on this connection.\n"); } @@ -843,183 +851,186 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list) // To simplify things I dont care about buffering. If message splits, I just hang up // in proxy mode messages are short. they can be split only intentionally. all normal programs send them in one packet - ssize_t rd,wr; + ssize_t rd, wr; char buf[sizeof(s5_req)]; // s5_req - the largest possible req struct sockaddr_storage ss; // receive proxy control message - rd=recv(conn->fd, buf, sizeof(buf), MSG_DONTWAIT); - DBGPRINT("handle_proxy_mode rd=%zd\n",rd); - if (rd<1) return false; // hangup - switch(conn->conn_type) + rd = recv(conn->fd, buf, sizeof(buf), MSG_DONTWAIT); + DBGPRINT("handle_proxy_mode rd=%zd\n", rd); + if (rd < 1) + return false; // hangup + switch (conn->conn_type) { - case CONN_TYPE_SOCKS: - switch(conn->socks_state) + case CONN_TYPE_SOCKS: + switch (conn->socks_state) + { + case S_WAIT_HANDSHAKE: + DBGPRINT("S_WAIT_HANDSHAKE\n"); + if (buf[0] != 5 && buf[0] != 4) + return false; // unknown SOCKS version + conn->socks_ver = buf[0]; + DBGPRINT("SOCKS version %u\n", conn->socks_ver); + if (conn->socks_ver == 5) { - case S_WAIT_HANDSHAKE: - DBGPRINT("S_WAIT_HANDSHAKE\n"); - if (buf[0] != 5 && buf[0] != 4) return false; // unknown socks version - conn->socks_ver = buf[0]; - DBGPRINT("socks version %u\n", conn->socks_ver); - if (conn->socks_ver==5) - { - s5_handshake *m = (s5_handshake*)buf; - s5_handshake_ack ack; - uint8_t k; + s5_handshake *m = (s5_handshake *)buf; + s5_handshake_ack ack; + uint8_t k; - ack.ver=5; - if (!S5_REQ_HANDHSHAKE_VALID(m,rd)) - { - DBGPRINT("socks5 proxy handshake invalid\n"); - return false; - } - for (k=0;knmethods;k++) if (m->methods[k]==S5_AUTH_NONE) break; - if (k>=m->nmethods) - { - DBGPRINT("socks5 client wants authentication but we dont support\n"); - ack.method=S5_AUTH_UNACCEPTABLE; - wr=send(conn->fd,&ack,sizeof(ack),MSG_DONTWAIT); - return false; - } - DBGPRINT("socks5 recv valid handshake\n"); - ack.method=S5_AUTH_NONE; - wr=send(conn->fd,&ack,sizeof(ack),MSG_DONTWAIT); - if (wr!=sizeof(ack)) - { - DBGPRINT("socks5 handshake ack send error. wr=%zd errno=%d\n",wr,errno); - return false; - } - DBGPRINT("socks5 send handshake ack OK\n"); - conn->socks_state=S_WAIT_REQUEST; - return true; - } - else - { - // socks4 does not have separate handshake phase. it starts with connect request - // ipv6 and domain resolving are not supported - s4_req *m = (s4_req*)buf; - if (!S4_REQ_HEADER_VALID(m, rd)) - { - DBGPRINT("socks4 request invalid\n"); - return false; - } - if (m->cmd!=S4_CMD_CONNECT) - { - // BIND is not supported - DBGPRINT("socks4 unsupported command %02X\n", m->cmd); - socks4_send_rep(conn->fd, S4_REP_FAILED); - return false; - } - if (!S4_REQ_CONNECT_VALID(m, rd)) - { - DBGPRINT("socks4 connect request invalid\n"); - socks4_send_rep(conn->fd, S4_REP_FAILED); - return false; - } - if (!m->port) - { - DBGPRINT("socks4 zero port\n"); - socks4_send_rep(conn->fd, S4_REP_FAILED); - return false; - } - if (m->ip==htonl(1)) // special ip 0.0.0.1 - { - VPRINT("socks4a protocol not supported\n"); - socks4_send_rep(conn->fd, S4_REP_FAILED); - return false; - } - ss.ss_family = AF_INET; - ((struct sockaddr_in*)&ss)->sin_port = m->port; - ((struct sockaddr_in*)&ss)->sin_addr.s_addr = m->ip; - return proxy_mode_connect_remote((struct sockaddr *)&ss, conn, conn_list); - } - break; - case S_WAIT_REQUEST: - DBGPRINT("S_WAIT_REQUEST\n"); - { - s5_req *m = (s5_req*)buf; - - if (!S5_REQ_HEADER_VALID(m,rd)) - { - DBGPRINT("socks5 request invalid\n"); - return false; - } - if (m->cmd!=S5_CMD_CONNECT) - { - // BIND and UDP are not supported - DBGPRINT("socks5 unsupported command %02X\n", m->cmd); - socks5_send_rep(conn->fd,S5_REP_COMMAND_NOT_SUPPORTED); - return false; - } - if (!S5_REQ_CONNECT_VALID(m,rd)) - { - DBGPRINT("socks5 connect request invalid\n"); - return false; - } - DBGPRINT("socks5 recv valid connect request\n"); - switch(m->atyp) - { - case S5_ATYP_IP4: - ss.ss_family = AF_INET; - ((struct sockaddr_in*)&ss)->sin_port = m->d4.port; - ((struct sockaddr_in*)&ss)->sin_addr = m->d4.addr; - break; - case S5_ATYP_IP6: - ss.ss_family = AF_INET6; - ((struct sockaddr_in6*)&ss)->sin6_port = m->d6.port; - ((struct sockaddr_in6*)&ss)->sin6_addr = m->d6.addr; - ((struct sockaddr_in6*)&ss)->sin6_flowinfo = 0; - ((struct sockaddr_in6*)&ss)->sin6_scope_id = 0; - break; - case S5_ATYP_DOM: - { - uint16_t port; - - if (params.no_resolve) - { - VPRINT("socks5 hostname resolving disabled\n"); - socks5_send_rep(conn->fd,S5_REP_NOT_ALLOWED_BY_RULESET); - return false; - } - port=S5_PORT_FROM_DD(m,rd); - if (!port) - { - VPRINT("socks5 no port is given\n"); - socks5_send_rep(conn->fd,S5_REP_HOST_UNREACHABLE); - return false; - } - m->dd.domport[m->dd.len] = 0; - DBGPRINT("socks5 queue resolve hostname '%s' port '%u'\n",m->dd.domport,port); - conn->socks_ri = resolver_queue(m->dd.domport,port,conn); - if (!conn->socks_ri) - { - VPRINT("socks5 could not queue resolve item\n"); - socks5_send_rep(conn->fd,S5_REP_GENERAL_FAILURE); - return false; - } - conn->socks_state=S_WAIT_RESOLVE; - DBGPRINT("S_WAIT_RESOLVE\n"); - return true; - } - break; - default: - return false; // should not be here. S5_REQ_CONNECT_VALID checks for valid atyp - - } - return proxy_mode_connect_remote((struct sockaddr *)&ss,conn,conn_list); - } - break; - case S_WAIT_RESOLVE: - DBGPRINT("socks received message while in S_WAIT_RESOLVE. hanging up\n"); - break; - case S_WAIT_CONNECTION: - DBGPRINT("socks received message while in S_WAIT_CONNECTION. hanging up\n"); - break; - default: - DBGPRINT("socks received message while in an unexpected connection state\n"); - break; + ack.ver = 5; + if (!S5_REQ_HANDHSHAKE_VALID(m, rd)) + { + DBGPRINT("socks5 proxy handshake invalid\n"); + return false; + } + for (k = 0; k < m->nmethods; k++) + if (m->methods[k] == S5_AUTH_NONE) + break; + if (k >= m->nmethods) + { + DBGPRINT("socks5 client wants authentication but we don't support\n"); + ack.method = S5_AUTH_UNACCEPTABLE; + wr = send(conn->fd, &ack, sizeof(ack), MSG_DONTWAIT); + return false; + } + DBGPRINT("socks5 recv valid handshake\n"); + ack.method = S5_AUTH_NONE; + wr = send(conn->fd, &ack, sizeof(ack), MSG_DONTWAIT); + if (wr != sizeof(ack)) + { + DBGPRINT("socks5 handshake ack send error. wr=%zd errno=%d\n", wr, errno); + return false; + } + DBGPRINT("socks5 send handshake ack OK\n"); + conn->socks_state = S_WAIT_REQUEST; + return true; + } + else + { + // SOCKS4 does not have separate handshake phase. it starts with connect request + // v6 and domain resolving are not supported + s4_req *m = (s4_req *)buf; + if (!S4_REQ_HEADER_VALID(m, rd)) + { + DBGPRINT("socks4 request invalid\n"); + return false; + } + if (m->cmd != S4_CMD_CONNECT) + { + // BIND is not supported + DBGPRINT("socks4 unsupported command %02X\n", m->cmd); + socks4_send_rep(conn->fd, S4_REP_FAILED); + return false; + } + if (!S4_REQ_CONNECT_VALID(m, rd)) + { + DBGPRINT("socks4 connect request invalid\n"); + socks4_send_rep(conn->fd, S4_REP_FAILED); + return false; + } + if (!m->port) + { + DBGPRINT("socks4 zero port\n"); + socks4_send_rep(conn->fd, S4_REP_FAILED); + return false; + } + if (m->ip == htonl(1)) // special ip 0.0.0.1 + { + VPRINT("socks4a protocol not supported\n"); + socks4_send_rep(conn->fd, S4_REP_FAILED); + return false; + } + ss.ss_family = AF_INET; + ((struct sockaddr_in *)&ss)->sin_port = m->port; + ((struct sockaddr_in *)&ss)->sin_addr.s_addr = m->ip; + return proxy_mode_connect_remote((struct sockaddr *)&ss, conn, conn_list); } break; + case S_WAIT_REQUEST: + DBGPRINT("S_WAIT_REQUEST\n"); + { + s5_req *m = (s5_req *)buf; + + if (!S5_REQ_HEADER_VALID(m, rd)) + { + DBGPRINT("socks5 request invalid\n"); + return false; + } + if (m->cmd != S5_CMD_CONNECT) + { + // BIND and UDP are not supported + DBGPRINT("socks5 unsupported command %02X\n", m->cmd); + socks5_send_rep(conn->fd, S5_REP_COMMAND_NOT_SUPPORTED); + return false; + } + if (!S5_REQ_CONNECT_VALID(m, rd)) + { + DBGPRINT("socks5 connect request invalid\n"); + return false; + } + DBGPRINT("socks5 recv valid connect request\n"); + switch (m->atyp) + { + case S5_ATYP_IP4: + ss.ss_family = AF_INET; + ((struct sockaddr_in *)&ss)->sin_port = m->d4.port; + ((struct sockaddr_in *)&ss)->sin_addr = m->d4.addr; + break; + case S5_ATYP_IP6: + ss.ss_family = AF_INET6; + ((struct sockaddr_in6 *)&ss)->sin6_port = m->d6.port; + ((struct sockaddr_in6 *)&ss)->sin6_addr = m->d6.addr; + ((struct sockaddr_in6 *)&ss)->sin6_flowinfo = 0; + ((struct sockaddr_in6 *)&ss)->sin6_scope_id = 0; + break; + case S5_ATYP_DOM: + { + uint16_t port; + + if (params.no_resolve) + { + VPRINT("socks5 hostname resolving disabled\n"); + socks5_send_rep(conn->fd, S5_REP_NOT_ALLOWED_BY_RULESET); + return false; + } + port = S5_PORT_FROM_DD(m, rd); + if (!port) + { + VPRINT("socks5 no port is given\n"); + socks5_send_rep(conn->fd, S5_REP_HOST_UNREACHABLE); + return false; + } + m->dd.domport[m->dd.len] = 0; + DBGPRINT("socks5 queue resolve hostname '%s' port '%u'\n", m->dd.domport, port); + conn->socks_ri = resolver_queue(m->dd.domport, port, conn); + if (!conn->socks_ri) + { + VPRINT("socks5 could not queue resolve item\n"); + socks5_send_rep(conn->fd, S5_REP_GENERAL_FAILURE); + return false; + } + conn->socks_state = S_WAIT_RESOLVE; + DBGPRINT("S_WAIT_RESOLVE\n"); + return true; + } + break; + default: + return false; // should not be here. S5_REQ_CONNECT_VALID checks for valid atyp + } + return proxy_mode_connect_remote((struct sockaddr *)&ss, conn, conn_list); + } + break; + case S_WAIT_RESOLVE: + DBGPRINT("SOCKS received message while in S_WAIT_RESOLVE. hanging up\n"); + break; + case S_WAIT_CONNECTION: + DBGPRINT("SOCKS received message while in S_WAIT_CONNECTION. hanging up\n"); + break; + default: + DBGPRINT("SOCKS received message while in an unexpected connection state\n"); + break; + } + break; } return false; } @@ -1030,13 +1041,14 @@ static bool resolve_complete(struct resolve_item *ri, struct tailhead *conn_list if (conn && (conn->state != CONN_CLOSED)) { - if (conn->socks_state==S_WAIT_RESOLVE) + if (conn->socks_state == S_WAIT_RESOLVE) { DBGPRINT("resolve_complete %s. getaddrinfo result %d\n", ri->dom, ri->ga_res); if (ri->ga_res) { - socks5_send_rep(conn->fd,S5_REP_HOST_UNREACHABLE); - return false;; + socks5_send_rep(conn->fd, S5_REP_HOST_UNREACHABLE); + return false; + ; } else { @@ -1045,7 +1057,7 @@ static bool resolve_complete(struct resolve_item *ri, struct tailhead *conn_list DBGPRINT("resolve_complete put hostname : %s\n", ri->dom); conn->track.hostname = strdup(ri->dom); } - return proxy_mode_connect_remote((struct sockaddr *)&ri->ss,conn,conn_list); + return proxy_mode_connect_remote((struct sockaddr *)&ri->ss, conn, conn_list); } } else @@ -1057,34 +1069,34 @@ static bool resolve_complete(struct resolve_item *ri, struct tailhead *conn_list return true; } - static bool in_tamper_out_range(tproxy_conn_t *conn) { - return (params.tamper_start_n ? (conn->tnrd+1) : conn->trd) >= params.tamper_start && - (!params.tamper_cutoff || (params.tamper_cutoff_n ? (conn->tnrd+1) : conn->trd) < params.tamper_cutoff); + return (params.tamper_start_n ? (conn->tnrd + 1) : conn->trd) >= params.tamper_start && + (!params.tamper_cutoff || (params.tamper_cutoff_n ? (conn->tnrd + 1) : conn->trd) < params.tamper_cutoff); } static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_size, size_t *segment_size, size_t *split_pos, uint8_t *split_flags) { - *split_pos=0; + *split_pos = 0; if (params.tamper) { if (conn->remote) { if (conn_partner_alive(conn) && !conn->partner->track.bTamperInCutoff) { - tamper_in(&conn->partner->track,segment,segment_buffer_size,segment_size); + tamper_in(&conn->partner->track, segment, segment_buffer_size, segment_size); } } else { bool in_range = in_tamper_out_range(conn); DBGPRINT("tamper_out stream pos %" PRIu64 "(n%" PRIu64 "). tamper range %s%u-%s%u (%s)\n", - conn->trd, conn->tnrd+1, - params.tamper_start_n ? "n" : "" , params.tamper_start, - params.tamper_cutoff_n ? "n" : "" , params.tamper_cutoff, - in_range ? "IN RANGE" : "OUT OF RANGE"); - if (in_range) tamper_out(&conn->track,segment,segment_buffer_size,segment_size,split_pos,split_flags); + conn->trd, conn->tnrd + 1, + params.tamper_start_n ? "n" : "", params.tamper_start, + params.tamper_cutoff_n ? "n" : "", params.tamper_cutoff, + in_range ? "IN RANGE" : "OUT OF RANGE"); + if (in_range) + tamper_out(&conn->track, segment, segment_buffer_size, segment_size, split_pos, split_flags); } } } @@ -1099,7 +1111,7 @@ static ssize_t send_or_buffer_oob(send_buffer_t *sb, int fd, uint8_t *buf, size_ uint8_t oob_save; oob_save = buf[len]; buf[len] = params.oob_byte; - wr = send_or_buffer(sb, fd, buf, len+1, MSG_OOB, ttl); + wr = send_or_buffer(sb, fd, buf, len + 1, MSG_OOB, ttl); buf[len] = oob_save; } else @@ -1107,23 +1119,21 @@ static ssize_t send_or_buffer_oob(send_buffer_t *sb, int fd, uint8_t *buf, size_ return wr; } - #define RD_BLOCK_SIZE 65536 -#define MAX_WASTE (1024*1024) +#define MAX_WASTE (1024 * 1024) static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32_t evt) { int numbytes; ssize_t rd = 0, wr = 0; size_t bs; - DBGPRINT("+handle_epoll\n"); if (!conn_in_tcp_mode(conn)) { if (!(evt & EPOLLIN)) return true; // nothing to read - return handle_proxy_mode(conn,conn_list); + return handle_proxy_mode(conn, conn_list); } if (!handle_unsent(conn)) @@ -1138,28 +1148,28 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32 { // throw it to a black hole uint8_t waste[65070]; - uint64_t trd=0; + uint64_t trd = 0; - while((rd=recv(conn->fd, waste, sizeof(waste), MSG_DONTWAIT))>0 && trdfd, waste, sizeof(waste), MSG_DONTWAIT)) > 0 && trd < MAX_WASTE) { - trd+=rd; - conn->trd+=rd; + trd += rd; + conn->trd += rd; } - DBGPRINT("wasted recv=%zd all_rd=%" PRIu64 " err=%d\n",rd,trd,errno); + DBGPRINT("wasted recv=%zd all_rd=%" PRIu64 " err=%d\n", rd, trd, errno); return true; } // do not receive new until old is sent if (conn_has_unsent(conn->partner)) return true; - - bool oom=false; - numbytes=conn_bytes_unread(conn); - DBGPRINT("numbytes=%d\n",numbytes); - if (numbytes>0) + bool oom = false; + + numbytes = conn_bytes_unread(conn); + DBGPRINT("numbytes=%d\n", numbytes); + if (numbytes > 0) { - DBGPRINT("%s leg fd=%d stream pos : %" PRIu64 "(n%" PRIu64 ")/%" PRIu64 "\n", conn->remote ? "remote" : "local", conn->fd, conn->trd,conn->tnrd+1,conn->twr); + DBGPRINT("%s leg fd=%d stream pos : %" PRIu64 "(n%" PRIu64 ")/%" PRIu64 "\n", conn->remote ? "remote" : "local", conn->fd, conn->trd, conn->tnrd + 1, conn->twr); #ifdef SPLICE_PRESENT if (!params.nosplice && (!params.tamper || (conn->remote && conn->partner->track.bTamperInCutoff) || (!conn->remote && !in_tamper_out_range(conn)))) { @@ -1168,17 +1178,19 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32 // if we dont tamper - splice both legs rd = splice(conn->fd, NULL, conn->partner->splice_pipe[1], NULL, SPLICE_LEN, SPLICE_F_MOVE | SPLICE_F_NONBLOCK); - DBGPRINT("splice fd=%d remote=%d len=%d rd=%zd err=%d\n",conn->fd,conn->remote,SPLICE_LEN,rd,errno); - if (rd<0 && errno==EAGAIN) rd=0; - if (rd>0) + DBGPRINT("splice fd=%d remote=%d len=%d rd=%zd err=%d\n", conn->fd, conn->remote, SPLICE_LEN, rd, errno); + if (rd < 0 && errno == EAGAIN) + rd = 0; + if (rd > 0) { conn->tnrd++; conn->trd += rd; conn->partner->wr_unsent += rd; wr = splice(conn->partner->splice_pipe[0], NULL, conn->partner->fd, NULL, conn->partner->wr_unsent, SPLICE_F_MOVE | SPLICE_F_NONBLOCK); - DBGPRINT("splice fd=%d remote=%d wr=%zd err=%d\n",conn->partner->fd,conn->partner->remote,wr,errno); - if (wr<0 && errno==EAGAIN) wr=0; - if (wr>0) + DBGPRINT("splice fd=%d remote=%d wr=%zd err=%d\n", conn->partner->fd, conn->partner->remote, wr, errno); + if (wr < 0 && errno == EAGAIN) + wr = 0; + if (wr > 0) { conn->partner->wr_unsent -= wr; conn->partner->twr += wr; @@ -1192,9 +1204,10 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32 uint8_t buf[RD_BLOCK_SIZE + 5]; rd = recv(conn->fd, buf, RD_BLOCK_SIZE, MSG_DONTWAIT); - DBGPRINT("recv fd=%d rd=%zd err=%d\n",conn->fd, rd,errno); - if (rd<0 && errno==EAGAIN) rd=0; - if (rd>0) + DBGPRINT("recv fd=%d rd=%zd err=%d\n", conn->fd, rd, errno); + if (rd < 0 && errno == EAGAIN) + rd = 0; + if (rd > 0) { size_t split_pos; uint8_t split_flags; @@ -1205,42 +1218,46 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32 tamper(conn, buf, sizeof(buf), &bs, &split_pos, &split_flags); // increase after tamper conn->tnrd++; - conn->trd+=rd; + conn->trd += rd; - if (split_pos && bspartner->wr_buf, conn->partner->fd, buf, split_pos, !!(split_flags & SPLIT_FLAG_DISORDER), !!(split_flags & SPLIT_FLAG_OOB)); - DBGPRINT("send_or_buffer(1) fd=%d wr=%zd err=%d\n",conn->partner->fd,wr,errno); + DBGPRINT("send_or_buffer(1) fd=%d wr=%zd err=%d\n", conn->partner->fd, wr, errno); if (wr >= 0) { conn->partner->twr += wr; wr = send_or_buffer(conn->partner->wr_buf + 1, conn->partner->fd, buf + split_pos, bs - split_pos, 0, 0); - DBGPRINT("send_or_buffer(2) fd=%d wr=%zd err=%d\n",conn->partner->fd,wr,errno); - if (wr>0) conn->partner->twr += wr; + DBGPRINT("send_or_buffer(2) fd=%d wr=%zd err=%d\n", conn->partner->fd, wr, errno); + if (wr > 0) + conn->partner->twr += wr; } } else { wr = send_or_buffer(conn->partner->wr_buf, conn->partner->fd, buf, bs, 0, 0); - DBGPRINT("send_or_buffer(3) fd=%d wr=%zd err=%d\n",conn->partner->fd,wr,errno); - if (wr>0) conn->partner->twr += wr; + DBGPRINT("send_or_buffer(3) fd=%d wr=%zd err=%d\n", conn->partner->fd, wr, errno); + if (wr > 0) + conn->partner->twr += wr; } - if (wr<0 && errno==ENOMEM) oom=true; + if (wr < 0 && errno == ENOMEM) + oom = true; } } if (!epoll_set_flow_pair(conn)) return false; } - - DBGPRINT("-handle_epoll rd=%zd wr=%zd\n",rd,wr); - if (oom) DBGPRINT("handle_epoll: OUT_OF_MEMORY\n"); + + DBGPRINT("-handle_epoll rd=%zd wr=%zd\n", rd, wr); + if (oom) + DBGPRINT("handle_epoll: OUT_OF_MEMORY\n"); // do not fail if partner fails. // if partner fails there will be another epoll event with EPOLLHUP or EPOLLERR - return rd>=0 && !oom; + return rd >= 0 && !oom; } static bool remove_closed_connections(int efd, struct tailhead *close_list) @@ -1254,8 +1271,11 @@ static bool remove_closed_connections(int efd, struct tailhead *close_list) epoll_del(conn); VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) closed, connection removed. total_read=%" PRIu64 " total_write=%" PRIu64 " event_count=%u\n", - conn->fd, conn->partner ? conn->partner->fd : 0, conn->remote, conn->trd, conn->twr, conn->event_count); - if (conn->remote) legs_remote--; else legs_local--; + conn->fd, conn->partner ? conn->partner->fd : 0, conn->remote, conn->trd, conn->twr, conn->event_count); + if (conn->remote) + legs_remote--; + else + legs_local--; free_conn(conn); bRemoved = true; } @@ -1273,21 +1293,20 @@ static void close_tcp_conn(struct tailhead *conn_list, struct tailhead *close_li } } - static bool read_all_and_buffer(tproxy_conn_t *conn, int buffer_number) { if (conn_partner_alive(conn)) { - int numbytes=conn_bytes_unread(conn); - DBGPRINT("read_all_and_buffer(%d) numbytes=%d\n",buffer_number,numbytes); - if (numbytes>0) + int numbytes = conn_bytes_unread(conn); + DBGPRINT("read_all_and_buffer(%d) numbytes=%d\n", buffer_number, numbytes); + if (numbytes > 0) { - if (send_buffer_create(conn->partner->wr_buf+buffer_number, NULL, numbytes, 5, 0, 0)) + if (send_buffer_create(conn->partner->wr_buf + buffer_number, NULL, numbytes, 5, 0, 0)) { ssize_t rd = recv(conn->fd, conn->partner->wr_buf[buffer_number].data, numbytes, MSG_DONTWAIT); - if (rd>0) + if (rd > 0) { - conn->trd+=rd; + conn->trd += rd; conn->partner->wr_buf[buffer_number].len = rd; conn->partner->bFlowOut = true; @@ -1295,44 +1314,42 @@ static bool read_all_and_buffer(tproxy_conn_t *conn, int buffer_number) size_t split_pos; uint8_t split_flags; - tamper(conn, conn->partner->wr_buf[buffer_number].data, numbytes+5, &conn->partner->wr_buf[buffer_number].len, &split_pos, &split_flags); + tamper(conn, conn->partner->wr_buf[buffer_number].data, numbytes + 5, &conn->partner->wr_buf[buffer_number].len, &split_pos, &split_flags); if (epoll_update_flow(conn->partner)) return true; - } - send_buffer_free(conn->partner->wr_buf+buffer_number); + send_buffer_free(conn->partner->wr_buf + buffer_number); } } } return false; } - static bool conn_timed_out(tproxy_conn_t *conn) { - if (conn->orphan_since && conn->state==CONN_UNAVAILABLE) + if (conn->orphan_since && conn->state == CONN_UNAVAILABLE) { time_t timediff = time(NULL) - conn->orphan_since; - return timediff>=params.max_orphan_time; + return timediff >= params.max_orphan_time; } else return false; } static void conn_close_timed_out(struct tailhead *conn_list, struct tailhead *close_list) { - tproxy_conn_t *c,*cnext = NULL; + tproxy_conn_t *c, *cnext = NULL; DBGPRINT("conn_close_timed_out\n"); c = TAILQ_FIRST(conn_list); - while(c) + while (c) { - cnext = TAILQ_NEXT(c,conn_ptrs); + cnext = TAILQ_NEXT(c, conn_ptrs); if (conn_timed_out(c)) { - DBGPRINT("closing timed out connection: fd=%d remote=%d\n",c->fd,c->remote); - close_tcp_conn(conn_list,close_list,c); + DBGPRINT("closing timed out connection: fd=%d remote=%d\n", c->fd, c->remote); + close_tcp_conn(conn_list, close_list, c); } c = cnext; } @@ -1340,44 +1357,45 @@ static void conn_close_timed_out(struct tailhead *conn_list, struct tailhead *cl static void conn_close_both(struct tailhead *conn_list, struct tailhead *close_list, tproxy_conn_t *conn) { - if (conn_partner_alive(conn)) close_tcp_conn(conn_list,close_list,conn->partner); - close_tcp_conn(conn_list,close_list,conn); + if (conn_partner_alive(conn)) + close_tcp_conn(conn_list, close_list, conn->partner); + close_tcp_conn(conn_list, close_list, conn); } static void conn_close_with_partner_check(struct tailhead *conn_list, struct tailhead *close_list, tproxy_conn_t *conn) { - close_tcp_conn(conn_list,close_list,conn); + close_tcp_conn(conn_list, close_list, conn); if (conn_partner_alive(conn)) - { + { if (!conn_has_unsent(conn->partner)) - close_tcp_conn(conn_list,close_list,conn->partner); - else if (conn->partner->remote && conn->partner->state==CONN_UNAVAILABLE && params.max_orphan_time) + close_tcp_conn(conn_list, close_list, conn->partner); + else if (conn->partner->remote && conn->partner->state == CONN_UNAVAILABLE && params.max_orphan_time) // time out only remote legs that are not connected yet conn->partner->orphan_since = time(NULL); } } - static bool handle_resolve_pipe(tproxy_conn_t **conn, struct tailhead *conn_list, int fd) { ssize_t rd; struct resolve_item *ri; bool b; - rd = read(fd,&ri,sizeof(void*)); - if (rd<0) + rd = read(fd, &ri, sizeof(void *)); + if (rd < 0) { DLOG_PERROR("resolve_pipe read"); return false; } - else if (rd!=sizeof(void*)) + else if (rd != sizeof(void *)) { // partial pointer read is FATAL. in any case it will cause pointer corruption and coredump - DLOG_ERR("resolve_pipe not full read %zu\n",rd); + DLOG_ERR("resolve_pipe not full read %zu\n", rd); exit(1000); } b = resolve_complete(ri, conn_list); *conn = (tproxy_conn_t *)ri->ptr; - if (*conn) (*conn)->socks_ri = NULL; + if (*conn) + (*conn)->socks_ri = NULL; free(ri); return b; } @@ -1385,55 +1403,58 @@ static bool handle_resolve_pipe(tproxy_conn_t **conn, struct tailhead *conn_list int event_loop(const int *listen_fd, size_t listen_fd_ct) { int retval = 0, num_events = 0; - int tmp_fd = 0; //Used to temporarily hold the accepted file descriptor + int tmp_fd = 0; // Used to temporarily hold the accepted file descriptor tproxy_conn_t *conn = NULL; - int efd=0, i; + int efd = 0, i; struct epoll_event ev, events[MAX_EPOLL_EVENTS]; struct tailhead conn_list, close_list; - time_t tm,last_timeout_check=0; + time_t tm, last_timeout_check = 0; tproxy_conn_t *listen_conn = NULL; size_t sct; struct sockaddr_storage accept_sa; socklen_t accept_salen; int resolve_pipe[2]; - if (!listen_fd_ct) return -1; - - resolve_pipe[0]=resolve_pipe[1]=0; + if (!listen_fd_ct) + return -1; + + resolve_pipe[0] = resolve_pipe[1] = 0; legs_local = legs_remote = 0; - //Initialize queue (remember that TAILQ_HEAD just defines the struct) + // Initialize queue (remember that TAILQ_HEAD just defines the struct) TAILQ_INIT(&conn_list); TAILQ_INIT(&close_list); - if ((efd = epoll_create(1)) == -1) { + if ((efd = epoll_create(1)) == -1) + { DLOG_PERROR("epoll_create"); return -1; } - if (!(listen_conn=calloc(listen_fd_ct,sizeof(*listen_conn)))) + if (!(listen_conn = calloc(listen_fd_ct, sizeof(*listen_conn)))) { DLOG_PERROR("calloc listen_conn"); return -1; } - - //Start monitoring listen sockets + + // Start monitoring listen sockets memset(&ev, 0, sizeof(ev)); ev.events = EPOLLIN; - for(sct=0;sctevent_count++; if (conn->listener) { - DBGPRINT("\nEVENT mask %08X fd=%d accept\n",events[i].events,conn->fd); + DBGPRINT("\nEVENT mask %08X fd=%d accept\n", events[i].events, conn->fd); accept_salen = sizeof(accept_sa); - //Accept new connection -#if defined (__APPLE__) - // macos does not have accept4() - tmp_fd = accept(conn->fd, (struct sockaddr*)&accept_sa, &accept_salen); + // Accept new connection +#if defined(__APPLE__) + // macOS does not have accept4() + tmp_fd = accept(conn->fd, (struct sockaddr *)&accept_sa, &accept_salen); #else - tmp_fd = accept4(conn->fd, (struct sockaddr*)&accept_sa, &accept_salen, SOCK_NONBLOCK); + tmp_fd = accept4(conn->fd, (struct sockaddr *)&accept_sa, &accept_salen, SOCK_NONBLOCK); #endif if (tmp_fd < 0) { @@ -1513,33 +1537,33 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) close(tmp_fd); VPRINT("Too many local legs : %d\n", legs_local); } -#if defined (__APPLE__) - // separate fcntl call to comply with macos +#if defined(__APPLE__) + // separate fcntl call to comply with macOS else if (fcntl(tmp_fd, F_SETFL, O_NONBLOCK) < 0) { DLOG_PERROR("socket set O_NONBLOCK (accept)"); close(tmp_fd); } #endif - else if (!(conn=add_tcp_connection(efd, &conn_list, tmp_fd, (struct sockaddr*)&accept_sa, params.port, params.proxy_type))) + else if (!(conn = add_tcp_connection(efd, &conn_list, tmp_fd, (struct sockaddr *)&accept_sa, params.port, params.proxy_type))) { // add_tcp_connection closes fd in case of failure VPRINT("Failed to add connection\n"); } else - { + { print_legs(); - - if (params.debug>=1) + + if (params.debug >= 1) { struct sockaddr_storage sa; - socklen_t salen=sizeof(sa); + socklen_t salen = sizeof(sa); char ip_port[48]; - if (getpeername(conn->fd,(struct sockaddr *)&sa,&salen)) - *ip_port=0; + if (getpeername(conn->fd, (struct sockaddr *)&sa, &salen)) + *ip_port = 0; else - ntop46_port((struct sockaddr*)&sa,ip_port,sizeof(ip_port)); + ntop46_port((struct sockaddr *)&sa, ip_port, sizeof(ip_port)); VPRINT("Socket fd=%d (local) connected from %s\n", conn->fd, ip_port); } @@ -1548,36 +1572,44 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) } else { - DBGPRINT("\nEVENT mask %08X fd=%d remote=%d fd_partner=%d\n",events[i].events,conn->fd,conn->remote,conn_partner_alive(conn) ? conn->partner->fd : 0); + DBGPRINT("\nEVENT mask %08X fd=%d remote=%d fd_partner=%d\n", events[i].events, conn->fd, conn->remote, conn_partner_alive(conn) ? conn->partner->fd : 0); if (conn->state != CONN_CLOSED) { - if (events[i].events & (EPOLLHUP|EPOLLERR)) + if (events[i].events & (EPOLLHUP | EPOLLERR)) { int errn = get_so_error(conn->fd); const char *se; - switch (events[i].events & (EPOLLHUP|EPOLLERR)) + switch (events[i].events & (EPOLLHUP | EPOLLERR)) { - case EPOLLERR: se="EPOLLERR"; break; - case EPOLLHUP: se="EPOLLHUP"; break; - case EPOLLHUP|EPOLLERR: se="EPOLLERR EPOLLHUP"; break; - default: se=NULL; + case EPOLLERR: + se = "EPOLLERR"; + break; + case EPOLLHUP: + se = "EPOLLHUP"; + break; + case EPOLLHUP | EPOLLERR: + se = "EPOLLERR EPOLLHUP"; + break; + default: + se = NULL; } - VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) %s so_error=%d (%s)\n",conn->fd,conn->partner ? conn->partner->fd : 0,conn->remote,se,errn,strerror(errn)); - proxy_remote_conn_ack(conn,errn); - read_all_and_buffer(conn,3); - if (errn==ECONNRESET && conn_partner_alive(conn)) + VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) %s so_error=%d (%s)\n", conn->fd, conn->partner ? conn->partner->fd : 0, conn->remote, se, errn, strerror(errn)); + proxy_remote_conn_ack(conn, errn); + read_all_and_buffer(conn, 3); + if (errn == ECONNRESET && conn_partner_alive(conn)) { - if (conn->remote && params.tamper) rst_in(&conn->partner->track); + if (conn->remote && params.tamper) + rst_in(&conn->partner->track); struct linger lin; - lin.l_onoff=1; - lin.l_linger=0; + lin.l_onoff = 1; + lin.l_linger = 0; DBGPRINT("setting LINGER=0 to partner to force mirrored RST close\n"); - if (setsockopt(conn->partner->fd,SOL_SOCKET,SO_LINGER,&lin,sizeof(lin))<0) + if (setsockopt(conn->partner->fd, SOL_SOCKET, SO_LINGER, &lin, sizeof(lin)) < 0) DLOG_PERROR("setsockopt (SO_LINGER)"); } - conn_close_with_partner_check(&conn_list,&close_list,conn); + conn_close_with_partner_check(&conn_list, &close_list, conn); continue; } if (events[i].events & EPOLLOUT) @@ -1585,21 +1617,22 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) if (!check_connection_attempt(conn, efd)) { VPRINT("Connection attempt failed for fd=%d\n", conn->fd); - conn_close_both(&conn_list,&close_list,conn); + conn_close_both(&conn_list, &close_list, conn); continue; } } if (events[i].events & EPOLLRDHUP) { DBGPRINT("EPOLLRDHUP\n"); - read_all_and_buffer(conn,2); - if (!conn->remote && params.tamper) hup_out(&conn->track); + read_all_and_buffer(conn, 2); + if (!conn->remote && params.tamper) + hup_out(&conn->track); conn->state = CONN_RDHUP; // only writes. do not receive RDHUP anymore if (conn_has_unsent(conn)) { DBGPRINT("conn fd=%d has unsent\n", conn->fd); - epoll_set_flow(conn,false,true); + epoll_set_flow(conn, false, true); } else { @@ -1617,40 +1650,48 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) if (!conn_shutdown(conn->partner)) { DBGPRINT("emergency connection close due to failed shutdown\n"); - conn_close_with_partner_check(&conn_list,&close_list,conn); + conn_close_with_partner_check(&conn_list, &close_list, conn); } - if (conn->partner->state==CONN_RDHUP) + if (conn->partner->state == CONN_RDHUP) { DBGPRINT("both partners are in RDHUP state and have no unsent. closing.\n"); - conn_close_with_partner_check(&conn_list,&close_list,conn); + conn_close_with_partner_check(&conn_list, &close_list, conn); } } } else { DBGPRINT("partner is absent or not alive. closing.\n"); - close_tcp_conn(&conn_list,&close_list,conn); + close_tcp_conn(&conn_list, &close_list, conn); } } continue; } - if (events[i].events & (EPOLLIN|EPOLLOUT)) + if (events[i].events & (EPOLLIN | EPOLLOUT)) { const char *se; - switch (events[i].events & (EPOLLIN|EPOLLOUT)) + switch (events[i].events & (EPOLLIN | EPOLLOUT)) { - case EPOLLIN: se="EPOLLIN"; break; - case EPOLLOUT: se="EPOLLOUT"; break; - case EPOLLIN|EPOLLOUT: se="EPOLLIN EPOLLOUT"; break; - default: se=NULL; + case EPOLLIN: + se = "EPOLLIN"; + break; + case EPOLLOUT: + se = "EPOLLOUT"; + break; + case EPOLLIN | EPOLLOUT: + se = "EPOLLIN EPOLLOUT"; + break; + default: + se = NULL; } - if (se) DBGPRINT("%s\n",se); + if (se) + DBGPRINT("%s\n", se); // will not receive this until successful check_connection_attempt() if (!handle_epoll(conn, &conn_list, events[i].events)) { DBGPRINT("handle_epoll false\n"); - conn_close_with_partner_check(&conn_list,&close_list,conn); + conn_close_with_partner_check(&conn_list, &close_list, conn); continue; } if ((conn->state == CONN_RDHUP) && conn_partner_alive(conn) && !conn->partner->bShutdown && !conn_has_unsent(conn)) @@ -1659,22 +1700,20 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) if (!conn_shutdown(conn->partner)) { DBGPRINT("emergency connection close due to failed shutdown\n"); - conn_close_with_partner_check(&conn_list,&close_list,conn); + conn_close_with_partner_check(&conn_list, &close_list, conn); continue; } } - } } - } } tm = time(NULL); - if (last_timeout_check!=tm) + if (last_timeout_check != tm) { // limit whole list lookups to once per second - last_timeout_check=tm; - conn_close_timed_out(&conn_list,&close_list); + last_timeout_check = tm; + conn_close_timed_out(&conn_list, &close_list); } if (remove_closed_connections(efd, &close_list)) { @@ -1682,14 +1721,19 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) print_legs(); } - fflush(stderr); fflush(stdout); // for console messages + fflush(stderr); + fflush(stdout); // for console messages } ex: - if (efd) close(efd); - if (listen_conn) free(listen_conn); + if (efd) + close(efd); + if (listen_conn) + free(listen_conn); resolver_deinit(); - if (resolve_pipe[0]) close(resolve_pipe[0]); - if (resolve_pipe[1]) close(resolve_pipe[1]); + if (resolve_pipe[0]) + close(resolve_pipe[0]); + if (resolve_pipe[1]) + close(resolve_pipe[1]); return retval; } diff --git a/tpws/tpws_conn.h b/tpws/tpws_conn.h index 31abbd2..89e9555 100644 --- a/tpws/tpws_conn.h +++ b/tpws/tpws_conn.h @@ -10,21 +10,22 @@ #define BACKLOG 10 #define MAX_EPOLL_EVENTS 64 -#define IP_TRANSPARENT 19 //So that application compiles on OpenWRT +#define IP_TRANSPARENT 19 // So that application compiles on OpenWrt #define SPLICE_LEN 65536 -#define DEFAULT_MAX_CONN 512 -#define DEFAULT_MAX_ORPHAN_TIME 5 -#define DEFAULT_TCP_USER_TIMEOUT_LOCAL 10 -#define DEFAULT_TCP_USER_TIMEOUT_REMOTE 20 +#define DEFAULT_MAX_CONN 512 +#define DEFAULT_MAX_ORPHAN_TIME 5 +#define DEFAULT_TCP_USER_TIMEOUT_LOCAL 10 +#define DEFAULT_TCP_USER_TIMEOUT_REMOTE 20 int event_loop(const int *listen_fd, size_t listen_fd_ct); -//Three different states of a connection -enum{ - CONN_UNAVAILABLE=0, // connecting - CONN_AVAILABLE, // operational - CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked - CONN_CLOSED // will be deleted soon +// Three different states of a connection +enum +{ + CONN_UNAVAILABLE = 0, // connecting + CONN_AVAILABLE, // operational + CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked + CONN_CLOSED // will be deleted soon }; typedef uint8_t conn_state_t; @@ -34,13 +35,14 @@ typedef uint8_t conn_state_t; struct send_buffer { uint8_t *data; - size_t len,pos; + size_t len, pos; int ttl, flags; }; typedef struct send_buffer send_buffer_t; -enum{ - CONN_TYPE_TRANSPARENT=0, +enum +{ + CONN_TYPE_TRANSPARENT = 0, CONN_TYPE_SOCKS }; typedef uint8_t conn_type_t; @@ -48,8 +50,8 @@ typedef uint8_t conn_type_t; struct tproxy_conn { bool listener; // true - listening socket. false = connecion socket - bool remote; // false - accepted, true - connected - int efd; // epoll fd + bool remote; // false - accepted, true - connected + int efd; // epoll fd int fd; int splice_pipe[2]; conn_state_t state; @@ -59,8 +61,9 @@ struct tproxy_conn time_t orphan_since; // socks5 state machine - enum { - S_WAIT_HANDSHAKE=0, + enum + { + S_WAIT_HANDSHAKE = 0, S_WAIT_REQUEST, S_WAIT_RESOLVE, S_WAIT_CONNECTION, @@ -70,11 +73,11 @@ struct tproxy_conn struct resolve_item *socks_ri; // these value are used in flow control. we do not use ET (edge triggered) polling - // if we dont disable notifications they will come endlessly until condition becomes false and will eat all cpu time - bool bFlowIn,bFlowOut, bShutdown, bFlowInPrev,bFlowOutPrev, bPrevRdhup; + // if we don't disable notifications they will come endlessly until condition becomes false and will eat all cpu time + bool bFlowIn, bFlowOut, bShutdown, bFlowInPrev, bFlowOutPrev, bPrevRdhup; // total read,write - uint64_t trd,twr, tnrd; + uint64_t trd, twr, tnrd; // number of epoll_wait events unsigned int event_count; @@ -94,14 +97,14 @@ struct tproxy_conn t_ctrack track; - //Create the struct which contains ptrs to next/prev element - TAILQ_ENTRY(tproxy_conn) conn_ptrs; + // Create the struct which contains ptrs to next/prev element + TAILQ_ENTRY(tproxy_conn) + conn_ptrs; }; typedef struct tproxy_conn tproxy_conn_t; -//Define the struct tailhead (code in sys/queue.h is quite intuitive) -//Use tail queue for efficient delete +// Define the struct tailhead (code in sys/queue.h is quite intuitive) +// Use tail queue for efficient delete TAILQ_HEAD(tailhead, tproxy_conn); - bool set_socket_buffers(int fd, int rcvbuf, int sndbuf); diff --git a/tpws/uthash.h b/tpws/uthash.h index 9a396b6..c669e13 100644 --- a/tpws/uthash.h +++ b/tpws/uthash.h @@ -26,9 +26,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define UTHASH_VERSION 2.3.0 -#include /* memcmp, memset, strlen */ -#include /* ptrdiff_t */ -#include /* exit */ +#include /* memcmp, memset, strlen */ +#include /* ptrdiff_t */ +#include /* exit */ #if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT /* This codepath is provided for backward compatibility, but I plan to remove it. */ @@ -37,7 +37,7 @@ typedef unsigned int uint32_t; typedef unsigned char uint8_t; #elif defined(HASH_NO_STDINT) && HASH_NO_STDINT #else -#include /* uint8_t, uint32_t */ +#include /* uint8_t, uint32_t */ #endif /* These macros use decltype or the earlier __typeof GNU extension. @@ -45,59 +45,61 @@ typedef unsigned char uint8_t; when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #if !defined(DECLTYPE) && !defined(NO_DECLTYPE) -#if defined(_MSC_VER) /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) -#else /* VS2008 or older (or VS2010 in C mode) */ +#else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #endif #elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE -#else /* GNU, Sun and other compilers */ +#else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #endif #ifdef NO_DECLTYPE #define DECLTYPE(x) -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - char **_da_dst = (char**)(&(dst)); \ - *_da_dst = (char*)(src); \ -} while (0) +#define DECLTYPE_ASSIGN(dst, src) \ + do \ + { \ + char **_da_dst = (char **)(&(dst)); \ + *_da_dst = (char *)(src); \ + } while (0) #else -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - (dst) = DECLTYPE(dst)(src); \ -} while (0) +#define DECLTYPE_ASSIGN(dst, src) \ + do \ + { \ + (dst) = DECLTYPE(dst)(src); \ + } while (0) #endif #ifndef uthash_malloc -#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #endif #ifndef uthash_free -#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#define uthash_free(ptr, sz) free(ptr) /* free fcn */ #endif #ifndef uthash_bzero -#define uthash_bzero(a,n) memset(a,'\0',n) +#define uthash_bzero(a, n) memset(a, '\0', n) #endif #ifndef uthash_strlen #define uthash_strlen(s) strlen(s) #endif #ifndef HASH_FUNCTION -#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv) +#define HASH_FUNCTION(keyptr, keylen, hashv) HASH_JEN(keyptr, keylen, hashv) #endif #ifndef HASH_KEYCMP -#define HASH_KEYCMP(a,b,n) memcmp(a,b,n) +#define HASH_KEYCMP(a, b, n) memcmp(a, b, n) #endif #ifndef uthash_noexpand_fyi -#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #endif #ifndef uthash_expand_fyi -#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ #endif #ifndef HASH_NONFATAL_OOM @@ -108,17 +110,24 @@ do { /* malloc failures can be recovered from */ #ifndef uthash_nonfatal_oom -#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ +#define uthash_nonfatal_oom(obj) \ + do \ + { \ + } while (0) /* non-fatal OOM error */ #endif -#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) +#define HASH_RECORD_OOM(oomed) \ + do \ + { \ + (oomed) = 1; \ + } while (0) #define IF_HASH_NONFATAL_OOM(x) x #else /* malloc failures result in lost memory, hash tables are unusable */ #ifndef uthash_fatal -#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ +#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ #endif #define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") @@ -132,306 +141,361 @@ do { #define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhp */ -#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +#define ELMT_FROM_HH(tbl, hhp) ((void *)(((char *)(hhp)) - ((tbl)->hho))) /* calculate the hash handle from element address elp */ -#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho))) +#define HH_FROM_ELMT(tbl, elp) ((UT_hash_handle *)(void *)(((char *)(elp)) + ((tbl)->hho))) -#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ -do { \ - struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ - unsigned _hd_bkt; \ - HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - (head)->hh.tbl->buckets[_hd_bkt].count++; \ - _hd_hh_item->hh_next = NULL; \ - _hd_hh_item->hh_prev = NULL; \ -} while (0) +#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ + do \ + { \ + struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ + unsigned _hd_bkt; \ + HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + (head)->hh.tbl->buckets[_hd_bkt].count++; \ + _hd_hh_item->hh_next = NULL; \ + _hd_hh_item->hh_prev = NULL; \ + } while (0) -#define HASH_VALUE(keyptr,keylen,hashv) \ -do { \ - HASH_FUNCTION(keyptr, keylen, hashv); \ -} while (0) +#define HASH_VALUE(keyptr, keylen, hashv) \ + do \ + { \ + HASH_FUNCTION(keyptr, keylen, hashv); \ + } while (0) -#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ -do { \ - (out) = NULL; \ - if (head) { \ - unsigned _hf_bkt; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ - if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ - HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ - } \ - } \ -} while (0) +#define HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, hashval, out) \ + do \ + { \ + (out) = NULL; \ + if (head) \ + { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) \ + { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[_hf_bkt], keyptr, keylen, hashval, out); \ + } \ + } \ + } while (0) -#define HASH_FIND(hh,head,keyptr,keylen,out) \ -do { \ - (out) = NULL; \ - if (head) { \ - unsigned _hf_hashv; \ - HASH_VALUE(keyptr, keylen, _hf_hashv); \ - HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ - } \ -} while (0) +#define HASH_FIND(hh, head, keyptr, keylen, out) \ + do \ + { \ + (out) = NULL; \ + if (head) \ + { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ + } \ + } while (0) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) -#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) -#define HASH_BLOOM_MAKE(tbl,oomed) \ -do { \ - (tbl)->bloom_nbits = HASH_BLOOM; \ - (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ - if (!(tbl)->bloom_bv) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ - (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ - } \ -} while (0) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN / 8UL) + (((HASH_BLOOM_BITLEN % 8UL) != 0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl, oomed) \ + do \ + { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t *)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) \ + { \ + HASH_RECORD_OOM(oomed); \ + } \ + else \ + { \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ + } \ + } while (0) -#define HASH_BLOOM_FREE(tbl) \ -do { \ - uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ -} while (0) +#define HASH_BLOOM_FREE(tbl) \ + do \ + { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + } while (0) -#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) -#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) +#define HASH_BLOOM_BITSET(bv, idx) (bv[(idx) / 8U] |= (1U << ((idx) % 8U))) +#define HASH_BLOOM_BITTEST(bv, idx) (bv[(idx) / 8U] & (1U << ((idx) % 8U))) -#define HASH_BLOOM_ADD(tbl,hashv) \ +#define HASH_BLOOM_ADD(tbl, hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) -#define HASH_BLOOM_TEST(tbl,hashv) \ +#define HASH_BLOOM_TEST(tbl, hashv) \ HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) #else -#define HASH_BLOOM_MAKE(tbl,oomed) +#define HASH_BLOOM_MAKE(tbl, oomed) #define HASH_BLOOM_FREE(tbl) -#define HASH_BLOOM_ADD(tbl,hashv) -#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_ADD(tbl, hashv) +#define HASH_BLOOM_TEST(tbl, hashv) (1) #define HASH_BLOOM_BYTELEN 0U #endif -#define HASH_MAKE_TABLE(hh,head,oomed) \ -do { \ - (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ - if (!(head)->hh.tbl) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head)->hh.tbl->tail = &((head)->hh); \ - (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ - (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ - (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ - (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ - HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ - (head)->hh.tbl->signature = HASH_SIGNATURE; \ - if (!(head)->hh.tbl->buckets) { \ - HASH_RECORD_OOM(oomed); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - } else { \ - uthash_bzero((head)->hh.tbl->buckets, \ - HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ - HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (oomed) { \ - uthash_free((head)->hh.tbl->buckets, \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - } \ - ) \ - } \ - } \ -} while (0) +#define HASH_MAKE_TABLE(hh, head, oomed) \ + do \ + { \ + (head)->hh.tbl = (UT_hash_table *)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) \ + { \ + HASH_RECORD_OOM(oomed); \ + } \ + else \ + { \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char *)(&(head)->hh) - (char *)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket *)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ + if (!(head)->hh.tbl->buckets) \ + { \ + HASH_RECORD_OOM(oomed); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } \ + else \ + { \ + uthash_bzero((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + uthash_free((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + }) \ + } \ + } \ + } while (0) -#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ -do { \ - (replaced) = NULL; \ - HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ - if (replaced) { \ - HASH_DELETE(hh, head, replaced); \ - } \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ -} while (0) +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, hashval, add, replaced, cmpfcn) \ + do \ + { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) \ + { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ + } while (0) -#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ -do { \ - (replaced) = NULL; \ - HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ - if (replaced) { \ - HASH_DELETE(hh, head, replaced); \ - } \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ -} while (0) +#define HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, hashval, add, replaced) \ + do \ + { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) \ + { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ + } while (0) -#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ -do { \ - unsigned _hr_hashv; \ - HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ - HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ -} while (0) +#define HASH_REPLACE(hh, head, fieldname, keylen_in, add, replaced) \ + do \ + { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ + } while (0) -#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ -do { \ - unsigned _hr_hashv; \ - HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ - HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ -} while (0) +#define HASH_REPLACE_INORDER(hh, head, fieldname, keylen_in, add, replaced, cmpfcn) \ + do \ + { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ + } while (0) -#define HASH_APPEND_LIST(hh, head, add) \ -do { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ - (head)->hh.tbl->tail->next = (add); \ - (head)->hh.tbl->tail = &((add)->hh); \ -} while (0) +#define HASH_APPEND_LIST(hh, head, add) \ + do \ + { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } while (0) -#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ -do { \ - do { \ - if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ - break; \ - } \ - } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ -} while (0) +#define HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn) \ + do \ + { \ + do \ + { \ + if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) \ + { \ + break; \ + } \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ + } while (0) #ifdef NO_DECLTYPE #undef HASH_AKBI_INNER_LOOP -#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ -do { \ - char *_hs_saved_head = (char*)(head); \ - do { \ - DECLTYPE_ASSIGN(head, _hs_iter); \ - if (cmpfcn(head, add) > 0) { \ - DECLTYPE_ASSIGN(head, _hs_saved_head); \ - break; \ - } \ - DECLTYPE_ASSIGN(head, _hs_saved_head); \ - } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ -} while (0) +#define HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn) \ + do \ + { \ + char *_hs_saved_head = (char *)(head); \ + do \ + { \ + DECLTYPE_ASSIGN(head, _hs_iter); \ + if (cmpfcn(head, add) > 0) \ + { \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + break; \ + } \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ + } while (0) #endif #if HASH_NONFATAL_OOM -#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ -do { \ - if (!(oomed)) { \ - unsigned _ha_bkt; \ - (head)->hh.tbl->num_items++; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ - if (oomed) { \ - HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ - HASH_DELETE_HH(hh, head, &(add)->hh); \ - (add)->hh.tbl = NULL; \ - uthash_nonfatal_oom(add); \ - } else { \ - HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ - HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ - } \ - } else { \ - (add)->hh.tbl = NULL; \ - uthash_nonfatal_oom(add); \ - } \ -} while (0) +#define HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, oomed) \ + do \ + { \ + if (!(oomed)) \ + { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + if (oomed) \ + { \ + HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ + HASH_DELETE_HH(hh, head, &(add)->hh); \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ + else \ + { \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } \ + } \ + else \ + { \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ + } while (0) #else -#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ -do { \ - unsigned _ha_bkt; \ - (head)->hh.tbl->num_items++; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ - HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ - HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ -} while (0) +#define HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, oomed) \ + do \ + { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } while (0) #endif - -#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ -do { \ - IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ - (add)->hh.hashv = (hashval); \ - (add)->hh.key = (char*) (keyptr); \ - (add)->hh.keylen = (unsigned) (keylen_in); \ - if (!(head)) { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh, add, _ha_oomed); \ - IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, hashval, add, cmpfcn) \ + do \ + { \ + IF_HASH_NONFATAL_OOM(int _ha_oomed = 0;) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char *)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) \ + { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM(if (!_ha_oomed) { ) \ (head) = (add); \ - IF_HASH_NONFATAL_OOM( } ) \ - } else { \ - void *_hs_iter = (head); \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ - if (_hs_iter) { \ - (add)->hh.next = _hs_iter; \ - if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ - HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ - } else { \ - (head) = (add); \ - } \ - HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ - } else { \ - HASH_APPEND_LIST(hh, head, add); \ - } \ - } \ - HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ - HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ -} while (0) + IF_HASH_NONFATAL_OOM( }) \ + } \ + else \ + { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) \ + { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) \ + { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ + } \ + else \ + { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } \ + else \ + { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ + } while (0) -#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ -do { \ - unsigned _hs_hashv; \ - HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ -} while (0) +#define HASH_ADD_KEYPTR_INORDER(hh, head, keyptr, keylen_in, add, cmpfcn) \ + do \ + { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ + } while (0) -#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ +#define HASH_ADD_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, hashval, add, cmpfcn) \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) -#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ +#define HASH_ADD_INORDER(hh, head, fieldname, keylen_in, add, cmpfcn) \ HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) -#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ -do { \ - IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ - (add)->hh.hashv = (hashval); \ - (add)->hh.key = (const void*) (keyptr); \ - (add)->hh.keylen = (unsigned) (keylen_in); \ - if (!(head)) { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh, add, _ha_oomed); \ - IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, hashval, add) \ + do \ + { \ + IF_HASH_NONFATAL_OOM(int _ha_oomed = 0;) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (const void *)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) \ + { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM(if (!_ha_oomed) { ) \ (head) = (add); \ - IF_HASH_NONFATAL_OOM( } ) \ - } else { \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_APPEND_LIST(hh, head, add); \ - } \ - HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ - HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ -} while (0) + IF_HASH_NONFATAL_OOM( }) \ + } \ + else \ + { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ + } while (0) -#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ -do { \ - unsigned _ha_hashv; \ - HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ -} while (0) +#define HASH_ADD_KEYPTR(hh, head, keyptr, keylen_in, add) \ + do \ + { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ + } while (0) -#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ +#define HASH_ADD_BYHASHVALUE(hh, head, fieldname, keylen_in, hashval, add) \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) -#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ +#define HASH_ADD(hh, head, fieldname, keylen_in, add) \ HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) -#define HASH_TO_BKT(hashv,num_bkts,bkt) \ -do { \ - bkt = ((hashv) & ((num_bkts) - 1U)); \ -} while (0) +#define HASH_TO_BKT(hashv, num_bkts, bkt) \ + do \ + { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ + } while (0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. @@ -445,360 +509,441 @@ do { * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ -#define HASH_DELETE(hh,head,delptr) \ - HASH_DELETE_HH(hh, head, &(delptr)->hh) +#define HASH_DELETE(hh, head, delptr) \ + HASH_DELETE_HH(hh, head, &(delptr)->hh) -#define HASH_DELETE_HH(hh,head,delptrhh) \ -do { \ - struct UT_hash_handle *_hd_hh_del = (delptrhh); \ - if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head) = NULL; \ - } else { \ - unsigned _hd_bkt; \ - if (_hd_hh_del == (head)->hh.tbl->tail) { \ - (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ +#define HASH_DELETE_HH(hh, head, delptrhh) \ + do \ + { \ + struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) \ + { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ } \ - if (_hd_hh_del->prev != NULL) { \ - HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ - } else { \ - DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + else \ + { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) \ + { \ + (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) \ + { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ + } \ + else \ + { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) \ + { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ } \ - if (_hd_hh_del->next != NULL) { \ - HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ - } \ - HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ - (head)->hh.tbl->num_items--; \ - } \ - HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ -} while (0) + HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ + } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ -#define HASH_FIND_STR(head,findstr,out) \ -do { \ - unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ - HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ -} while (0) -#define HASH_ADD_STR(head,strfield,add) \ -do { \ - unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ - HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ -} while (0) -#define HASH_REPLACE_STR(head,strfield,add,replaced) \ -do { \ - unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ - HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ -} while (0) -#define HASH_FIND_INT(head,findint,out) \ - HASH_FIND(hh,head,findint,sizeof(int),out) -#define HASH_ADD_INT(head,intfield,add) \ - HASH_ADD(hh,head,intfield,sizeof(int),add) -#define HASH_REPLACE_INT(head,intfield,add,replaced) \ - HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) -#define HASH_FIND_PTR(head,findptr,out) \ - HASH_FIND(hh,head,findptr,sizeof(void *),out) -#define HASH_ADD_PTR(head,ptrfield,add) \ - HASH_ADD(hh,head,ptrfield,sizeof(void *),add) -#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ - HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) -#define HASH_DEL(head,delptr) \ - HASH_DELETE(hh,head,delptr) +#define HASH_FIND_STR(head, findstr, out) \ + do \ + { \ + unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ + HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ + } while (0) +#define HASH_ADD_STR(head, strfield, add) \ + do \ + { \ + unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ + } while (0) +#define HASH_REPLACE_STR(head, strfield, add, replaced) \ + do \ + { \ + unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ + } while (0) +#define HASH_FIND_INT(head, findint, out) \ + HASH_FIND(hh, head, findint, sizeof(int), out) +#define HASH_ADD_INT(head, intfield, add) \ + HASH_ADD(hh, head, intfield, sizeof(int), add) +#define HASH_REPLACE_INT(head, intfield, add, replaced) \ + HASH_REPLACE(hh, head, intfield, sizeof(int), add, replaced) +#define HASH_FIND_PTR(head, findptr, out) \ + HASH_FIND(hh, head, findptr, sizeof(void *), out) +#define HASH_ADD_PTR(head, ptrfield, add) \ + HASH_ADD(hh, head, ptrfield, sizeof(void *), add) +#define HASH_REPLACE_PTR(head, ptrfield, add, replaced) \ + HASH_REPLACE(hh, head, ptrfield, sizeof(void *), add, replaced) +#define HASH_DEL(head, delptr) \ + HASH_DELETE(hh, head, delptr) /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG -#include /* fprintf, stderr */ -#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0) -#define HASH_FSCK(hh,head,where) \ -do { \ - struct UT_hash_handle *_thh; \ - if (head) { \ - unsigned _bkt_i; \ - unsigned _count = 0; \ - char *_prev; \ - for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ - unsigned _bkt_count = 0; \ - _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ - _prev = NULL; \ - while (_thh) { \ - if (_prev != (char*)(_thh->hh_prev)) { \ - HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ - (where), (void*)_thh->hh_prev, (void*)_prev); \ +#include /* fprintf, stderr */ +#define HASH_OOPS(...) \ + do \ + { \ + fprintf(stderr, __VA_ARGS__); \ + exit(-1); \ + } while (0) +#define HASH_FSCK(hh, head, where) \ + do \ + { \ + struct UT_hash_handle *_thh; \ + if (head) \ + { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) \ + { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) \ + { \ + if (_prev != (char *)(_thh->hh_prev)) \ + { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + (where), (void *)_thh->hh_prev, (void *)_prev); \ + } \ + _bkt_count++; \ + _prev = (char *)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) \ + { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ - _bkt_count++; \ - _prev = (char*)(_thh); \ - _thh = _thh->hh_next; \ } \ - _count += _bkt_count; \ - if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ - HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ - (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + if (_count != (head)->hh.tbl->num_items) \ + { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) \ + { \ + _count++; \ + if (_prev != (char *)_thh->prev) \ + { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", \ + (where), (void *)_thh->prev, (void *)_prev); \ + } \ + _prev = (char *)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) \ + { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ } \ } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ - (where), (head)->hh.tbl->num_items, _count); \ - } \ - _count = 0; \ - _prev = NULL; \ - _thh = &(head)->hh; \ - while (_thh) { \ - _count++; \ - if (_prev != (char*)_thh->prev) { \ - HASH_OOPS("%s: invalid prev %p, actual %p\n", \ - (where), (void*)_thh->prev, (void*)_prev); \ - } \ - _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ - _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ - (where), (head)->hh.tbl->num_items, _count); \ - } \ - } \ -} while (0) + } while (0) #else -#define HASH_FSCK(hh,head,where) +#define HASH_FSCK(hh, head, where) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ -do { \ - unsigned _klen = fieldlen; \ - write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ - write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ -} while (0) +#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen) \ + do \ + { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ + } while (0) #else -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen) #endif /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ -#define HASH_BER(key,keylen,hashv) \ -do { \ - unsigned _hb_keylen = (unsigned)keylen; \ - const unsigned char *_hb_key = (const unsigned char*)(key); \ - (hashv) = 0; \ - while (_hb_keylen-- != 0U) { \ - (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ - } \ -} while (0) - +#define HASH_BER(key, keylen, hashv) \ + do \ + { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char *)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) \ + { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ + } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ -#define HASH_SAX(key,keylen,hashv) \ -do { \ - unsigned _sx_i; \ - const unsigned char *_hs_key = (const unsigned char*)(key); \ - hashv = 0; \ - for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ - hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ - } \ -} while (0) +#define HASH_SAX(key, keylen, hashv) \ + do \ + { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char *)(key); \ + hashv = 0; \ + for (_sx_i = 0; _sx_i < keylen; _sx_i++) \ + { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ + } while (0) /* FNV-1a variation */ -#define HASH_FNV(key,keylen,hashv) \ -do { \ - unsigned _fn_i; \ - const unsigned char *_hf_key = (const unsigned char*)(key); \ - (hashv) = 2166136261U; \ - for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ - hashv = hashv ^ _hf_key[_fn_i]; \ - hashv = hashv * 16777619U; \ - } \ -} while (0) +#define HASH_FNV(key, keylen, hashv) \ + do \ + { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char *)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i = 0; _fn_i < keylen; _fn_i++) \ + { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ + } while (0) -#define HASH_OAT(key,keylen,hashv) \ -do { \ - unsigned _ho_i; \ - const unsigned char *_ho_key=(const unsigned char*)(key); \ - hashv = 0; \ - for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ - hashv += _ho_key[_ho_i]; \ - hashv += (hashv << 10); \ - hashv ^= (hashv >> 6); \ - } \ - hashv += (hashv << 3); \ - hashv ^= (hashv >> 11); \ - hashv += (hashv << 15); \ -} while (0) +#define HASH_OAT(key, keylen, hashv) \ + do \ + { \ + unsigned _ho_i; \ + const unsigned char *_ho_key = (const unsigned char *)(key); \ + hashv = 0; \ + for (_ho_i = 0; _ho_i < keylen; _ho_i++) \ + { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + } while (0) -#define HASH_JEN_MIX(a,b,c) \ -do { \ - a -= b; a -= c; a ^= ( c >> 13 ); \ - b -= c; b -= a; b ^= ( a << 8 ); \ - c -= a; c -= b; c ^= ( b >> 13 ); \ - a -= b; a -= c; a ^= ( c >> 12 ); \ - b -= c; b -= a; b ^= ( a << 16 ); \ - c -= a; c -= b; c ^= ( b >> 5 ); \ - a -= b; a -= c; a ^= ( c >> 3 ); \ - b -= c; b -= a; b ^= ( a << 10 ); \ - c -= a; c -= b; c ^= ( b >> 15 ); \ -} while (0) +#define HASH_JEN_MIX(a, b, c) \ + do \ + { \ + a -= b; \ + a -= c; \ + a ^= (c >> 13); \ + b -= c; \ + b -= a; \ + b ^= (a << 8); \ + c -= a; \ + c -= b; \ + c ^= (b >> 13); \ + a -= b; \ + a -= c; \ + a ^= (c >> 12); \ + b -= c; \ + b -= a; \ + b ^= (a << 16); \ + c -= a; \ + c -= b; \ + c ^= (b >> 5); \ + a -= b; \ + a -= c; \ + a ^= (c >> 3); \ + b -= c; \ + b -= a; \ + b ^= (a << 10); \ + c -= a; \ + c -= b; \ + c ^= (b >> 15); \ + } while (0) -#define HASH_JEN(key,keylen,hashv) \ -do { \ - unsigned _hj_i,_hj_j,_hj_k; \ - unsigned const char *_hj_key=(unsigned const char*)(key); \ - hashv = 0xfeedbeefu; \ - _hj_i = _hj_j = 0x9e3779b9u; \ - _hj_k = (unsigned)(keylen); \ - while (_hj_k >= 12U) { \ - _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ - + ( (unsigned)_hj_key[2] << 16 ) \ - + ( (unsigned)_hj_key[3] << 24 ) ); \ - _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ - + ( (unsigned)_hj_key[6] << 16 ) \ - + ( (unsigned)_hj_key[7] << 24 ) ); \ - hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ - + ( (unsigned)_hj_key[10] << 16 ) \ - + ( (unsigned)_hj_key[11] << 24 ) ); \ - \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - \ - _hj_key += 12; \ - _hj_k -= 12U; \ - } \ - hashv += (unsigned)(keylen); \ - switch ( _hj_k ) { \ - case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ - case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ - case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ - case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ - case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ - case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ - case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ - case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ - case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ - case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ - case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ - default: ; \ - } \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ -} while (0) +#define HASH_JEN(key, keylen, hashv) \ + do \ + { \ + unsigned _hj_i, _hj_j, _hj_k; \ + unsigned const char *_hj_key = (unsigned const char *)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) \ + { \ + _hj_i += (_hj_key[0] + ((unsigned)_hj_key[1] << 8) + ((unsigned)_hj_key[2] << 16) + ((unsigned)_hj_key[3] << 24)); \ + _hj_j += (_hj_key[4] + ((unsigned)_hj_key[5] << 8) + ((unsigned)_hj_key[6] << 16) + ((unsigned)_hj_key[7] << 24)); \ + hashv += (_hj_key[8] + ((unsigned)_hj_key[9] << 8) + ((unsigned)_hj_key[10] << 16) + ((unsigned)_hj_key[11] << 24)); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch (_hj_k) \ + { \ + case 11: \ + hashv += ((unsigned)_hj_key[10] << 24); /* FALLTHROUGH */ \ + case 10: \ + hashv += ((unsigned)_hj_key[9] << 16); /* FALLTHROUGH */ \ + case 9: \ + hashv += ((unsigned)_hj_key[8] << 8); /* FALLTHROUGH */ \ + case 8: \ + _hj_j += ((unsigned)_hj_key[7] << 24); /* FALLTHROUGH */ \ + case 7: \ + _hj_j += ((unsigned)_hj_key[6] << 16); /* FALLTHROUGH */ \ + case 6: \ + _hj_j += ((unsigned)_hj_key[5] << 8); /* FALLTHROUGH */ \ + case 5: \ + _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: \ + _hj_i += ((unsigned)_hj_key[3] << 24); /* FALLTHROUGH */ \ + case 3: \ + _hj_i += ((unsigned)_hj_key[2] << 16); /* FALLTHROUGH */ \ + case 2: \ + _hj_i += ((unsigned)_hj_key[1] << 8); /* FALLTHROUGH */ \ + case 1: \ + _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ + default:; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + } while (0) /* The Paul Hsieh hash function */ #undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__) +#define get16bits(d) (*((const uint16_t *)(d))) #endif -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ - +(uint32_t)(((const uint8_t *)(d))[0]) ) +#if !defined(get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) + (uint32_t)(((const uint8_t *)(d))[0])) #endif -#define HASH_SFH(key,keylen,hashv) \ -do { \ - unsigned const char *_sfh_key=(unsigned const char*)(key); \ - uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ - \ - unsigned _sfh_rem = _sfh_len & 3U; \ - _sfh_len >>= 2; \ - hashv = 0xcafebabeu; \ - \ - /* Main loop */ \ - for (;_sfh_len > 0U; _sfh_len--) { \ - hashv += get16bits (_sfh_key); \ - _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ - hashv = (hashv << 16) ^ _sfh_tmp; \ - _sfh_key += 2U*sizeof (uint16_t); \ - hashv += hashv >> 11; \ - } \ - \ - /* Handle end cases */ \ - switch (_sfh_rem) { \ - case 3: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 16; \ - hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ - hashv += hashv >> 11; \ - break; \ - case 2: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 11; \ - hashv += hashv >> 17; \ - break; \ - case 1: hashv += *_sfh_key; \ - hashv ^= hashv << 10; \ - hashv += hashv >> 1; \ - break; \ - default: ; \ - } \ - \ - /* Force "avalanching" of final 127 bits */ \ - hashv ^= hashv << 3; \ - hashv += hashv >> 5; \ - hashv ^= hashv << 4; \ - hashv += hashv >> 17; \ - hashv ^= hashv << 25; \ - hashv += hashv >> 6; \ -} while (0) +#define HASH_SFH(key, keylen, hashv) \ + do \ + { \ + unsigned const char *_sfh_key = (unsigned const char *)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (; _sfh_len > 0U; _sfh_len--) \ + { \ + hashv += get16bits(_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits(_sfh_key + 2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U * sizeof(uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) \ + { \ + case 3: \ + hashv += get16bits(_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof(uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: \ + hashv += get16bits(_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: \ + hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + break; \ + default:; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + } while (0) /* iterate over items in a known bucket to find desired item */ -#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ -do { \ - if ((head).hh_head != NULL) { \ - DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ - } else { \ - (out) = NULL; \ - } \ - while ((out) != NULL) { \ - if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ - if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ - break; \ - } \ - } \ - if ((out)->hh.hh_next != NULL) { \ - DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ - } else { \ - (out) = NULL; \ - } \ - } \ -} while (0) +#define HASH_FIND_IN_BKT(tbl, hh, head, keyptr, keylen_in, hashval, out) \ + do \ + { \ + if ((head).hh_head != NULL) \ + { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } \ + else \ + { \ + (out) = NULL; \ + } \ + while ((out) != NULL) \ + { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) \ + { \ + if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) \ + { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) \ + { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } \ + else \ + { \ + (out) = NULL; \ + } \ + } \ + } while (0) /* add an item to a bucket */ -#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ -do { \ - UT_hash_bucket *_ha_head = &(head); \ - _ha_head->count++; \ - (addhh)->hh_next = _ha_head->hh_head; \ - (addhh)->hh_prev = NULL; \ - if (_ha_head->hh_head != NULL) { \ - _ha_head->hh_head->hh_prev = (addhh); \ - } \ - _ha_head->hh_head = (addhh); \ - if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ - && !(addhh)->tbl->noexpand) { \ - HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (oomed) { \ - HASH_DEL_IN_BKT(head,addhh); \ - } \ - ) \ - } \ -} while (0) +#define HASH_ADD_TO_BKT(head, hh, addhh, oomed) \ + do \ + { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) \ + { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) && !(addhh)->tbl->noexpand) \ + { \ + HASH_EXPAND_BUCKETS(addhh, (addhh)->tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + HASH_DEL_IN_BKT(head, addhh); \ + }) \ + } \ + } while (0) /* remove an item from a given bucket */ -#define HASH_DEL_IN_BKT(head,delhh) \ -do { \ - UT_hash_bucket *_hd_head = &(head); \ - _hd_head->count--; \ - if (_hd_head->hh_head == (delhh)) { \ - _hd_head->hh_head = (delhh)->hh_next; \ - } \ - if ((delhh)->hh_prev) { \ - (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ - } \ - if ((delhh)->hh_next) { \ - (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ - } \ -} while (0) +#define HASH_DEL_IN_BKT(head, delhh) \ + do \ + { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) \ + { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) \ + { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) \ + { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ + } while (0) /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the @@ -829,259 +974,292 @@ do { * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ -#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ -do { \ - unsigned _he_bkt; \ - unsigned _he_bkt_i; \ - struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ - UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ - _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ - sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ - if (!_he_new_buckets) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero(_he_new_buckets, \ - sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ - (tbl)->ideal_chain_maxlen = \ - ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ - ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ - (tbl)->nonideal_items = 0; \ - for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ - _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ - while (_he_thh != NULL) { \ - _he_hh_nxt = _he_thh->hh_next; \ - HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ - _he_newbkt = &(_he_new_buckets[_he_bkt]); \ - if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ - (tbl)->nonideal_items++; \ - if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ - _he_newbkt->expand_mult++; \ - } \ - } \ - _he_thh->hh_prev = NULL; \ - _he_thh->hh_next = _he_newbkt->hh_head; \ - if (_he_newbkt->hh_head != NULL) { \ - _he_newbkt->hh_head->hh_prev = _he_thh; \ - } \ - _he_newbkt->hh_head = _he_thh; \ - _he_thh = _he_hh_nxt; \ - } \ - } \ - uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ - (tbl)->num_buckets *= 2U; \ - (tbl)->log2_num_buckets++; \ - (tbl)->buckets = _he_new_buckets; \ - (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ - ((tbl)->ineff_expands+1U) : 0U; \ - if ((tbl)->ineff_expands > 1U) { \ - (tbl)->noexpand = 1; \ - uthash_noexpand_fyi(tbl); \ - } \ - uthash_expand_fyi(tbl); \ - } \ -} while (0) - +#define HASH_EXPAND_BUCKETS(hh, tbl, oomed) \ + do \ + { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket *)uthash_malloc( \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + if (!_he_new_buckets) \ + { \ + HASH_RECORD_OOM(oomed); \ + } \ + else \ + { \ + uthash_bzero(_he_new_buckets, \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets + 1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets * 2U) - 1U)) != 0U) ? 1U : 0U); \ + (tbl)->nonideal_items = 0; \ + for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = (tbl)->buckets[_he_bkt_i].hh_head; \ + while (_he_thh != NULL) \ + { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) \ + { \ + (tbl)->nonideal_items++; \ + if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) \ + { \ + _he_newbkt->expand_mult++; \ + } \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) \ + { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? ((tbl)->ineff_expands + 1U) : 0U; \ + if ((tbl)->ineff_expands > 1U) \ + { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ + } \ + } while (0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ -#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) -#define HASH_SRT(hh,head,cmpfcn) \ -do { \ - unsigned _hs_i; \ - unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ - struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ - if (head != NULL) { \ - _hs_insize = 1; \ - _hs_looping = 1; \ - _hs_list = &((head)->hh); \ - while (_hs_looping != 0U) { \ - _hs_p = _hs_list; \ - _hs_list = NULL; \ - _hs_tail = NULL; \ - _hs_nmerges = 0; \ - while (_hs_p != NULL) { \ - _hs_nmerges++; \ - _hs_q = _hs_p; \ - _hs_psize = 0; \ - for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ - _hs_psize++; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - if (_hs_q == NULL) { \ - break; \ - } \ - } \ - _hs_qsize = _hs_insize; \ - while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ - if (_hs_psize == 0U) { \ - _hs_e = _hs_q; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - _hs_qsize--; \ - } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ - _hs_e = _hs_p; \ - if (_hs_p != NULL) { \ - _hs_p = ((_hs_p->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ - } \ - _hs_psize--; \ - } else if ((cmpfcn( \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ - )) <= 0) { \ - _hs_e = _hs_p; \ - if (_hs_p != NULL) { \ - _hs_p = ((_hs_p->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ - } \ - _hs_psize--; \ - } else { \ - _hs_e = _hs_q; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - _hs_qsize--; \ - } \ - if ( _hs_tail != NULL ) { \ - _hs_tail->next = ((_hs_e != NULL) ? \ - ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ - } else { \ - _hs_list = _hs_e; \ - } \ - if (_hs_e != NULL) { \ - _hs_e->prev = ((_hs_tail != NULL) ? \ - ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ - } \ - _hs_tail = _hs_e; \ - } \ - _hs_p = _hs_q; \ - } \ - if (_hs_tail != NULL) { \ - _hs_tail->next = NULL; \ - } \ - if (_hs_nmerges <= 1U) { \ - _hs_looping = 0; \ - (head)->hh.tbl->tail = _hs_tail; \ - DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ - } \ - _hs_insize *= 2U; \ - } \ - HASH_FSCK(hh, head, "HASH_SRT"); \ - } \ -} while (0) +#define HASH_SORT(head, cmpfcn) HASH_SRT(hh, head, cmpfcn) +#define HASH_SRT(hh, head, cmpfcn) \ + do \ + { \ + unsigned _hs_i; \ + unsigned _hs_looping, _hs_nmerges, _hs_insize, _hs_psize, _hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) \ + { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) \ + { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) \ + { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) \ + { \ + _hs_psize++; \ + _hs_q = ((_hs_q->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + if (_hs_q == NULL) \ + { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) \ + { \ + if (_hs_psize == 0U) \ + { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + else if ((_hs_qsize == 0U) || (_hs_q == NULL)) \ + { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) \ + { \ + _hs_p = ((_hs_p->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } \ + else if ((cmpfcn( \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)))) <= 0) \ + { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) \ + { \ + _hs_p = ((_hs_p->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } \ + else \ + { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + if (_hs_tail != NULL) \ + { \ + _hs_tail->next = ((_hs_e != NULL) ? ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ + } \ + else \ + { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) \ + { \ + _hs_e->prev = ((_hs_tail != NULL) ? ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) \ + { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) \ + { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ + } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ -#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ -do { \ - unsigned _src_bkt, _dst_bkt; \ - void *_last_elt = NULL, *_elt; \ - UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ - ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ - if ((src) != NULL) { \ - for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ - for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ - _src_hh != NULL; \ - _src_hh = _src_hh->hh_next) { \ - _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ - if (cond(_elt)) { \ - IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ - _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \ - _dst_hh->key = _src_hh->key; \ - _dst_hh->keylen = _src_hh->keylen; \ - _dst_hh->hashv = _src_hh->hashv; \ - _dst_hh->prev = _last_elt; \ - _dst_hh->next = NULL; \ - if (_last_elt_hh != NULL) { \ - _last_elt_hh->next = _elt; \ - } \ - if ((dst) == NULL) { \ - DECLTYPE_ASSIGN(dst, _elt); \ - HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (_hs_oomed) { \ - uthash_nonfatal_oom(_elt); \ - (dst) = NULL; \ - continue; \ - } \ - ) \ - } else { \ - _dst_hh->tbl = (dst)->hh_dst.tbl; \ - } \ - HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ - HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ - (dst)->hh_dst.tbl->num_items++; \ - IF_HASH_NONFATAL_OOM( \ - if (_hs_oomed) { \ - HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ - HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ - _dst_hh->tbl = NULL; \ - uthash_nonfatal_oom(_elt); \ - continue; \ - } \ - ) \ - HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ - _last_elt = _elt; \ - _last_elt_hh = _dst_hh; \ - } \ - } \ - } \ - } \ - HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ -} while (0) +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ + do \ + { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh = NULL; \ + ptrdiff_t _dst_hho = ((char *)(&(dst)->hh_dst) - (char *)(dst)); \ + if ((src) != NULL) \ + { \ + for (_src_bkt = 0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) \ + { \ + for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; \ + _src_hh = _src_hh->hh_next) \ + { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) \ + { \ + IF_HASH_NONFATAL_OOM(int _hs_oomed = 0;) \ + _dst_hh = (UT_hash_handle *)(void *)(((char *)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) \ + { \ + _last_elt_hh->next = _elt; \ + } \ + if ((dst) == NULL) \ + { \ + DECLTYPE_ASSIGN(dst, _elt); \ + HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + uthash_nonfatal_oom(_elt); \ + (dst) = NULL; \ + continue; \ + }) \ + } \ + else \ + { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ + (dst)->hh_dst.tbl->num_items++; \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ + HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ + _dst_hh->tbl = NULL; \ + uthash_nonfatal_oom(_elt); \ + continue; \ + }) \ + HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ + } while (0) -#define HASH_CLEAR(hh,head) \ -do { \ - if ((head) != NULL) { \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head) = NULL; \ - } \ -} while (0) +#define HASH_CLEAR(hh, head) \ + do \ + { \ + if ((head) != NULL) \ + { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } \ + } while (0) -#define HASH_OVERHEAD(hh,head) \ - (((head) != NULL) ? ( \ - (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ - ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ - sizeof(UT_hash_table) + \ - (HASH_BLOOM_BYTELEN))) : 0U) +#define HASH_OVERHEAD(hh, head) \ + (((head) != NULL) ? ( \ + (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + \ + (HASH_BLOOM_BYTELEN))) \ + : 0U) #ifdef NO_DECLTYPE -#define HASH_ITER(hh,head,el,tmp) \ -for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ - (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#define HASH_ITER(hh, head, el, tmp) \ + for (((el) = (head)), ((*(char **)(&(tmp))) = (char *)((head != NULL) ? (head)->hh.next : NULL)); \ + (el) != NULL; ((el) = (tmp)), ((*(char **)(&(tmp))) = (char *)((tmp != NULL) ? (tmp)->hh.next : NULL))) #else -#define HASH_ITER(hh,head,el,tmp) \ -for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ - (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#define HASH_ITER(hh, head, el, tmp) \ + for (((el) = (head)), ((tmp) = DECLTYPE(el)((head != NULL) ? (head)->hh.next : NULL)); \ + (el) != NULL; ((el) = (tmp)), ((tmp) = DECLTYPE(el)((tmp != NULL) ? (tmp)->hh.next : NULL))) #endif /* obtain a count of items in the hash */ -#define HASH_COUNT(head) HASH_CNT(hh,head) -#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) +#define HASH_COUNT(head) HASH_CNT(hh, head) +#define HASH_CNT(hh, head) ((head != NULL) ? ((head)->hh.tbl->num_items) : 0U) -typedef struct UT_hash_bucket { - struct UT_hash_handle *hh_head; - unsigned count; +typedef struct UT_hash_bucket +{ + struct UT_hash_handle *hh_head; + unsigned count; - /* expand_mult is normally set to 0. In this situation, the max chain length - * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If - * the bucket's chain exceeds this length, bucket expansion is triggered). - * However, setting expand_mult to a non-zero value delays bucket expansion - * (that would be triggered by additions to this particular bucket) - * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. - * (The multiplier is simply expand_mult+1). The whole idea of this - * multiplier is to reduce bucket expansions, since they are expensive, in - * situations where we know that a particular bucket tends to be overused. - * It is better to let its chain length grow to a longer yet-still-bounded - * value, than to do an O(n) bucket expansion too often. - */ - unsigned expand_mult; + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; } UT_hash_bucket; @@ -1089,48 +1267,50 @@ typedef struct UT_hash_bucket { #define HASH_SIGNATURE 0xa0111fe1u #define HASH_BLOOM_SIGNATURE 0xb12220f2u -typedef struct UT_hash_table { - UT_hash_bucket *buckets; - unsigned num_buckets, log2_num_buckets; - unsigned num_items; - struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ - ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ +typedef struct UT_hash_table +{ + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ - /* in an ideal situation (all buckets used equally), no bucket would have - * more than ceil(#items/#buckets) items. that's the ideal chain length. */ - unsigned ideal_chain_maxlen; + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; - /* nonideal_items is the number of items in the hash whose chain position - * exceeds the ideal chain maxlen. these items pay the penalty for an uneven - * hash distribution; reaching them in a chain traversal takes >ideal steps */ - unsigned nonideal_items; + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; - /* ineffective expands occur when a bucket doubling was performed, but - * afterward, more than half the items in the hash had nonideal chain - * positions. If this happens on two consecutive expansions we inhibit any - * further expansion, as it's not helping; this happens when the hash - * function isn't a good fit for the key domain. When expansion is inhibited - * the hash will still work, albeit no longer in constant time. */ - unsigned ineff_expands, noexpand; + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; - uint32_t signature; /* used only to find hash tables in external analysis */ + uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM - uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ - uint8_t *bloom_bv; - uint8_t bloom_nbits; + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; #endif } UT_hash_table; -typedef struct UT_hash_handle { - struct UT_hash_table *tbl; - void *prev; /* prev element in app order */ - void *next; /* next element in app order */ - struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ - struct UT_hash_handle *hh_next; /* next hh in bucket order */ - const void *key; /* ptr to enclosing struct's key */ - unsigned keylen; /* enclosing struct's key len */ - unsigned hashv; /* result of hash-fcn(key) */ +typedef struct UT_hash_handle +{ + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + const void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */