diff --git a/binaries/aarch64/nfqws b/binaries/aarch64/nfqws index 88cb0fc..6d122dc 100755 Binary files a/binaries/aarch64/nfqws and b/binaries/aarch64/nfqws differ diff --git a/binaries/aarch64/tpws b/binaries/aarch64/tpws index f9d03e8..d2a4be7 100755 Binary files a/binaries/aarch64/tpws and b/binaries/aarch64/tpws differ diff --git a/binaries/armhf/nfqws b/binaries/armhf/nfqws index e16e66b..d708da7 100755 Binary files a/binaries/armhf/nfqws and b/binaries/armhf/nfqws differ diff --git a/binaries/armhf/tpws b/binaries/armhf/tpws index 87524f2..c3369db 100755 Binary files a/binaries/armhf/tpws and b/binaries/armhf/tpws differ diff --git a/binaries/mips32r1-lsb/nfqws b/binaries/mips32r1-lsb/nfqws index 13a1929..3b55548 100755 Binary files a/binaries/mips32r1-lsb/nfqws and b/binaries/mips32r1-lsb/nfqws differ diff --git a/binaries/mips32r1-lsb/tpws b/binaries/mips32r1-lsb/tpws index 4c09d5a..858e273 100755 Binary files a/binaries/mips32r1-lsb/tpws and b/binaries/mips32r1-lsb/tpws differ diff --git a/binaries/mips32r1-msb/nfqws b/binaries/mips32r1-msb/nfqws index b4e51b6..914424f 100755 Binary files a/binaries/mips32r1-msb/nfqws and b/binaries/mips32r1-msb/nfqws differ diff --git a/binaries/mips32r1-msb/tpws b/binaries/mips32r1-msb/tpws index 2842e94..893dbbd 100755 Binary files a/binaries/mips32r1-msb/tpws and b/binaries/mips32r1-msb/tpws differ diff --git a/binaries/mips64r2-msb/nfqws b/binaries/mips64r2-msb/nfqws index 08ca049..475d573 100755 Binary files a/binaries/mips64r2-msb/nfqws and b/binaries/mips64r2-msb/nfqws differ diff --git a/binaries/mips64r2-msb/tpws b/binaries/mips64r2-msb/tpws index 19cf364..f4b2e2e 100755 Binary files a/binaries/mips64r2-msb/tpws and b/binaries/mips64r2-msb/tpws differ diff --git a/binaries/ppc/nfqws b/binaries/ppc/nfqws index b7f1d16..7b827bd 100755 Binary files a/binaries/ppc/nfqws and b/binaries/ppc/nfqws differ diff --git a/binaries/ppc/tpws b/binaries/ppc/tpws index 8c369e8..2aee02f 100755 Binary files a/binaries/ppc/tpws and b/binaries/ppc/tpws differ diff --git a/binaries/x86/nfqws b/binaries/x86/nfqws index 97b2c9c..64bca70 100755 Binary files a/binaries/x86/nfqws and b/binaries/x86/nfqws differ diff --git a/binaries/x86/tpws b/binaries/x86/tpws index 99f5daa..49e027e 100755 Binary files a/binaries/x86/tpws and b/binaries/x86/tpws differ diff --git a/binaries/x86_64/nfqws b/binaries/x86_64/nfqws index 53afe09..36ee0cb 100755 Binary files a/binaries/x86_64/nfqws and b/binaries/x86_64/nfqws differ diff --git a/binaries/x86_64/tpws b/binaries/x86_64/tpws index 5cfafd1..4a136f1 100755 Binary files a/binaries/x86_64/tpws and b/binaries/x86_64/tpws differ diff --git a/nfq/Makefile b/nfq/Makefile index a138ba7..a465242 100644 --- a/nfq/Makefile +++ b/nfq/Makefile @@ -1,6 +1,6 @@ CC ?= gcc CFLAGS += -std=c99 -s -O3 -LIBS = -lnetfilter_queue -lnfnetlink -lcap -lz +LIBS = -lnetfilter_queue -lnfnetlink -lz SRC_FILES = *.c all: nfqws diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index 41cdbed..bcc5d60 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -10,65 +10,138 @@ uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment) return htonl(ntohl(netorder_value)+cpuorder_increment); } +uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind) +{ + char *t = (char*)(tcp+1); + char *end = (char*)tcp + (tcp->doff<<2); + while(t=end || (t+t[1])>end) + 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; +} -static void fill_tcphdr(struct tcphdr *tcp, uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, enum tcp_fooling_mode fooling, uint16_t nsport, uint16_t ndport, uint16_t nwsize) +static void fill_tcphdr(struct tcphdr *tcp, uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint8_t fooling, uint16_t nsport, uint16_t ndport, uint16_t nwsize, uint32_t *timestamps) { char *tcpopt = (char*)(tcp+1); + uint8_t t=0; + memset(tcp,0,sizeof(*tcp)); tcp->source = nsport; tcp->dest = ndport; - tcp->seq = seq; - tcp->ack_seq = ack_seq; + if (fooling & TCP_FOOL_BADSEQ) + { + tcp->seq = net32_add(seq,0x80000000); + tcp->ack_seq = net32_add(ack_seq,0x80000000); + } + else + { + tcp->seq = seq; + tcp->ack_seq = ack_seq; + } tcp->doff = 5; *((uint8_t*)tcp+13)= tcp_flags; tcp->window = nwsize; - if (fooling==TCP_FOOL_MD5SIG) + if (fooling & TCP_FOOL_MD5SIG) { - tcp->doff += 5; // +20 bytes 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(); - tcpopt[18] = 0; // end - tcpopt[19] = 0; + t=18; } + if (timestamps || (fooling & TCP_FOOL_TS)) + { + 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 & TCP_FOOL_TS)) ? timestamps[1] : -1; + t+=10; + } + while (t&3) tcpopt[t++]=1; // noop + tcp->doff += t>>2; +} +static uint16_t tcpopt_len(uint8_t fooling, uint32_t *timestamps) +{ + uint16_t t=0; + if (fooling & TCP_FOOL_MD5SIG) t=18; + if ((fooling & TCP_FOOL_TS) || timestamps) t+=10; + return (t+3)&~3; } -static int rawsend_sock=-1; -void rawsend_cleanup() +static int rawsend_sock4=-1, rawsend_sock6=-1; +static void rawsend_clean_sock(int *sock) { - if (rawsend_sock!=-1) + if (sock && *sock!=-1) { - close(rawsend_sock); - rawsend_sock=-1; + close(*sock); + *sock=-1; } } -static void rawsend_socket(int family,uint32_t fwmark) +void rawsend_cleanup() { - if (rawsend_sock==-1) + rawsend_clean_sock(&rawsend_sock4); + rawsend_clean_sock(&rawsend_sock6); +} +static int *rawsend_family_sock(int family) +{ + switch(family) + { + case AF_INET: return &rawsend_sock4; + case AF_INET6: return &rawsend_sock6; + default: return NULL; + } +} +static int rawsend_socket(int family,uint32_t fwmark) +{ + int *sock = rawsend_family_sock(family); + if (!sock) return -1; + + if (*sock==-1) { int yes=1,pri=6; - rawsend_sock = socket(family, SOCK_RAW, IPPROTO_RAW); - if (rawsend_sock==-1) + *sock = socket(family, SOCK_RAW, IPPROTO_RAW); + if (*sock==-1) perror("rawsend: socket()"); - else if (setsockopt(rawsend_sock, SOL_SOCKET, SO_MARK, &fwmark, sizeof(fwmark)) == -1) + else if (setsockopt(*sock, SOL_SOCKET, SO_MARK, &fwmark, sizeof(fwmark)) == -1) { perror("rawsend: setsockopt(SO_MARK)"); - rawsend_cleanup(); + rawsend_clean_sock(sock); } - else if (setsockopt(rawsend_sock, SOL_SOCKET, SO_PRIORITY, &pri, sizeof(pri)) == -1) + else if (setsockopt(*sock, SOL_SOCKET, SO_PRIORITY, &pri, sizeof(pri)) == -1) { perror("rawsend: setsockopt(SO_PRIORITY)"); - rawsend_cleanup(); + rawsend_clean_sock(sock); } } + return *sock; } bool rawsend(struct sockaddr* dst,uint32_t fwmark,const void *data,size_t len) { - rawsend_socket(dst->sa_family,fwmark); - if (rawsend_sock==-1) return false; + int sock=rawsend_socket(dst->sa_family,fwmark); + if (sock==-1) return false; int salen = dst->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); struct sockaddr_storage dst2; @@ -76,7 +149,7 @@ bool rawsend(struct sockaddr* dst,uint32_t fwmark,const void *data,size_t len) if (dst->sa_family==AF_INET6) ((struct sockaddr_in6 *)&dst2)->sin6_port = 0; // or will be EINVAL - int bytes = sendto(rawsend_sock, data, len, 0, (struct sockaddr*)&dst2, salen); + int bytes = sendto(sock, data, len, 0, (struct sockaddr*)&dst2, salen); if (bytes==-1) { perror("rawsend: sendto"); @@ -89,14 +162,14 @@ bool prepare_tcp_segment4( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint32_t *timestamps, uint8_t ttl, - enum tcp_fooling_mode fooling, + uint8_t fooling, const void *data, uint16_t len, char *buf, size_t *buflen) { - uint16_t tcpoptlen = 0; - if (fooling==TCP_FOOL_MD5SIG) tcpoptlen=20; - uint16_t pktlen = sizeof(struct iphdr) + sizeof(struct tcphdr) + tcpoptlen + len; + uint16_t tcpoptlen = tcpopt_len(fooling,timestamps); + uint16_t pktlen = sizeof(struct iphdr) + sizeof(struct tcphdr) + tcpoptlen + len; if (pktlen>*buflen) { fprintf(stderr,"prepare_tcp_segment : packet len cannot exceed %zu\n",*buflen); @@ -116,11 +189,11 @@ bool prepare_tcp_segment4( ip->saddr = src->sin_addr.s_addr; ip->daddr = dst->sin_addr.s_addr; - fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin_port,dst->sin_port,wsize); + fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin_port,dst->sin_port,wsize,timestamps); memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len); tcp_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,ip->saddr,ip->daddr); - if (fooling==TCP_FOOL_BADSUM) tcp->check^=0xBEAF; + if (fooling & TCP_FOOL_BADSUM) tcp->check^=0xBEAF; *buflen = pktlen; return true; @@ -132,13 +205,13 @@ bool prepare_tcp_segment6( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint32_t *timestamps, uint8_t ttl, - enum tcp_fooling_mode fooling, + uint8_t fooling, const void *data, uint16_t len, char *buf, size_t *buflen) { - uint16_t tcpoptlen = 0; - if (fooling==TCP_FOOL_MD5SIG) tcpoptlen=20; + uint16_t tcpoptlen = tcpopt_len(fooling,timestamps); uint16_t payloadlen = sizeof(struct tcphdr) + tcpoptlen + len; uint16_t pktlen = sizeof(struct ip6_hdr) + payloadlen; if (pktlen>*buflen) @@ -157,11 +230,11 @@ bool prepare_tcp_segment6( ip6->ip6_src = src->sin6_addr; ip6->ip6_dst = dst->sin6_addr; - fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin6_port,dst->sin6_port,wsize); + fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin6_port,dst->sin6_port,wsize,timestamps); memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len); tcp6_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,&ip6->ip6_src,&ip6->ip6_dst); - if (fooling==TCP_FOOL_BADSUM) tcp->check^=0xBEAF; + if (fooling & TCP_FOOL_BADSUM) tcp->check^=0xBEAF; *buflen = pktlen; return true; @@ -172,15 +245,16 @@ bool prepare_tcp_segment( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint32_t *timestamps, uint8_t ttl, - enum tcp_fooling_mode fooling, + uint8_t fooling, const void *data, uint16_t len, char *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,seq,ack_seq,wsize,ttl,fooling,data,len,buf,buflen) : + prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,seq,ack_seq,wsize,timestamps,ttl,fooling,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,seq,ack_seq,wsize,ttl,fooling,data,len,buf,buflen) : + prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,seq,ack_seq,wsize,timestamps,ttl,fooling,data,len,buf,buflen) : false; } diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index 72593b9..63864b5 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -12,19 +12,21 @@ // returns netorder value uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment); -enum tcp_fooling_mode { - TCP_FOOL_NONE=0, - TCP_FOOL_MD5SIG=1, - TCP_FOOL_BADSUM=2 -}; +#define TCP_FOOL_NONE 0 +#define TCP_FOOL_MD5SIG 1 +#define TCP_FOOL_BADSUM 2 +#define TCP_FOOL_TS 4 +#define TCP_FOOL_BADSEQ 8 + // seq and wsize have network byte order bool prepare_tcp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint32_t *timestamps, uint8_t ttl, - enum tcp_fooling_mode fooling, + uint8_t fooling, const void *data, uint16_t len, char *buf, size_t *buflen); bool prepare_tcp_segment6( @@ -32,8 +34,9 @@ bool prepare_tcp_segment6( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint32_t *timestamps, uint8_t ttl, - enum tcp_fooling_mode fooling, + uint8_t fooling, const void *data, uint16_t len, char *buf, size_t *buflen); bool prepare_tcp_segment( @@ -41,12 +44,15 @@ bool prepare_tcp_segment( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint32_t *timestamps, uint8_t ttl, - enum tcp_fooling_mode fooling, + uint8_t fooling, const void *data, uint16_t len, char *buf, size_t *buflen); void extract_endpoints(const struct iphdr *iphdr,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr, 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); // auto creates internal socket and uses it for subsequent calls bool rawsend(struct sockaddr* dst,uint32_t fwmark,const void *data,size_t len); diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 520db18..737b625 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -91,7 +91,7 @@ struct params_s bool desync_retrans,desync_skip_nosni,desync_any_proto; int desync_split_pos; uint8_t desync_ttl; - enum tcp_fooling_mode desync_tcp_fooling_mode; + uint8_t desync_tcp_fooling_mode; uint32_t desync_fwmark; char hostfile[256]; strpool *hostlist; @@ -467,7 +467,7 @@ static bool modify_tcp_packet(uint8_t *data, size_t len, struct tcphdr *tcphdr) // result : true - drop original packet, false = dont drop -static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const struct iphdr *iphdr, const struct ip6_hdr *ip6hdr, const struct tcphdr *tcphdr, const uint8_t *data_payload, size_t len_payload) +static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *iphdr, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, uint8_t *data_payload, size_t len_payload) { if (!!iphdr == !!ip6hdr) return false; // one and only one must be present @@ -535,11 +535,12 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str uint8_t ttl_orig = iphdr ? iphdr->ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim; uint8_t ttl_fake = params.desync_ttl ? params.desync_ttl : ttl_orig; uint8_t flags_orig = *((uint8_t*)tcphdr+13); + uint32_t *timestamps = tcp_find_timestamps(tcphdr); switch(params.desync_mode) { case DESYNC_FAKE: - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq, tcphdr->window, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq, tcphdr->window, timestamps, ttl_fake,params.desync_tcp_fooling_mode, fake, fake_size, newdata, &newlen)) { @@ -548,7 +549,7 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str break; case DESYNC_RST: case DESYNC_RSTACK: - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (params.desync_mode==DESYNC_RSTACK ? TH_ACK:0), tcphdr->seq, tcphdr->ack_seq, tcphdr->window, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (params.desync_mode==DESYNC_RSTACK ? TH_ACK:0), tcphdr->seq, tcphdr->ack_seq, tcphdr->window, timestamps, ttl_fake,params.desync_tcp_fooling_mode, NULL, 0, newdata, &newlen)) { @@ -565,7 +566,7 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str if (split_posseq,split_pos), tcphdr->ack_seq, tcphdr->window, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->seq,split_pos), tcphdr->ack_seq, tcphdr->window, timestamps, ttl_orig,TCP_FOOL_NONE, data_payload+split_pos, len_payload-split_pos, newdata, &newlen) || !rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen)) @@ -579,7 +580,7 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str { DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu\n",split_pos-1, split_pos) fakeseg_len = sizeof(fakeseg); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq, tcphdr->window, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq, tcphdr->window, timestamps, ttl_fake,params.desync_tcp_fooling_mode, zeropkt, split_pos, fakeseg, &fakeseg_len) || !rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len)) @@ -591,7 +592,7 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu\n",split_pos-1, split_pos) newlen = sizeof(newdata); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq, tcphdr->window, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq, tcphdr->window, timestamps, ttl_orig,TCP_FOOL_NONE, data_payload, split_pos, newdata, &newlen) || !rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen)) @@ -734,7 +735,7 @@ static void exithelp() " --dpi-desync[=]\t\t\t; try to desync dpi state. modes : fake rst rstack disorder disorder2\n" " --dpi-desync-fwmark=\t; override fwmark for desync packet. default = 0x%08X\n" " --dpi-desync-ttl=\t\t\t; set ttl for desync packet\n" - " --dpi-desync-fooling=none|md5sig|badsum\n" + " --dpi-desync-fooling=none|md5sig|ts|badseq|badsum\t; can use multiple comma separated values\n" " --dpi-desync-retrans=0|1\t\t; 0(default)=reinject original data packet after fake 1=drop original data packet to force its retransmission\n" " --dpi-desync-skip-nosni=0|1\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n" " --dpi-desync-split-pos=<1..%zu>\t; (for disorder only) split TCP packet at specified position\n" @@ -911,16 +912,27 @@ int main(int argc, char **argv) params.desync_ttl = (uint8_t)atoi(optarg); break; case 13: /* dpi-desync-fooling */ - if (!strcmp(optarg,"none")) - params.desync_tcp_fooling_mode = TCP_FOOL_NONE; - else if (!strcmp(optarg,"md5sig")) - params.desync_tcp_fooling_mode = TCP_FOOL_MD5SIG; - else if (!strcmp(optarg,"badsum")) - params.desync_tcp_fooling_mode = TCP_FOOL_BADSUM; - else { - fprintf(stderr, "dpi-desync-fooling allowed values : none,md5sig,badsum\n"); - exit_clean(1); + char *e,*p = optarg; + while (p) + { + e = strchr(p,','); + if (e) *e++=0; + if (!strcmp(p,"md5sig")) + params.desync_tcp_fooling_mode |= TCP_FOOL_MD5SIG; + else if (!strcmp(p,"ts")) + params.desync_tcp_fooling_mode |= TCP_FOOL_TS; + else if (!strcmp(p,"badsum")) + params.desync_tcp_fooling_mode |= TCP_FOOL_BADSUM; + else if (!strcmp(p,"badseq")) + params.desync_tcp_fooling_mode |= TCP_FOOL_BADSEQ; + else if (strcmp(p,"none")) + { + fprintf(stderr, "dpi-desync-fooling allowed values : none,md5sig,ts,badseq,badsum\n"); + exit_clean(1); + } + p = e; + } } break; case 14: /* dpi-desync-retrans */ diff --git a/nfq/sec.c b/nfq/sec.c index 38612d2..019d2d9 100644 --- a/nfq/sec.c +++ b/nfq/sec.c @@ -5,26 +5,26 @@ #include #include -bool setpcap(cap_value_t *caps, int ncaps) +bool checkpcap(uint64_t caps) { - cap_t capabilities; + 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); - if (!(capabilities = cap_init())) - return false; + return !capget(&ch,cd) && (cd[0].effective & c0)==c0 && (cd[0].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].inheritable = 0; - if (ncaps && (cap_set_flag(capabilities, CAP_PERMITTED, ncaps, caps, CAP_SET) || - cap_set_flag(capabilities, CAP_EFFECTIVE, ncaps, caps, CAP_SET))) - { - cap_free(capabilities); - return false; - } - if (cap_set_proc(capabilities)) - { - cap_free(capabilities); - return false; - } - cap_free(capabilities); - return true; + return !capset(&ch,cd); } int getmaxcap() { @@ -40,27 +40,25 @@ int getmaxcap() } bool dropcaps() { - // must have CAP_SETPCAP at the end. its required to clear bounding set - cap_value_t cap_values[] = { CAP_NET_ADMIN,CAP_NET_RAW,CAP_SETPCAP }; - int capct = sizeof(cap_values) / sizeof(*cap_values); + uint64_t caps = (1< #include -bool setpcap(cap_value_t *caps, int ncaps); +bool setpcap(uint64_t caps); int getmaxcap(); bool dropcaps(); bool droproot(uid_t uid, gid_t gid); diff --git a/tpws/Makefile b/tpws/Makefile index 7094d43..b8a3430 100644 --- a/tpws/Makefile +++ b/tpws/Makefile @@ -1,6 +1,6 @@ CC ?= gcc CFLAGS += -std=c99 -s -O3 -LIBS = -lz -lcap +LIBS = -lz SRC_FILES = *.c all: tpws diff --git a/tpws/sec.c b/tpws/sec.c new file mode 100644 index 0000000..0cf2abc --- /dev/null +++ b/tpws/sec.c @@ -0,0 +1,126 @@ +#include +#include +#include "sec.h" +#include +#include +#include + +bool checkpcap(uint64_t caps) +{ + 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); + + return !capget(&ch,cd) && (cd[0].effective & c0)==c0 && (cd[0].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].inheritable = 0; + + return !capset(&ch,cd); +} +int getmaxcap() +{ + int maxcap = CAP_LAST_CAP; + FILE *F = fopen("/proc/sys/kernel/cap_last_cap", "r"); + if (F) + { + int n = fscanf(F, "%d", &maxcap); + fclose(F); + } + return maxcap; + +} +bool dropcaps() +{ + uint64_t caps = 0; + int maxcap = getmaxcap(); + + if (setpcap(caps|(1< +#include +#include + +bool setpcap(uint64_t caps); +int getmaxcap(); +bool dropcaps(); +bool droproot(uid_t uid, gid_t gid); +void daemonize(); +bool writepid(const char *filename); diff --git a/tpws/tpws.c b/tpws/tpws.c index 2b671b7..f1d855c 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include @@ -29,7 +27,8 @@ #include "tpws_conn.h" #include "hostlist.h" #include "params.h" - +#include "sec.h" + struct params_s params; bool bHup = false; @@ -422,128 +421,6 @@ void parse_params(int argc, char *argv[]) } } -static void daemonize() -{ - int pid,fd; - - pid = fork(); - if (pid == -1) - { - perror("fork: "); - exit(2); - } - else if (pid != 0) - exit(0); - - if (setsid() == -1) - exit(2); - if (chdir("/") == -1) - exit(2); - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - /* redirect fd's 0,1,2 to /dev/null */ - open("/dev/null", O_RDWR); - /* stdin */ - fd=dup(0); - /* stdout */ - fd=dup(0); - /* stderror */ -} - -static bool setpcap(cap_value_t *caps,int ncaps) -{ - cap_t capabilities; - - if (!(capabilities = cap_init())) - return false; - - if (ncaps && (cap_set_flag(capabilities, CAP_PERMITTED, ncaps, caps, CAP_SET) || - cap_set_flag(capabilities, CAP_EFFECTIVE, ncaps, caps, CAP_SET))) - { - cap_free(capabilities); - return false; - } - if (cap_set_proc(capabilities)) - { - cap_free(capabilities); - return false; - } - cap_free(capabilities); - return true; -} -static int getmaxcap() -{ - int maxcap = CAP_LAST_CAP; - FILE *F = fopen("/proc/sys/kernel/cap_last_cap","r"); - if (F) - { - int n=fscanf(F,"%d",&maxcap); - fclose(F); - } - return maxcap; - -} -static bool dropcaps() -{ - // must have CAP_SETPCAP at the end. its required to clear bounding set - cap_value_t cap_values[] = {CAP_SETPCAP}; - int capct=sizeof(cap_values)/sizeof(*cap_values); - int maxcap = getmaxcap(); - - if (setpcap(cap_values, capct)) - { - for(int cap=0;cap<=maxcap;cap++) - { - if (cap_drop_bound(cap)) - { - fprintf(stderr,"could not drop cap %d\n",cap); - perror("cap_drop_bound"); - } - } - } - // now without CAP_SETPCAP - if (!setpcap(cap_values, capct - 1)) - { - perror("setpcap"); - return false; - } - return true; -} -static bool droproot() -{ - if (params.uid || params.gid) - { - if (prctl(PR_SET_KEEPCAPS, 1L)) - { - perror("prctl(PR_SET_KEEPCAPS): "); - return false; - } - if (setgid(params.gid)) - { - perror("setgid: "); - return false; - } - if (setuid(params.uid)) - { - perror("setuid: "); - return false; - } - } - return dropcaps(); -} - - -static bool writepid(const char *filename) -{ - FILE *F; - if (!(F=fopen(filename,"w"))) - return false; - fprintf(F,"%d",getpid()); - fclose(F); - return true; -} - static bool find_listen_addr(struct sockaddr_storage *salisten, bool bindll, int *if_index) @@ -806,11 +683,11 @@ int main(int argc, char *argv[]) { set_ulimit(); - if (!droproot()) + if (!droproot(params.uid,params.gid)) { goto exiterr; } - + fprintf(stderr,"Running as UID=%u GID=%u\n",getuid(),getgid()); if (listen(listen_fd, BACKLOG) == -1) {