nfqws: preserve fwmark. bind-fix

This commit is contained in:
bol-van 2022-05-15 15:54:35 +03:00
parent ba5bde81a3
commit 877adbd6f6
17 changed files with 160 additions and 60 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -140,6 +140,8 @@ nfqws takes the following parameters:
```
--debug=0|1 ; 1=print debug info
--qnum=<nfqueue_number>
--bind-fix4 ; apply outgoing interface selection fix for generated ipv4 packets
--bind-fix6 ; apply outgoing interface selection fix for generated ipv6 packets
--wsize=<winsize>[:<scale_factor>] ; change window size in SYN,ACK packets. default is not to change scale factor (OBSOLETE !)
--wssize=<winsize>[:<scale_factor>] ; change window size in outgoing packets. default scale factor is 0. (see CONNTRACK)
--wssize-cutoff=[n|d|s]N ; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N

View File

@ -197,6 +197,8 @@ nfqws
--user=<username> ; менять uid процесса
--uid=uid[:gid] ; менять uid процесса
--qnum=N ; номер очереди N
--bind-fix4 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv4 пакетов
--bind-fix6 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv6 пакетов
--wsize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !)
--wssize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !)
--wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N

View File

@ -851,6 +851,7 @@ void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize, uint8_t scale_fac
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)
@ -934,7 +935,28 @@ static int rawsend_socket_raw(int domain, int proto)
return fd;
}
static int rawsend_socket(sa_family_t family,uint32_t fwmark)
static bool set_socket_fwmark(int sock, uint32_t fwmark)
{
#ifdef BSD
#ifdef SO_USER_COOKIE
if (setsockopt(sock, SOL_SOCKET, SO_USER_COOKIE, &fwmark, sizeof(fwmark)) == -1)
{
perror("rawsend: setsockopt(SO_USER_COOKIE)");
return false;
}
#endif
#elif defined(__linux__)
if (setsockopt(sock, SOL_SOCKET, SO_MARK, &fwmark, sizeof(fwmark)) == -1)
{
perror("rawsend: setsockopt(SO_MARK)");
return false;
}
#endif
return true;
}
static int rawsend_socket(sa_family_t family)
{
int yes=1;
int *sock = rawsend_family_sock(family);
@ -971,20 +993,8 @@ static int rawsend_socket(sa_family_t family,uint32_t fwmark)
goto exiterr;
}
#endif
#ifdef SO_USER_COOKIE
if (setsockopt(*sock, SOL_SOCKET, SO_USER_COOKIE, &fwmark, sizeof(fwmark)) == -1)
{
perror("rawsend: setsockopt(SO_MARK)");
goto exiterr;
}
#endif
#endif
#ifdef __linux__
if (setsockopt(*sock, SOL_SOCKET, SO_MARK, &fwmark, sizeof(fwmark)) == -1)
{
perror("rawsend: setsockopt(SO_MARK)");
goto exiterr;
}
if (setsockopt(*sock, SOL_SOCKET, SO_PRIORITY, &pri, sizeof(pri)) == -1)
{
perror("rawsend: setsockopt(SO_PRIORITY)");
@ -995,6 +1005,16 @@ static int rawsend_socket(sa_family_t family,uint32_t fwmark)
perror("rawsend: setsockopt(IP_NODEFRAG)");
goto exiterr;
}
if (family==AF_INET && setsockopt(*sock, IPPROTO_IP, IP_FREEBIND, &yes, sizeof(yes)) == -1)
{
perror("rawsend: setsockopt(IP_FREEBIND)");
goto exiterr;
}
if (family==AF_INET6 && setsockopt(*sock, SOL_IPV6, IPV6_FREEBIND, &yes, sizeof(yes)) == -1)
{
perror("rawsend: setsockopt(IPV6_FREEBIND)");
// dont error because it's supported only from kernel 4.15
}
#endif
}
return *sock;
@ -1002,14 +1022,17 @@ exiterr:
rawsend_clean_sock(sock);
return -1;
}
bool rawsend_preinit(uint32_t fwmark)
bool rawsend_preinit(bool bind_fix4, bool bind_fix6)
{
return rawsend_socket(AF_INET,fwmark)!=-1 && rawsend_socket(AF_INET6,fwmark)!=-1;
b_bind_fix4 = bind_fix4;
b_bind_fix6 = bind_fix6;
return rawsend_socket(AF_INET)!=-1 && rawsend_socket(AF_INET6)!=-1;
}
bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const void *data,size_t len)
bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len)
{
int sock=rawsend_socket(dst->sa_family,fwmark);
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;
@ -1028,7 +1051,7 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const void *data,size_t
v = ((struct ip6_hdr *)data)->ip6_ctlun.ip6_un1.ip6_un1_hlim;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &v, sizeof(v)) == -1)
perror("rawsend: setsockopt(IPV6_HOPLIMIT)");
[5~ // the only way to control source address is bind. make it equal to ip6_hdr
// the only way to control source address is bind. make it equal to ip6_hdr
if (bind(sock, (struct sockaddr*)&sa_src, salen) < 0)
perror("rawsend bind: ");
//printf("BSD v6 RAWSEND "); print_sockaddr((struct sockaddr*)&sa_src); printf(" -> "); print_sockaddr((struct sockaddr*)&dst2); printf("\n");
@ -1059,6 +1082,44 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const void *data,size_t
((struct ip*)data)->ip_off = htons(((struct ip*)data)->ip_off);
}
#endif
#if defined(__linux__)
struct sockaddr_storage sa_src;
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
}
//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)
{
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)))
{
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));
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)))
{
perror("rawsend: bind to any");
return false;
}
}
nofix:
#endif
// normal raw socket sendto
ssize_t bytes = sendto(sock, data, len, 0, (struct sockaddr*)&dst2, salen);
#if defined(__FreeBSD) && __FreeBSD__<=10

View File

@ -118,9 +118,9 @@ uint32_t *tcp_find_timestamps(struct tcphdr *tcp);
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp);
// auto creates internal socket and uses it for subsequent calls
bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const void *data,size_t len);
bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len);
// should pre-do it if dropping privileges. otherwise its not necessary
bool rawsend_preinit(uint32_t fwmark);
bool rawsend_preinit(bool bind_fix4, bool bind_fix6);
// cleans up socket autocreated by rawsend
void rawsend_cleanup();

View File

@ -122,10 +122,10 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
// auto creates internal socket and uses it for subsequent calls
static bool rawsend_rep(const struct sockaddr* dst,uint32_t fwmark,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;i<params.desync_repeats;i++)
if (!rawsend(dst,fwmark,data,len))
if (!rawsend(dst,fwmark,ifout,data,len))
return false;
return true;
}
@ -169,7 +169,7 @@ static void wssize_cutoff(t_ctrack *ctrack)
}
#define CONNTRACK_REQUIRED (params.wssize || params.desync_cutoff)
// result : true - drop original packet, false = dont drop
packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload)
packet_process_result dpi_desync_tcp_packet(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 len_tcp, uint8_t *data_payload, size_t len_payload)
{
packet_process_result res=pass;
t_ctrack *ctrack=NULL;
@ -200,6 +200,8 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
if (bReverse) return res; // nothing to do. do not waste cpu
uint32_t desync_fwmark = fwmark | params.desync_fwmark;
if (params.wssize)
{
if (ctrack)
@ -243,7 +245,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
}
DLOG("sending fake SYNACK\n");
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
}
@ -424,7 +426,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
}
DLOG("resending original packet with extension header\n");
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
// this mode is final, no other options available
return drop;
@ -434,7 +436,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
if (b)
{
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
if (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(params.desync_mode2))
{
@ -453,7 +455,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
if (res==modify)
#endif
tcp_fix_checksum(tcphdr,len_tcp,ip,ip6hdr);
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, data_pkt, len_pkt))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , data_pkt, len_pkt))
return res;
}
return drop;
@ -479,7 +481,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
DLOG("sending 2nd out-of-order 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, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
}
@ -493,7 +495,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
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, params.desync_fwmark, fakeseg, fakeseg_len))
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return res;
}
@ -505,14 +507,14 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
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, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
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, params.desync_fwmark, fakeseg, fakeseg_len))
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return res;
}
@ -534,7 +536,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
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, params.desync_fwmark, fakeseg, fakeseg_len))
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return res;
}
@ -545,14 +547,14 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
DLOG("sending 1st 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, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
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, params.desync_fwmark, fakeseg, fakeseg_len))
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return res;
}
@ -565,7 +567,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
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, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
}
@ -610,12 +612,12 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
DLOG("sending 1st ip fragment 0-%zu len=%zu : ", ipfrag_pos-1, ipfrag_pos)
hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n")
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt2, pkt2_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt2, pkt2_len))
return res;
DLOG("sending 2nd ip fragment %zu-%zu len=%zu : ", ipfrag_pos, len_tcp-1, len_tcp-ipfrag_pos)
hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n")
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
return frag;
@ -628,7 +630,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct udphdr *udphdr, uint8_t *data_payload, size_t len_payload)
packet_process_result dpi_desync_udp_packet(uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct udphdr *udphdr, uint8_t *data_payload, size_t len_payload)
{
packet_process_result res=pass;
t_ctrack *ctrack=NULL;
@ -760,6 +762,8 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
printf("\n");
}
uint32_t desync_fwmark = fwmark | params.desync_fwmark;
pkt1_len = sizeof(pkt1);
b = false;
switch(desync_mode)
@ -776,7 +780,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
DLOG("sending fake request : ");
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
b = true;
break;
@ -793,7 +797,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
return res;
}
DLOG("resending original packet with extension header\n");
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
// this mode is final, no other options available
return drop;
@ -815,7 +819,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
if (res==modify)
#endif
udp_fix_checksum(udphdr,sizeof(struct udphdr)+len_payload,ip,ip6hdr);
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, data_pkt, len_pkt))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , data_pkt, len_pkt))
return res;
return drop;
}
@ -829,7 +833,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,fooling_orig, params.udplen_increment, data_payload, len_payload, pkt1, &pkt1_len))
return res;
DLOG("resending original packet with increased by %u length\n", params.udplen_increment);
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
return drop;
case DESYNC_IPFRAG2:
@ -873,12 +877,12 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
DLOG("sending 1st ip fragment 0-%zu len=%zu : ", ipfrag_pos-1, ipfrag_pos)
hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n")
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt2, pkt2_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt2, pkt2_len))
return res;
DLOG("sending 2nd ip fragment %zu-%zu len=%zu : ", ipfrag_pos, len_transport-1, len_transport-ipfrag_pos)
hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n")
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return res;
return frag;

View File

@ -49,5 +49,5 @@ bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode);
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode);
void desync_init();
packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload);
packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct udphdr *udphdr, uint8_t *data_payload, size_t len_payload);
packet_process_result dpi_desync_tcp_packet(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 len_tcp, uint8_t *data_payload, size_t len_payload);
packet_process_result dpi_desync_udp_packet(uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct udphdr *udphdr, uint8_t *data_payload, size_t len_payload);

View File

@ -78,11 +78,7 @@ static void onusr1(int sig)
#ifdef __linux__
static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt, uint32_t *mark)
#else
static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt)
#endif
static packet_process_result processPacketData(uint32_t *mark, const char *ifout, uint8_t *data_pkt, size_t len_pkt)
{
struct ip *ip = NULL;
struct ip6_hdr *ip6hdr = NULL;
@ -143,7 +139,7 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
if (len) { DLOG("TCP: ") hexdump_limited_dlog(data, len, 32); DLOG("\n") }
res = dpi_desync_tcp_packet(data_pkt, len_pkt, ip, ip6hdr, tcphdr, len_with_th, data, len);
res = dpi_desync_tcp_packet(*mark, ifout, data_pkt, len_pkt, ip, ip6hdr, tcphdr, len_with_th, data, len);
// in my FreeBSD divert tests only ipv4 packets were reinjected with correct checksum
// ipv6 packets were with incorrect checksum
#ifdef __FreeBSD__
@ -168,7 +164,7 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
}
if (len) { DLOG("UDP: ") hexdump_limited_dlog(data, len, 32); DLOG("\n") }
res = dpi_desync_udp_packet(data_pkt, len_pkt, ip, ip6hdr, udphdr, data, len);
res = dpi_desync_udp_packet(*mark, ifout, data_pkt, len_pkt, ip, ip6hdr, udphdr, data, len);
#ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
if (res==modify || res!=frag && ip6hdr)
@ -187,23 +183,35 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
#ifdef __linux__
static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfa, void *cookie)
static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *cookie)
{
int id;
int len;
struct nfqnl_msg_packet_hdr *ph;
uint8_t *data;
uint32_t ifidx;
char ifout[IFNAMSIZ+1];
ph = nfq_get_msg_packet_hdr(nfa);
id = ph ? ntohl(ph->packet_id) : 0;
uint32_t mark = nfq_get_nfmark(nfa);
len = nfq_get_payload(nfa, &data);
DLOG("packet: id=%d len=%d\n", id, len)
*ifout=0;
if (params.bind_fix4 || params.bind_fix6)
{
ifidx = nfq_get_outdev(nfa);
if (ifidx) if_indextoname(ifidx,ifout);
DLOG("packet: id=%d len=%d ifout=%s(%u)\n", id, len, ifout, ifidx)
}
else
// save some syscalls
DLOG("packet: id=%d len=%d\n", id, len)
if (len >= 0)
{
switch (processPacketData(data, len, &mark))
switch (processPacketData(&mark, ifout, data, len))
{
case modify:
DLOG("packet: id=%d pass modified\n", id);
@ -266,6 +274,10 @@ static int nfq_main()
// dot not fail. not supported on old linuxes <3.6
}
printf("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;
if (params.droproot && !droproot(params.uid, params.gid))
goto exiterr;
print_id();
@ -378,8 +390,8 @@ static int dvt_main()
#endif
fdmax = (fd[0]>fd[1] ? fd[0] : fd[1]) + 1;
printf("initializing raw sockets with sockarg 0x%08X (%u)\n", params.desync_fwmark, params.desync_fwmark);
if (!rawsend_preinit(params.desync_fwmark))
printf("initializing raw sockets\n");
if (!rawsend_preinit(false,false))
goto exiterr;
if (params.droproot && !droproot(params.uid, params.gid))
@ -420,8 +432,9 @@ static int dvt_main()
}
else if (rd>0)
{
uint32_t mark=0;
DLOG("packet: id=%u len=%zd\n", id, rd)
ppr = processPacketData(buf, rd);
ppr = processPacketData(&mark, NULL, buf, rd);
switch (ppr)
{
case pass:
@ -497,6 +510,10 @@ static void exithelp()
" --pidfile=<filename>\t\t\t; write pid to file\n"
" --user=<username>\t\t\t; drop root privs\n"
" --uid=uid[:gid]\t\t\t; drop root privs\n"
#ifdef __linux__
" --bind-fix4\t\t\t\t; apply outgoing interface selection fix for generated ipv4 packets\n"
" --bind-fix6\t\t\t\t; apply outgoing interface selection fix for generated ipv6 packets\n"
#endif
" --wsize=<window_size>[:<scale_factor>]\t; set window size. 0 = do not modify. OBSOLETE !\n"
" --wssize=<window_size>[:<scale_factor>]; set window size for server. 0 = do not modify. default scale_factor = 0.\n"
" --wssize-cutoff=[n|d|s]N\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
@ -686,6 +703,10 @@ int main(int argc, char **argv)
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=33
{"dpi-desync-cutoff",required_argument,0,0},// optidx=34
{"hostlist",required_argument,0,0}, // optidx=35
#ifdef __linux__
{"bind-fix4",no_argument,0,0}, // optidx=36
{"bind-fix6",no_argument,0,0}, // optidx=37
#endif
{NULL,0,NULL,0}
};
if (argc < 2) exithelp();
@ -986,6 +1007,14 @@ int main(int argc, char **argv)
strncpy(params.hostfile,optarg,sizeof(params.hostfile));
params.hostfile[sizeof(params.hostfile)-1]='\0';
break;
#ifdef __linux__
case 36: /* bind-fix4 */
params.bind_fix4 = true;
break;
case 37: /* bind-fix6 */
params.bind_fix6 = true;
break;
#endif
}
}
// not specified - use desync_ttl value instead

View File

@ -7,6 +7,7 @@
#include <sys/param.h>
#include <sys/types.h>
#include <net/if.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
@ -37,6 +38,7 @@ struct params_s
#elif defined(BSD)
uint16_t port; // divert port
#endif
char bind_fix4,bind_fix6;
bool hostcase, hostnospace, domcase;
char hostspell[4];
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;