diff --git a/blockcheck.sh b/blockcheck.sh index 9ee3184..dca4bad 100755 --- a/blockcheck.sh +++ b/blockcheck.sh @@ -45,7 +45,6 @@ HTTP_PORT=${HTTP_PORT:-80} HTTPS_PORT=${HTTPS_PORT:-443} QUIC_PORT=${QUIC_PORT:-443} UNBLOCKED_DOM=${UNBLOCKED_DOM:-iana.org} -[ "$CURL_VERBOSE" = 1 ] && CURL_CMD=1 HDRTEMP=/tmp/zapret-hdr.txt @@ -792,7 +791,7 @@ pktws_ipt_prepare() # disable PF to avoid interferences pf_is_avail && pfctl -qd for ip in $3; do - IPFW_ADD divert $IPFW_DIVERT_PORT $1 from me to $ip $2 proto ip${IPV} out not diverted not sockarg + IPFW_ADD divert $IPFW_DIVERT_PORT $1 from me to $ip $2 proto ip${IPV} out not diverted done ;; opf) @@ -867,7 +866,7 @@ pktws_ipt_prepare_tcp() ;; ipfw) for ip in $2; do - IPFW_ADD divert $IPFW_DIVERT_PORT tcp from $ip $1 to me proto ip${IPV} tcpflags syn,ack in not diverted not sockarg + IPFW_ADD divert $IPFW_DIVERT_PORT tcp from $ip $1 to me proto ip${IPV} tcpflags syn,ack in not diverted done ;; esac @@ -994,7 +993,6 @@ ws_curl_test() # $2 - test function # $3 - domain # $4,$5,$6, ... - ws params - local code ws_start=$1 testf=$2 dom=$3 shift shift @@ -1088,7 +1086,7 @@ test_has_split() } test_has_fake() { - contains "$1" fake + [ "$1" = fake ] || starts_with "$1" fake, } warn_fool() { @@ -1105,25 +1103,34 @@ pktws_curl_test_update_vary() # $4 - desync mode # $5,$6,... - strategy - local testf=$1 sec=$2 domain=$3 desync=$4 zerofake split fake + local testf=$1 sec=$2 domain=$3 desync=$4 proto zerofake= splits= pos fake ret=1 shift; shift; shift; shift - zerofake=http - [ "$sec" = 0 ] || zerofake=tls - zerofake="--dpi-desync-fake-$zerofake=0x00000000" - + proto=http + [ "$sec" = 0 ] || proto=tls + test_has_fake $desync && zerofake="--dpi-desync-fake-$proto=0x00000000" + test_has_split $desync && { + splits="method+2 midsld" + [ "$sec" = 0 ] || splits="1 midsld 1,midsld" + } for fake in '' $zerofake ; do - for split in '' '--dpi-desync-split-pos=1' ; do - pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" $fake $split && return 0 - # split-pos=1 is meaningful for DPIs searching for 16 03 in TLS. no reason to apply to http - [ "$sec" = 1 ] || break - test_has_split $desync || break - done - test_has_fake $desync || break + if [ -n "$splits" ]; then + for pos in $splits ; do + pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" --dpi-desync-split-pos=$pos $fake && { + [ "$SCANLEVEL" = force ] || return 0 + ret=0 + } + done + else + pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" $fake && { + [ "$SCANLEVEL" = force ] || return 0 + ret=0 + } + fi done - return 1 + return $ret } pktws_check_domain_http_bypass_() @@ -1132,7 +1139,10 @@ pktws_check_domain_http_bypass_() # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk # $3 - domain - local tests='fake' ret ok ttls s f e desync pos fooling frag sec="$2" delta hostcase + local ok ttls s f f2 e desync pos fooling frag sec="$2" delta splits + local need_split need_disorder need_fakedsplit need_fakeddisorder need_fake need_wssize + local splits_http='method+2 midsld method+2,midsld' + local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1' [ "$sec" = 0 ] && { for s in '--hostcase' '--hostspell=hoSt' '--hostnospace' '--domcase'; do @@ -1140,74 +1150,62 @@ pktws_check_domain_http_bypass_() done } - s="--dpi-desync=split2" - ok=0 - pktws_curl_test_update $1 $3 $s - ret=$? - [ "$ret" = 0 ] && { - [ "$SCANLEVEL" = quick ] && return - ok=1 - } - [ "$ret" != 0 -o "$SCANLEVEL" = force ] && { - if [ "$sec" = 0 ]; then - pktws_curl_test_update $1 $3 $s --hostcase && { - [ "$SCANLEVEL" = quick ] && return - ok=1 - } - for pos in method host; do - for hostcase in '' '--hostcase'; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-http-req=$pos $hostcase && { - [ "$SCANLEVEL" = quick ] && return - ok=1 - } - done - done - else - for pos in sni sniext; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-tls=$pos && { - [ "$SCANLEVEL" = quick ] && return - ok=1 - } - done - fi - for pos in 1 3 4 5 10 50; do - s="--dpi-desync=split2 --dpi-desync-split-pos=$pos" - if pktws_curl_test_update $1 $3 $s; then - [ "$SCANLEVEL" = quick ] && return - ok=1 - [ "$SCANLEVEL" = force ] || break - elif [ "$sec" = 0 ]; then - pktws_curl_test_update $1 $3 $s --hostcase && [ "$SCANLEVEL" = quick ] && return - fi - done - } - [ "$ok" = 1 -a "$SCANLEVEL" != force ] || tests="$tests split fake,split2 fake,split" - - pktws_curl_test_update $1 $3 --dpi-desync=disorder2 - ret=$? - [ "$ret" = 0 -a "$SCANLEVEL" = quick ] && return - [ "$ret" != 0 -o "$SCANLEVEL" = force ] && { - pktws_curl_test_update $1 $3 --dpi-desync=disorder2 --dpi-desync-split-pos=1 - ret=$? - [ "$ret" = 0 -a "$SCANLEVEL" = quick ] && return - } - [ "$ret" != 0 -o "$SCANLEVEL" = force ] && tests="$tests disorder fake,disorder2 fake,disorder" - ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL) + need_wssize=1 for e in '' '--wssize 1:6'; do + need_split= + need_disorder= + [ -n "$e" ] && { pktws_curl_test_update $1 $3 $e && [ "$SCANLEVEL" = quick ] && return - for desync in split2 disorder2; do - pktws_curl_test_update_vary $1 $2 $3 $desync $e && [ "$SCANLEVEL" = quick ] && return - done } - for desync in $tests; do + + for desync in multisplit multidisorder; do + ok=0 + splits="$splits_http" + [ "$sec" = 0 ] || splits="$splits_tls" + for pos in $splits; do + pktws_curl_test_update $1 $3 --dpi-desync=$desync --dpi-desync-split-pos=$pos $e && { + [ "$SCANLEVEL" = quick ] && return + ok=1 + need_wssize=0 + [ "$SCANLEVEL" = force ] || break + } + done + [ "$ok" = 1 -a "$SCANLEVEL" != force ] || { + case $desync in + multisplit) + need_split=1 + ;; + multidisorder) + need_disorder=1 + ;; + esac + } + done + + need_fakedsplit=1 + need_fakeddisorder=1 + need_fake=1 + for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do + [ "$need_fake" = 0 ] && test_has_fake "$desync" && continue + [ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue + [ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue + ok=0 for ttl in $ttls; do pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=$ttl $e && { [ "$SCANLEVEL" = quick ] && return + ok=1 + need_wssize=0 break } done + # only skip tests if TTL succeeded. do not skip if TTL failed but fooling succeeded + [ $ok = 1 -a "$SCANLEVEL" != force ] && { + [ "$desync" = fake ] && need_fake=0 + [ "$desync" = fakedsplit ] && need_fakedsplit=0 + [ "$desync" = fakeddisorder ] && need_fakeddisorder=0 + } f= [ "$UNAME" = "OpenBSD" ] || f="badsum" f="$f badseq datanoack md5sig" @@ -1216,37 +1214,68 @@ pktws_check_domain_http_bypass_() pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && { warn_fool $fooling [ "$SCANLEVEL" = quick ] && return + need_wssize=0 } done done + [ "$IPV" = 6 ] && { - f="hopbyhop hopbyhop,split2 hopbyhop,disorder2 destopt destopt,split2 destopt,disorder2" - [ -n "$IP6_DEFRAG_DISABLE" ] && f="$f ipfrag1 ipfrag1,split2 ipfrag1,disorder2" + f="hopbyhop ${need_split:+hopbyhop,multisplit} ${need_disorder:+hopbyhop,multidisorder} destopt ${need_split:+destopt,multisplit} ${need_disorder:+destopt,multidisorder}" + [ -n "$IP6_DEFRAG_DISABLE" ] && f="$f ipfrag1 ${need_split:+ ipfrag1,multisplit} ${need_disorder:+ ipfrag1,multidisorder}" for desync in $f; do - pktws_curl_test_update_vary $1 $2 $3 $desync $e && [ "$SCANLEVEL" = quick ] && return + pktws_curl_test_update_vary $1 $2 $3 $desync $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } done } - for desync in split2 disorder2; do - s="--dpi-desync=$desync" + [ "$need_split" = 1 ] && { + # relative markers can be anywhere, even in subsequent packets. first packet can be MTU-full. + # make additional split pos "10" to guarantee enough space for seqovl and likely to be before midsld,sniext,... + # method is always expected in the beginning of the first packet + f="method+2 method+2,midsld" + [ "$sec" = 0 ] || f="10 10,sniext+1 10,sniext+4 10,midsld" + for pos in $f; do + pktws_curl_test_update $1 $3 --dpi-desync=multisplit --dpi-desync-split-pos=$pos --dpi-desync-split-seqovl=1 $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + done + [ "$sec" != 0 ] && pktws_curl_test_update $1 $3 --dpi-desync=multisplit --dpi-desync-split-pos=2 --dpi-desync-split-seqovl=336 --dpi-desync-split-seqovl-pattern="$ZAPRET_BASE/files/fake/tls_clienthello_iana_org.bin" $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + } + [ "$need_disorder" = 1 ] && { if [ "$sec" = 0 ]; then - for pos in method host; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-seqovl=1 --dpi-desync-split-http-req=$pos $e && [ "$SCANLEVEL" = quick ] && return + for pos in 'method+1 method+2' 'midsld-1 midsld' 'method+1 method+2,midsld'; do + f="$(extract_arg 1 $pos)" + f2="$(extract_arg 2 $pos)" + pktws_curl_test_update $1 $3 --dpi-desync=multidisorder --dpi-desync-split-pos=$f2 --dpi-desync-split-seqovl=$f $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } done else - for pos in sni sniext; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-seqovl=1 --dpi-desync-split-tls=$pos $e && [ "$SCANLEVEL" = quick ] && return + for pos in '1 2' 'sniext sniext+1' 'sniext+3 sniext+4' 'midsld-1 midsld' '1 2,midsld'; do + f=$(extract_arg 1 $pos) + f2=$(extract_arg 2 $pos) + pktws_curl_test_update $1 $3 --dpi-desync=multidisorder --dpi-desync-split-pos=$f2 --dpi-desync-split-seqovl=$f $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } done fi - for pos in 2 3 4 5 10 50; do - pktws_curl_test_update $1 $3 $s --dpi-desync-split-seqovl=$(($pos - 1)) --dpi-desync-split-pos=$pos $e && [ "$SCANLEVEL" = quick ] && return - done - [ "$sec" != 0 -a $desync = split2 ] && { - pktws_curl_test_update $1 $3 $s --dpi-desync-split-seqovl=336 --dpi-desync-split-seqovl-pattern="$ZAPRET_BASE/files/fake/tls_clienthello_iana_org.bin" $e && [ "$SCANLEVEL" = quick ] && return - } - done + } - for desync in $tests; do + need_fakedsplit=1 + need_fakeddisorder=1 + need_fake=1 + for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do + [ "$need_fake" = 0 ] && test_has_fake "$desync" && continue + [ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue + [ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue ok=0 for delta in 1 2 3 4 5; do pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=1 --dpi-desync-autottl=$delta $e && ok=1 @@ -1256,18 +1285,25 @@ pktws_check_domain_http_bypass_() echo "WARNING ! although autottl worked it requires testing on multiple domains to find out reliable delta" echo "WARNING ! if a reliable delta cannot be found it's a good idea not to use autottl" [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + [ "$SCANLEVEL" = force ] || { + [ "$desync" = fake ] && need_fake=0 + [ "$desync" = fakedsplit ] && need_fakedsplit=0 + [ "$desync" = fakeddisorder ] && need_fakeddisorder=0 + } } done s="http_iana_org.bin" [ "$sec" = 0 ] || s="tls_clienthello_iana_org.bin" - for desync in syndata syndata,split2 syndata,disorder2 ; do + for desync in syndata ${need_split:+syndata,multisplit} ${need_disorder:+syndata,multidisorder} ; do pktws_curl_test_update_vary $1 $2 $3 $desync $e && [ "$SCANLEVEL" = quick ] && return pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fake-syndata="$ZAPRET_BASE/files/fake/$s" $e && [ "$SCANLEVEL" = quick ] && return done # do not do wssize test for http and TLS 1.3. it's useless [ "$sec" = 1 ] || break + [ "$SCANLEVEL" = force -o "$need_wssize" = 1 ] || break done } pktws_check_domain_http_bypass() @@ -1338,15 +1374,28 @@ tpws_check_domain_http_bypass_() # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk # $3 - domain - local s mss s2 s3 pos sec="$2" + local s mss s2 s3 oobdis pos sec="$2" + local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld,endhost-1' + local splits_http='method+2 midsld method+2,midsld' + + # simulteneous oob and disorder works properly only in linux. other systems retransmit oob byte without URG tcp flag and poison tcp stream. + [ "$UNAME" = Linux ] && oobdis='--oob --disorder' if [ "$sec" = 0 ]; then - for s in '--hostcase' '--hostspell=hoSt' '--hostdot' '--hosttab' '--hostnospace' '--domcase' \ - '--hostpad=1024' '--hostpad=2048' '--hostpad=4096' '--hostpad=8192' '--hostpad=16384' ; do + for s in '--hostcase' '--hostspell=hoSt' '--hostdot' '--hosttab' '--hostnospace' '--domcase' ; do tpws_curl_test_update $1 $3 $s && [ "$SCANLEVEL" = quick ] && return done - for s2 in '' '--oob' '--disorder' '--oob --disorder'; do - for s in '--split-http-req=method' '--split-http-req=method --hostcase' '--split-http-req=host' '--split-http-req=host --hostcase' ; do - tpws_curl_test_update $1 $3 $s $s2 && [ "$SCANLEVEL" = quick ] && return + for s in 1024 2048 4096 8192 16384 ; do + tpws_curl_test_update $1 $3 --hostpad=$s && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + break + } + done + for s2 in '' '--hostcase' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do + for s in $splits_http ; do + tpws_curl_test_update $1 $3 --split-pos=$s $s2 && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + break + } done done for s in '--methodspace' '--unixeol' '--methodeol'; do @@ -1355,30 +1404,21 @@ tpws_check_domain_http_bypass_() else for mss in '' 88; do s3=${mss:+--mss=$mss} - for s2 in '' '--oob' '--disorder' '--oob --disorder'; do - for pos in sni sniext; do - s="--split-tls=$pos" - tpws_curl_test_update $1 $3 $s $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { - [ "$SCANLEVEL" = quick ] && return - break - } - done - for pos in 1 2 3 4 5 10 50; do - s="--split-pos=$pos" - tpws_curl_test_update $1 $3 $s $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { + for s2 in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do + for pos in $splits_tls; do + tpws_curl_test_update $1 $3 --split-pos=$pos $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { [ "$SCANLEVEL" = quick ] && return break } done done - for s2 in '--tlsrec=sni' '--tlsrec=sni --split-tls=sni' '--tlsrec=sni --split-tls=sni --oob' \ - '--tlsrec=sni --split-tls=sni --disorder' '--tlsrec=sni --split-tls=sni --oob --disorder' \ - '--tlsrec=sni --split-pos=1' '--tlsrec=sni --split-pos=1 --oob' '--tlsrec=sni --split-pos=1 --disorder' \ - '--tlsrec=sni --split-pos=1 --oob --disorder'; do - tpws_curl_test_update $1 $3 $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { - [ "$SCANLEVEL" = quick ] && return - break - } + for s in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do + for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+4 --split-pos=midsld' '--tlsrec=sniext+1 --split-pos=1,midsld' '--tlsrec=sniext+4 --split-pos=1,midsld' ; do + tpws_curl_test_update $1 $3 $s2 $s $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + break + } + done done # only linux supports mss [ "$UNAME" = Linux -a "$sec" = 1 ] || break @@ -1682,17 +1722,6 @@ ask_params() echo "installed curl version does not support http3 QUIC. tests disabled." fi - IGNORE_CA=0 - CURL_OPT= - [ $ENABLE_HTTPS_TLS13 = 1 -o $ENABLE_HTTPS_TLS12 = 1 ] && { - echo - echo "on limited systems like openwrt CA certificates might not be installed to preserve space" - echo "in such a case curl cannot verify server certificate and you should either install ca-bundle or disable verification" - echo "however disabling verification will break https check if ISP does MitM attack and substitutes server certificate" - ask_yes_no_var IGNORE_CA "do not verify server certificate" - [ "$IGNORE_CA" = 1 ] && CURL_OPT=-k - } - echo echo "sometimes ISPs use multiple DPIs or load balancing. bypass strategies may work unstable." printf "how many times to repeat each test (default: 1) : " diff --git a/common/base.sh b/common/base.sh index 8d466cc..c8e4be9 100644 --- a/common/base.sh +++ b/common/base.sh @@ -60,11 +60,22 @@ starts_with() esac return 1 } +extract_arg() +{ + # $1 - arg number + # $2,$3,... - args + local n=$1 + while [ -n "$1" ]; do + shift + [ $n -eq 1 ] && { echo "$1"; return 0; } + n=$(($n-1)) + done + return 1 +} find_str_in_list() { # $1 - string # $2 - space separated values - local v [ -n "$1" ] && { for v in $2; do diff --git a/common/installer.sh b/common/installer.sh index 2f3a3b6..9948cd2 100644 --- a/common/installer.sh +++ b/common/installer.sh @@ -221,7 +221,7 @@ check_system() else echo system is not either systemd, openrc or openwrt based echo easy installer can set up config settings but can\'t configure auto start - echo you have to do it manually. check readme.txt for manual setup info. + echo you have to do it manually. check readme.md for manual setup info. if [ -n "$1" ] || ask_yes_no N "do you want to continue"; then SYSTEM=linux else @@ -232,7 +232,7 @@ check_system() elif [ "$UNAME" = "Darwin" ]; then SYSTEM=macos else - echo easy installer only supports Linux and MacOS. check readme.txt for supported systems and manual setup info. + echo easy installer only supports Linux and MacOS. check readme.md for supported systems and manual setup info. exitp 5 fi echo system is based on $SYSTEM diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index 5a583b0..be03de8 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -163,7 +163,7 @@ static void fill_udphdr(struct udphdr *udp, uint16_t nsport, uint16_t ndport, ui udp->uh_sum = 0; } -static void fill_iphdr(struct ip *ip, const struct in_addr *src, const struct in_addr *dst, uint16_t pktlen, uint8_t proto, uint8_t ttl, uint8_t tos) +static void fill_iphdr(struct ip *ip, const struct in_addr *src, const struct in_addr *dst, uint16_t pktlen, uint8_t proto, uint8_t ttl, uint8_t tos, uint16_t ip_id) { ip->ip_tos = tos; ip->ip_sum = 0; @@ -171,7 +171,7 @@ static void fill_iphdr(struct ip *ip, const struct in_addr *src, const struct in ip->ip_v = 4; ip->ip_hl = 5; ip->ip_len = htons(pktlen); - ip->ip_id = 0; + ip->ip_id = ip_id; ip->ip_ttl = ttl; ip->ip_p = proto; ip->ip_src = *src; @@ -196,6 +196,7 @@ bool prepare_tcp_segment4( uint32_t *timestamps, uint8_t ttl, uint8_t tos, + uint16_t ip_id, uint32_t fooling, uint32_t badseq_increment, uint32_t badseq_ack_increment, @@ -211,7 +212,7 @@ bool prepare_tcp_segment4( 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, tos); + fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, ttl, tos, ip_id); 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); @@ -314,7 +315,9 @@ bool prepare_tcp_segment( uint8_t scale_factor, uint32_t *timestamps, uint8_t ttl, - uint8_t tos, uint32_t flow_label, + uint8_t tos, + uint16_t ip_id, + uint32_t flow_label, uint32_t fooling, uint32_t badseq_increment, uint32_t badseq_ack_increment, @@ -322,7 +325,7 @@ bool prepare_tcp_segment( 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,tos,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) : + prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,tos,ip_id,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,flow_label,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) : false; @@ -334,6 +337,7 @@ bool prepare_udp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, uint8_t ttl, uint8_t tos, + uint16_t ip_id, uint32_t fooling, const uint8_t *padding, size_t padding_size, int padlen, @@ -357,7 +361,7 @@ bool prepare_udp_segment4( uint8_t *payload = (uint8_t*)(udp+1); - fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, ttl, tos); + fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, ttl, tos, ip_id); fill_udphdr(udp, src->sin_port, dst->sin_port, datalen); memcpy(payload,data,len); @@ -463,7 +467,9 @@ bool prepare_udp_segment6( bool prepare_udp_segment( const struct sockaddr *src, const struct sockaddr *dst, uint8_t ttl, - uint8_t tos, uint32_t flow_label, + uint8_t tos, + uint16_t ip_id, + uint32_t flow_label, uint32_t fooling, const uint8_t *padding, size_t padding_size, int padlen, @@ -471,7 +477,7 @@ bool prepare_udp_segment( 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,tos,fooling,padding,padding_size,padlen,data,len,buf,buflen) : + prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,ttl,tos,ip_id,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,flow_label,fooling,padding,padding_size,padlen,data,len,buf,buflen) : false; diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index 1426682..42f7902 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -61,6 +61,7 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment); #define VERDICT_NOCSUM 4 #define IP4_TOS(ip_header) (ip_header ? ip_header->ip_tos : 0) +#define IP4_IP_ID(ip_header) (ip_header ? ip_header->ip_id : 0) #define IP6_FLOW(ip6_header) (ip6_header ? ip6_header->ip6_ctlun.ip6_un1.ip6_un1_flow : 0) // seq and wsize have network byte order @@ -73,6 +74,7 @@ bool prepare_tcp_segment4( uint32_t *timestamps, uint8_t ttl, uint8_t tos, + uint16_t ip_id, uint32_t fooling, uint32_t badseq_increment, uint32_t badseq_ack_increment, @@ -100,7 +102,9 @@ bool prepare_tcp_segment( uint8_t scale_factor, uint32_t *timestamps, uint8_t ttl, - uint8_t tos, uint32_t flow_label, + uint8_t tos, + uint16_t ip_id, + uint32_t flow_label, uint32_t fooling, uint32_t badseq_increment, uint32_t badseq_ack_increment, @@ -112,6 +116,7 @@ bool prepare_udp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, uint8_t ttl, uint8_t tos, + uint16_t ip_id, uint32_t fooling, const uint8_t *padding, size_t padding_size, int padlen, @@ -129,7 +134,9 @@ bool prepare_udp_segment6( bool prepare_udp_segment( const struct sockaddr *src, const struct sockaddr *dst, uint8_t ttl, - uint8_t tos, uint32_t flow_label, + uint8_t tos, + uint16_t ip_id, + uint32_t flow_label, uint32_t fooling, const uint8_t *padding, size_t padding_size, int padlen, diff --git a/nfq/desync.c b/nfq/desync.c index a46071d..f201f38 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -603,6 +603,22 @@ static void autottl_discover(t_ctrack *ctrack, bool bIpv6) } } +#ifdef BSD +// BSD pass to divert socket ip_id=0 and does not auto set it if sent via divert socket +static uint16_t IP4_IP_ID_FIX(const struct ip *ip) +{ + return ip ? ip->ip_id ? ip->ip_id : (uint16_t)random() : 0; +} +#define IP4_IP_ID_NEXT(ip_id) net16_add(ip_id,+1) +#define IP4_IP_ID_PREV(ip_id) net16_add(ip_id,-1) +#else +// in linux kernel sets increasing ip_id if it's zero +#define IP4_IP_ID_FIX(x) 0 +#define IP4_IP_ID_NEXT(ip_id) ip_id +#define IP4_IP_ID_PREV(ip_id) ip_id +#endif + + static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, struct dissect *dis) { uint8_t verdict=VERDICT_PASS; @@ -787,7 +803,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint case DESYNC_SYNACK: pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, NULL, 0, pkt1, &pkt1_len)) { @@ -811,7 +827,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), 0,0,0, dp->fake_syndata,dp->fake_syndata_size, pkt1,&pkt1_len)) { return verdict; @@ -844,6 +860,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint size_t multisplit_pos[MAX_SPLITS]; int multisplit_count; int i; + uint16_t ip_id; t_l7proto l7proto = UNKNOWN; if (replay) @@ -1165,7 +1182,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint DLOG("all multisplit pos are outside of this packet\n"); } } - seqovl_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, &dp->seqovl); } else if (dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER) { @@ -1187,15 +1203,26 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint DLOG("normalized regular split pos : %zu\n",split_pos); else DLOG("regular split pos is outside of this packet\n"); - seqovl_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, &dp->seqovl); } else { multisplit_count=0; - split_pos = seqovl_pos = 0; + split_pos = 0; } - seqovl_pos = pos_normalize(seqovl_pos,reasm_offset,dis->len_payload); - if (seqovl_pos) DLOG("normalized seqovl pos : %zu\n",seqovl_pos); + if (dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_MULTISPLIT) + { + // split seqovl only uses absolute positive values + seqovl_pos = (dp->seqovl.marker==PM_ABS && dp->seqovl.pos>0) ? dp->seqovl.pos : 0; + if (seqovl_pos) DLOG("seqovl : %zu\n",seqovl_pos); + } + else if (dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_MULTIDISORDER) + { + seqovl_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, &dp->seqovl); + seqovl_pos = pos_normalize(seqovl_pos,reasm_offset,dis->len_payload); + if (seqovl_pos) DLOG("normalized seqovl : %zu\n",seqovl_pos); + } + else + seqovl_pos = 0; // we do not need reasm buffer anymore reasm_orig_cancel(ctrack); @@ -1216,7 +1243,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint case DESYNC_FAKE: if (reasm_offset) break; if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, fake, fake_size, pkt1, &pkt1_len)) { @@ -1230,7 +1257,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint case DESYNC_RSTACK: if (reasm_offset) break; if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, NULL, 0, pkt1, &pkt1_len)) { @@ -1248,7 +1275,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint (!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)))) { if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), fooling_orig,0,0, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) { @@ -1280,6 +1307,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint uint8_t ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg; size_t seg_len,from,to; unsigned int seqovl; + + ip_id = IP4_IP_ID_FIX(dis->ip); + for (i=0,from=0 ; i<=multisplit_count ; i++) { to = i==multisplit_count ? dis->len_payload : multisplit_pos[i]; @@ -1315,10 +1345,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack, - dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,0,0, seg, seg_len, pkt1, &pkt1_len)) return verdict; + ip_id=IP4_IP_ID_NEXT(ip_id); DLOG("sending multisplit part %d %zu-%zu len=%zu seqovl=%u : ",i+1,from,to-1,to-from,seqovl); hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) @@ -1348,6 +1379,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint uint8_t ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg; size_t seg_len,from,to; unsigned int seqovl; + + ip_id = IP4_IP_ID_FIX(dis->ip); + for (i=multisplit_count-1,to=dis->len_payload ; i>=-1 ; i--) { from = i>=0 ? multisplit_pos[i] : 0; @@ -1380,10 +1414,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack, - dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,0,0, seg, seg_len, pkt1, &pkt1_len)) return verdict; + ip_id=IP4_IP_ID_PREV(ip_id); DLOG("sending multisplit part %d %zu-%zu len=%zu seqovl=%u : ",i+2,from,to-1,to-from,seqovl); hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) @@ -1401,6 +1436,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint size_t seg_len; unsigned int seqovl; + ip_id = IP4_IP_ID_FIX(dis->ip); + if (seqovl_pos>=split_pos) { DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl.\n",seqovl_pos,split_pos); @@ -1409,44 +1446,42 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint else seqovl = seqovl_pos; - if (split_poslen_payload) + if (seqovl) { - if (seqovl) + seg_len = dis->len_payload-split_pos+seqovl; + if (seg_len>sizeof(fakeseg)) { - seg_len = dis->len_payload-split_pos+seqovl; - if (seg_len>sizeof(fakeseg)) - { - DLOG("seqovl is too large\n"); - return verdict; - } - fill_pattern(fakeseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); - memcpy(fakeseg+seqovl,dis->data_payload+split_pos,dis->len_payload-split_pos); - seg = fakeseg; - } - else - { - seg = dis->data_payload+split_pos; - seg_len = dis->len_payload-split_pos; - } - - pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq , split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), - fooling_orig,dp->desync_badseq_increment,dp->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,dis->len_payload-1, dis->len_payload-split_pos, seqovl); - hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + DLOG("seqovl is too large\n"); return verdict; + } + fill_pattern(fakeseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); + memcpy(fakeseg+seqovl,dis->data_payload+split_pos,dis->len_payload-split_pos); + seg = fakeseg; } + else + { + seg = dis->data_payload+split_pos; + seg_len = dis->len_payload-split_pos; + } + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq , split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, + seg, seg_len, pkt1, &pkt1_len)) + return verdict; + ip_id=IP4_IP_ID_PREV(ip_id); + DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos, seqovl); + hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + return verdict; seg_len = sizeof(fakeseg); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, zeropkt, split_pos, fakeseg, &seg_len)) return verdict; + ip_id=IP4_IP_ID_PREV(ip_id); 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(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len)) @@ -1454,15 +1489,17 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, dis->data_payload, split_pos, pkt1, &pkt1_len)) return verdict; + ip_id=IP4_IP_ID_PREV(ip_id); DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); hexdump_limited_dlog(dis->data_payload,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) return verdict; + if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id; 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(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len)) @@ -1477,12 +1514,15 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100],ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg; size_t fakeseg_len,seg_len; + ip_id = IP4_IP_ID_FIX(dis->ip); + fakeseg_len = sizeof(fakeseg); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, zeropkt, split_pos, fakeseg, &fakeseg_len)) return verdict; + ip_id=IP4_IP_ID_NEXT(ip_id); 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(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len)) @@ -1514,10 +1554,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,-seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, seg, seg_len, pkt1, &pkt1_len)) return verdict; + ip_id=IP4_IP_ID_NEXT(ip_id); DLOG("sending 1st tcp segment 0-%zu len=%zu seqovl=%u : ",split_pos-1, split_pos, seqovl); hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) @@ -1535,25 +1576,23 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint break; } #endif - + if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id; + ip_id=IP4_IP_ID_NEXT(ip_id); 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(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len)) return verdict; - if (split_poslen_payload) - { - pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), - fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, - dis->data_payload+split_pos, dis->len_payload-split_pos, pkt1, &pkt1_len)) - return verdict; - DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos); - hexdump_limited_dlog(dis->data_payload+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - } + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, + dis->data_payload+split_pos, dis->len_payload-split_pos, pkt1, &pkt1_len)) + return verdict; + DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos); + hexdump_limited_dlog(dis->data_payload+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + return verdict; return VERDICT_DROP; } @@ -1566,8 +1605,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN+100], *pkt_orig; size_t pkt_orig_len; + ip_id = IP4_IP_ID_FIX(dis->ip); + uint32_t ident = dis->ip ? ip_id ? ip_id : htons(1+random()%0xFFFF) : htonl(1+random()%0xFFFFFFFF); size_t ipfrag_pos = (dp->desync_ipfrag_pos_tcp && dp->desync_ipfrag_pos_tcptransport_len) ? dp->desync_ipfrag_pos_tcp : 24; - uint32_t ident = dis->ip ? dis->ip->ip_id ? dis->ip->ip_id : htons(1+random()%0xFFFF) : htonl(1+random()%0xFFFFFFFF); pkt1_len = sizeof(pkt1); pkt2_len = sizeof(pkt2); @@ -1735,6 +1775,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint size_t fake_size; char host[256]; bool bHaveHost=false; + uint16_t ip_id; if (IsQUICInitial(dis->data_payload,dis->len_payload)) { @@ -2005,7 +2046,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint break; } case DESYNC_FAKE: - if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len)) + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len)) return verdict; DLOG("sending fake : "); hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n"); @@ -2020,7 +2061,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(dp->desync_mode2))) { if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, - ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), fooling_orig,NULL,0,0, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) { @@ -2043,7 +2084,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint { case DESYNC_UDPLEN: pkt1_len = sizeof(pkt1); - if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, dp->udplen_pattern, sizeof(dp->udplen_pattern), dp->udplen_increment, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, dp->udplen_pattern, sizeof(dp->udplen_pattern), dp->udplen_increment, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) { DLOG("could not construct packet with modified length. too large ?\n"); break; @@ -2068,7 +2109,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint memcpy(pkt2+pkt2_len,dis->data_payload+1,szcopy); pkt2_len+=szcopy; pkt1_len = sizeof(pkt1); - if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, NULL, 0 , 0, pkt2, pkt2_len, pkt1, &pkt1_len)) + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, NULL, 0 , 0, pkt2, pkt2_len, pkt1, &pkt1_len)) { DLOG("could not construct packet with modified length. too large ?\n"); break; @@ -2090,9 +2131,10 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN+100], *pkt_orig; size_t pkt_orig_len; - size_t ipfrag_pos = (dp->desync_ipfrag_pos_udp && dp->desync_ipfrag_pos_udptransport_len) ? dp->desync_ipfrag_pos_udp : sizeof(struct udphdr); // freebsd do not set ip.id - uint32_t ident = dis->ip ? dis->ip->ip_id ? dis->ip->ip_id : htons(1+random()%0xFFFF) : htonl(1+random()%0xFFFFFFFF); + ip_id = IP4_IP_ID_FIX(dis->ip); + uint32_t ident = dis->ip ? ip_id ? ip_id : htons(1+random()%0xFFFF) : htonl(1+random()%0xFFFFFFFF); + size_t ipfrag_pos = (dp->desync_ipfrag_pos_udp && dp->desync_ipfrag_pos_udptransport_len) ? dp->desync_ipfrag_pos_udp : sizeof(struct udphdr); pkt1_len = sizeof(pkt1); pkt2_len = sizeof(pkt2); diff --git a/nfq/nfqws.c b/nfq/nfqws.c index f8b74a4..da81369 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -844,6 +844,11 @@ static void split_compat(struct desync_profile *dp) dp->splits[dp->split_count].pos = 2; dp->split_count++; } + if ((dp->seqovl.marker!=PM_ABS || dp->seqovl.pos<0) && (dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_MULTISPLIT)) + { + DLOG_ERR("split seqovl supports only absolute positive positions\n"); + exit_clean(1); + } } static void SplitDebug(void) @@ -1590,7 +1595,13 @@ int main(int argc, char **argv) dp->split_count++; break; case 26: /* dpi-desync-split-seqovl */ - if (!parse_split_pos(optarg, &dp->seqovl)) + if (!strcmp(optarg,"0")) + { + // allow zero = disable seqovl + dp->seqovl.marker=PM_ABS; + dp->seqovl.pos=0; + } + else if (!parse_split_pos(optarg, &dp->seqovl)) { DLOG_ERR("Invalid argument for dpi-desync-split-seqovl\n"); exit_clean(1);