Browse Source

tpws,nfqws : remove cap library dependency

pull/53/head
bol-van 5 years ago
parent
commit
c69a31cc1d
  1. BIN
      binaries/aarch64/nfqws
  2. BIN
      binaries/aarch64/tpws
  3. BIN
      binaries/armhf/nfqws
  4. BIN
      binaries/armhf/tpws
  5. BIN
      binaries/mips32r1-lsb/nfqws
  6. BIN
      binaries/mips32r1-lsb/tpws
  7. BIN
      binaries/mips32r1-msb/nfqws
  8. BIN
      binaries/mips32r1-msb/tpws
  9. BIN
      binaries/mips64r2-msb/nfqws
  10. BIN
      binaries/mips64r2-msb/tpws
  11. BIN
      binaries/ppc/nfqws
  12. BIN
      binaries/ppc/tpws
  13. BIN
      binaries/x86/nfqws
  14. BIN
      binaries/x86/tpws
  15. BIN
      binaries/x86_64/nfqws
  16. BIN
      binaries/x86_64/tpws
  17. 2
      nfq/Makefile
  18. 146
      nfq/darkmagic.c
  19. 22
      nfq/darkmagic.h
  20. 46
      nfq/nfqws.c
  21. 48
      nfq/sec.c
  22. 2
      nfq/sec.h
  23. 2
      tpws/Makefile
  24. 126
      tpws/sec.c
  25. 12
      tpws/sec.h
  26. 131
      tpws/tpws.c

BIN
binaries/aarch64/nfqws

Binary file not shown.

BIN
binaries/aarch64/tpws

Binary file not shown.

BIN
binaries/armhf/nfqws

Binary file not shown.

BIN
binaries/armhf/tpws

Binary file not shown.

BIN
binaries/mips32r1-lsb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-lsb/tpws

Binary file not shown.

BIN
binaries/mips32r1-msb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-msb/tpws

Binary file not shown.

BIN
binaries/mips64r2-msb/nfqws

Binary file not shown.

BIN
binaries/mips64r2-msb/tpws

Binary file not shown.

BIN
binaries/ppc/nfqws

Binary file not shown.

BIN
binaries/ppc/tpws

Binary file not shown.

BIN
binaries/x86/nfqws

Binary file not shown.

BIN
binaries/x86/tpws

Binary file not shown.

BIN
binaries/x86_64/nfqws

Binary file not shown.

BIN
binaries/x86_64/tpws

Binary file not shown.

2
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

146
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)
{
switch(*t)
{
case 0: // end
break;
case 1: // noop
t++;
break;
default: // kind,len,data
if ((t+1)>=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;
static int rawsend_sock4=-1, rawsend_sock6=-1;
static void rawsend_clean_sock(int *sock)
{
if (sock && *sock!=-1)
{
close(*sock);
*sock=-1;
}
}
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)
{
close(rawsend_sock);
rawsend_sock=-1;
case AF_INET: return &rawsend_sock4;
case AF_INET6: return &rawsend_sock6;
default: return NULL;
}
}
static void rawsend_socket(int family,uint32_t fwmark)
static int rawsend_socket(int family,uint32_t fwmark)
{
if (rawsend_sock==-1)
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;
}

22
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);

46
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_pos<len_payload)
{
DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu\n",split_pos,len_payload-1, len_payload-split_pos)
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->seq,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[=<mode>]\t\t\t; try to desync dpi state. modes : fake rst rstack disorder disorder2\n"
" --dpi-desync-fwmark=<int|0xHEX>\t; override fwmark for desync packet. default = 0x%08X\n"
" --dpi-desync-ttl=<int>\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 */

48
nfq/sec.c

@ -5,26 +5,26 @@
#include <unistd.h>
#include <fcntl.h>
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<<CAP_NET_ADMIN)|(1<<CAP_NET_RAW);
int maxcap = getmaxcap();
if (setpcap(cap_values, capct))
if (setpcap(caps|(1<<CAP_SETPCAP)))
{
for (int cap = 0; cap <= maxcap; cap++)
{
if (cap_drop_bound(cap))
if (prctl(PR_CAPBSET_DROP, cap)<0)
{
fprintf(stderr, "could not drop cap %d\n", cap);
fprintf(stderr, "could not drop bound cap %d\n", cap);
perror("cap_drop_bound");
}
}
}
// now without CAP_SETPCAP
if (!setpcap(cap_values, capct - 1))
if (!setpcap(caps))
{
perror("setpcap");
return false;
return checkpcap(caps);
}
return true;
}

2
nfq/sec.h

@ -4,7 +4,7 @@
#include <sys/types.h>
#include <stdbool.h>
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);

2
tpws/Makefile

@ -1,6 +1,6 @@
CC ?= gcc
CFLAGS += -std=c99 -s -O3
LIBS = -lz -lcap
LIBS = -lz
SRC_FILES = *.c
all: tpws

126
tpws/sec.c

@ -0,0 +1,126 @@
#include <stdio.h>
#include <stdlib.h>
#include "sec.h"
#include <sys/prctl.h>
#include <unistd.h>
#include <fcntl.h>
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<<CAP_SETPCAP)))
{
for (int cap = 0; cap <= maxcap; cap++)
{
if (prctl(PR_CAPBSET_DROP, cap)<0)
{
fprintf(stderr, "could not drop bound cap %d\n", cap);
perror("cap_drop_bound");
}
}
}
// now without CAP_SETPCAP
if (!setpcap(caps))
{
perror("setpcap");
return checkpcap(caps);
}
return true;
}
bool droproot(uid_t uid, gid_t gid)
{
if (uid || gid)
{
if (prctl(PR_SET_KEEPCAPS, 1L))
{
perror("prctl(PR_SET_KEEPCAPS): ");
return false;
}
if (setgid(gid))
{
perror("setgid: ");
return false;
}
if (setuid(uid))
{
perror("setuid: ");
return false;
}
}
return dropcaps();
}
void daemonize()
{
int pid;
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);
int fd;
/* stdin */
fd = dup(0);
/* stdout */
fd = dup(0);
/* stderror */
}
bool writepid(const char *filename)
{
FILE *F;
if (!(F = fopen(filename, "w")))
return false;
fprintf(F, "%d", getpid());
fclose(F);
return true;
}

12
tpws/sec.h

@ -0,0 +1,12 @@
#pragma once
#include <sys/capability.h>
#include <sys/types.h>
#include <stdbool.h>
bool setpcap(uint64_t caps);
int getmaxcap();
bool dropcaps();
bool droproot(uid_t uid, gid_t gid);
void daemonize();
bool writepid(const char *filename);

131
tpws/tpws.c

@ -20,8 +20,6 @@
#include <netinet/tcp.h>
#include <getopt.h>
#include <pwd.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <time.h>
@ -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) {

Loading…
Cancel
Save