Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-22 01:05:48 +00:00

46 Commits

Author SHA1 Message Date
bol-van
46a7632f59 50-dht4all iptables fix 2025-12-25 16:13:42 +03:00
bol-van
0642969a2d 50-dht4all fix comment 2025-12-25 16:07:33 +03:00
bol-van
13af2ec1be chmod 2025-12-25 16:02:12 +03:00
bol-van
50a1bb72d9 change dht and wireguard detection 2025-12-25 15:54:49 +03:00
bol-van
1696f1b552 update docs 2025-12-25 12:06:39 +03:00
bol-van
b0ce5c0c1b nfqws2: harden tls handshake detection 2025-12-24 17:18:25 +03:00
bol-van
87943846d9 update docs 2025-12-24 16:43:45 +03:00
bol-van
8b359d0410 update docs 2025-12-24 16:39:03 +03:00
bol-van
0430d9d9cd zapret-pcap: move file:close 2025-12-24 16:16:34 +03:00
bol-van
efcc1477dd update docs 2025-12-24 14:27:43 +03:00
bol-van
100fff0461 update docs 2025-12-24 14:26:51 +03:00
bol-van
1d14f8b0a4 update docs 2025-12-24 12:58:09 +03:00
bol-van
6e5c6511d3 update docs 2025-12-24 12:57:02 +03:00
bol-van
491a24d671 update docs 2025-12-24 12:53:48 +03:00
bol-van
505e8ff82c zapret-auto: tcp options nil 2025-12-24 00:12:49 +03:00
bol-van
1bbc56dc1b zapret-auto: desync.track presence check 2025-12-24 00:10:32 +03:00
bol-van
ad60550bf3 update docs 2025-12-23 23:52:34 +03:00
bol-van
3043963e28 nfqws2,zapret-auto: ip6flow fixes 2025-12-23 23:48:32 +03:00
bol-van
664bc60175 winws2: send to interface 1.0 if no ifname given 2025-12-23 23:01:36 +03:00
bol-van
815801a7db zapret-auto: preserve interface name in rst send 2025-12-23 22:24:21 +03:00
bol-van
05f54086cf zapret-auto: add reset to detector defaults 2025-12-23 22:14:52 +03:00
bol-van
b7a5f0410f nfqws2: minor lua safety checks 2025-12-23 21:57:25 +03:00
bol-van
da8bb9f5b8 nfqws2: struct iphdr -> ip 2025-12-23 21:39:04 +03:00
bol-van
9e52d767d1 update docs 2025-12-23 15:31:31 +03:00
bol-van
3ff06303cb init.d: autohostlist reset feature 2025-12-23 15:30:31 +03:00
bol-van
2a5c036909 nfqws2,zapret-auto: reset retransmitter 2025-12-23 15:13:33 +03:00
bol-van
a6e11540ff zapret-auto: reset parameter to standard_detector 2025-12-23 10:27:23 +03:00
bol-van
347c35e588 update docs 2025-12-23 09:52:17 +03:00
bol-van
ea28460f1d update docs 2025-12-23 09:49:47 +03:00
bol-van
0ac5df9d0e update docs 2025-12-22 20:54:44 +03:00
bol-van
63767929a0 nfqws2: dtls, reevaulate profile on l7/host discovery in any direction 2025-12-22 17:42:53 +03:00
bol-van
026c832f3f update docs 2025-12-22 13:55:54 +03:00
bol-van
53ef85773e update docs 2025-12-22 13:53:54 +03:00
bol-van
c41353cb8a update docs 2025-12-22 13:53:00 +03:00
bol-van
d2f6c18adf update docs 2025-12-22 13:52:45 +03:00
bol-van
00d1406791 update docs 2025-12-22 12:21:52 +03:00
bol-van
a38acae652 update docs 2025-12-22 12:16:28 +03:00
bol-van
90a991b5ee update docs 2025-12-22 12:14:47 +03:00
bol-van
686721f96a zapret-lib: wsize_rewrite change dlog text 2025-12-22 11:34:01 +03:00
bol-van
479b067f1a update docs 2025-12-21 23:28:46 +03:00
bol-van
ea1f34c833 update docs 2025-12-21 23:27:29 +03:00
bol-van
b4fe028cb7 update docs 2025-12-21 23:26:18 +03:00
bol-van
39c3640477 update docs 2025-12-21 23:18:49 +03:00
bol-van
2236a95d49 update docs 2025-12-21 23:08:18 +03:00
bol-van
8bb03d68b5 update docs 2025-12-21 23:05:34 +03:00
bol-van
7b2a9a26ed update docs 2025-12-21 23:02:52 +03:00
25 changed files with 1655 additions and 1060 deletions

View File

@@ -25,7 +25,7 @@ filter_apply_hostlist_target()
{ {
# $1 - var name of nfqws params # $1 - var name of nfqws params
local v parm parm1 parm2 parm3 parm4 parm5 parm6 parm7 parm8 parm9 parm10 parmNA local v parm parm1 parm2 parm3 parm4 parm5 parm6 parm7 parm8 parm9 parm10 param11 param12 param13 parmNA
eval v="\$$1" eval v="\$$1"
if contains "$v" "$HOSTLIST_MARKER" || contains "$v" "$HOSTLIST_NOAUTO_MARKER"; then if contains "$v" "$HOSTLIST_MARKER" || contains "$v" "$HOSTLIST_NOAUTO_MARKER"; then
[ "$MODE_FILTER" = hostlist -o "$MODE_FILTER" = autohostlist ] && [ "$MODE_FILTER" = hostlist -o "$MODE_FILTER" = autohostlist ] &&
@@ -40,14 +40,15 @@ filter_apply_hostlist_target()
parm5="${AUTOHOSTLIST_FAIL_THRESHOLD:+--hostlist-auto-fail-threshold=$AUTOHOSTLIST_FAIL_THRESHOLD}" parm5="${AUTOHOSTLIST_FAIL_THRESHOLD:+--hostlist-auto-fail-threshold=$AUTOHOSTLIST_FAIL_THRESHOLD}"
parm6="${AUTOHOSTLIST_FAIL_TIME:+--hostlist-auto-fail-time=$AUTOHOSTLIST_FAIL_TIME}" parm6="${AUTOHOSTLIST_FAIL_TIME:+--hostlist-auto-fail-time=$AUTOHOSTLIST_FAIL_TIME}"
parm7="${AUTOHOSTLIST_RETRANS_THRESHOLD:+--hostlist-auto-retrans-threshold=$AUTOHOSTLIST_RETRANS_THRESHOLD}" parm7="${AUTOHOSTLIST_RETRANS_THRESHOLD:+--hostlist-auto-retrans-threshold=$AUTOHOSTLIST_RETRANS_THRESHOLD}"
parm8="${AUTOHOSTLIST_RETRANS_MAXSEQ:+--hostlist-auto-retrans-maxseq=$AUTOHOSTLIST_RETRANS_MAXSEQ}" parm8="${AUTOHOSTLIST_RETRANS_RESET:+--hostlist-auto-retrans-reset=$AUTOHOSTLIST_RETRANS_RESET}"
parm9="${AUTOHOSTLIST_INCOMING_MAXSEQ:+--hostlist-auto-incoming-maxseq=$AUTOHOSTLIST_INCOMING_MAXSEQ}" parm9="${AUTOHOSTLIST_RETRANS_MAXSEQ:+--hostlist-auto-retrans-maxseq=$AUTOHOSTLIST_RETRANS_MAXSEQ}"
parm10="${AUTOHOSTLIST_UDP_IN:+--hostlist-auto-udp-in=$AUTOHOSTLIST_UDP_IN}" parm10="${AUTOHOSTLIST_INCOMING_MAXSEQ:+--hostlist-auto-incoming-maxseq=$AUTOHOSTLIST_INCOMING_MAXSEQ}"
parm11="${AUTOHOSTLIST_UDP_OUT:+--hostlist-auto-udp-out=$AUTOHOSTLIST_UDP_OUT}" parm11="${AUTOHOSTLIST_UDP_IN:+--hostlist-auto-udp-in=$AUTOHOSTLIST_UDP_IN}"
parm12="--hostlist=$HOSTLIST_AUTO" parm12="${AUTOHOSTLIST_UDP_OUT:+--hostlist-auto-udp-out=$AUTOHOSTLIST_UDP_OUT}"
parm13="--hostlist=$HOSTLIST_AUTO"
} }
parm="$parm1${parm2:+ $parm2}${parm3:+ $parm3}${parm4:+ $parm4}${parm5:+ $parm5}${parm6:+ $parm6}${parm7:+ $parm7}${parm8:+ $parm8}${parm9:+ $parm9}${parm10:+ $parm10}${parm11:+ $parm11}" parm="$parm1${parm2:+ $parm2}${parm3:+ $parm3}${parm4:+ $parm4}${parm5:+ $parm5}${parm6:+ $parm6}${parm7:+ $parm7}${parm8:+ $parm8}${parm9:+ $parm9}${parm10:+ $parm10}${parm11:+ $parm11}${parm12:+ $parm12}"
parmNA="$parm1${parm2:+ $parm2}${parm3:+ $parm3}${parm10:+ $parm12}" parmNA="$parm1${parm2:+ $parm2}${parm3:+ $parm3}${parm13:+ $parm13}"
} }
v="$(replace_str $HOSTLIST_NOAUTO_MARKER "$parmNA" "$v")" v="$(replace_str $HOSTLIST_NOAUTO_MARKER "$parmNA" "$v")"
v="$(replace_str $HOSTLIST_MARKER "$parm" "$v")" v="$(replace_str $HOSTLIST_MARKER "$parm" "$v")"

View File

@@ -30,6 +30,7 @@ IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5"
# NOTE : set PKT_IN, PKT_OUT variables appropriately # NOTE : set PKT_IN, PKT_OUT variables appropriately
AUTOHOSTLIST_INCOMING_MAXSEQ=4096 AUTOHOSTLIST_INCOMING_MAXSEQ=4096
AUTOHOSTLIST_RETRANS_MAXSEQ=32768 AUTOHOSTLIST_RETRANS_MAXSEQ=32768
AUTOHOSTLIST_RETRANS_RESET=1
AUTOHOSTLIST_RETRANS_THRESHOLD=3 AUTOHOSTLIST_RETRANS_THRESHOLD=3
AUTOHOSTLIST_FAIL_THRESHOLD=3 AUTOHOSTLIST_FAIL_THRESHOLD=3
AUTOHOSTLIST_FAIL_TIME=60 AUTOHOSTLIST_FAIL_TIME=60

View File

@@ -125,3 +125,11 @@ v0.7.5
* ipset: remove get_reestr_hostlist.sh and get_reestr_resolve.sh because zapret-info does not and will probably not ever update * ipset: remove get_reestr_hostlist.sh and get_reestr_resolve.sh because zapret-info does not and will probably not ever update
* nfqws2: fix "reasm cancelled" if no incoming traffic redirected * nfqws2: fix "reasm cancelled" if no incoming traffic redirected
* blockcheck2: MULTIDISORDER=multidisorder_legacy * blockcheck2: MULTIDISORDER=multidisorder_legacy
v0.7.6
* nfqws2: reevaluate profile on l7/host discovery in any direction
* nfqws2: dtls protocol detection
* nfqws2: autohostlist reset retransmitter to break long wait
* zapret-auto: stadard_failure_detector reset retransmitter to break long wait
* nfqws2, init.d, windivert : dht and wg detection changes

File diff suppressed because it is too large Load Diff

View File

@@ -301,18 +301,15 @@ nfqws2 --lua-desync=send:ipfrag:ipfrag_pos_udp=8 --lua-desync=drop
Но это решаемо. А что не решаемо - это перехват вторых частей kyber tls hello. Их невозможно опознать без связи с предыдущими фрагментами. Поэтому перехватывается весь порт. Но это решаемо. А что не решаемо - это перехват вторых частей kyber tls hello. Их невозможно опознать без связи с предыдущими фрагментами. Поэтому перехватывается весь порт.
Для HTTP вопрос решаемый, поскольку там нет реассемблирования запросов, но http сейчас стал настолько редким, что и смысла нет заморачиваться. Для HTTP вопрос решаемый, поскольку там нет реассемблирования запросов, но http сейчас стал настолько редким, что и смысла нет заморачиваться.
Везде расставлены фильтры профиля мультистратегии `--filter-l7`, фильтры по `--out-range` и по `--payload`. Везде расставлены фильтры профиля мультистратегии `--filter-l7`, фильтры по `--out-range` и по `--payload`. Зачем ? В основном для сокращения вызовов LUA кода, который заведомо медленнее C кода.
Зачем ? В основном для сокращения вызовов LUA кода, который заведомо медленнее C кода. Если пакет не попадет в профили с LUA - ни о каком вызове кода LUA речи быть не может. Если пакет попал в профиль с LUA, то после первых 10 пакетов с данными наступает отсечение по верхней границе range. Все LUA инстансы входят в состояние instance cutoff, соединение входит в состояние "lua cutoff" по направлению "out". Значит вызовов LUA не будет вообще. Не просто вызовов, а даже обращения к движку LUA с какой-либо целью. Будет только C код, который посмотрит на признак "cutoff" и сразу же отпустит пакет.
Если пакет не попадет в профили с LUA - ни о каком вызове кода LUA речи быть не может.
Если пакет попал в профиль с LUA, то после первых 10 пакетов с данными наступает отсечение по верхней границе range. Все LUA инстансы входят в состояние instance cutoff, Почему именно `-d10` ? Чтобы хватило для отработки большинства вариантов стратегий, учитывая возможные ретрансмиссии и плохую связь. В winws2 по умолчанию включен параметр `--wf-tcp-empty=0`. Он блокирует перехват пустых пакетов с ACK, что позволяет примерно в 2 раза сэкономить на процессоре при интенсивных скачиваниях. Пустые ACK в большинстве стратегий не нужны. Но это же и ломает счетчик "n" - он не будет показывать реальное количество пакетов по соединению. Счетчик "d" работать будет как надо.
соединение входит в состояние "lua cutoff" по направлению "out". Значит вызовов LUA не будет вообще. Не просто вызовов, а даже обращения к движку LUA
с какой-либо целью. Будет только C код, который посмотрит на признак "cutoff" и сразу же отпустит пакет.
Так же везде расставлены фильтры по payload type. Отчасти так же с целью сократить вызовы LUA даже в пределах первых 10 пакетов с данными. Так же везде расставлены фильтры по payload type. Отчасти так же с целью сократить вызовы LUA даже в пределах первых 10 пакетов с данными.
С другой стороны, даже при совпадении протокола соединения (`--filter-l7`) может пробежать не интересующий нас пейлоад. С другой стороны, даже при совпадении протокола соединения (`--filter-l7`) может пробежать не интересующий нас пейлоад.
По умолчанию многие функции из `zapret-antidpi.lua` реагируют только на известные типы пейлоада, но не на конкретные, а на любые известные. По умолчанию многие функции из `zapret-antidpi.lua` реагируют только на известные типы пейлоада, но не на конкретные, а на любые известные.
Если допустить малореальный, но гипотетически возможный сценарий, что в рамках протокола http будет отправлен блок данных с tls или фраза, похожая на сообщение из xmpp, Если допустить малореальный, но гипотетически возможный сценарий, что в рамках протокола http будет отправлен блок данных с tls или фраза, похожая на сообщение из xmpp, то тип пейлоада выскочит tls_client_hello или xmpp_stream, например. Лучше от этого сразу уберечься. Тем более что в других видах протоколов - xmpp, например, -
то тип пейлоада выскочит tls_client_hello или xmpp_stream, например. Лучше от этого сразу уберечься. Тем более что в других видах протоколов - xmpp, например, -
пейлоады могут проскакивать нескольких типов вполне ожидаемо. Но работать надо не по всем. пейлоады могут проскакивать нескольких типов вполне ожидаемо. Но работать надо не по всем.
В фейке для TLS по умолчанию - fake_default_tls - однократно при старте меняется SNI с "www.microsoft.com" на случайный и рандомизируется поле "random" в TLS handshake. В фейке для TLS по умолчанию - fake_default_tls - однократно при старте меняется SNI с "www.microsoft.com" на случайный и рандомизируется поле "random" в TLS handshake.

View File

@@ -1,4 +1,4 @@
# this custom script runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering # this custom script runs desync to DHT packets with udp payload length >=5 , without ipset/hostlist filtering
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22) # NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config : # can override in config :
@@ -21,9 +21,9 @@ zapret_custom_firewall()
local f uf4 uf6 local f uf4 uf6
local first_packet_only="$ipt_connbytes 1:1" local first_packet_only="$ipt_connbytes 1:1"
f='-p udp -m length --length 109:407 -m u32 --u32' f='-p udp -m u32 --u32'
uf4='0>>22&0x3C@8>>16=0x6431' uf4='0>>22&0x3C@4>>16=13:0xFFFF&&0>>22&0x3C@8>>16=0x6431:0x6432'
uf6='48>>16=0x6431' uf6='44>>16=13:0xFFFF&&48>>16=0x6431:0x6432'
fw_nfqws_post $1 "$f $uf4 $first_packet_only" "$f $uf6 $first_packet_only" $QNUM_DHT4ALL fw_nfqws_post $1 "$f $uf4 $first_packet_only" "$f $uf6 $first_packet_only" $QNUM_DHT4ALL
} }
zapret_custom_firewall_nft() zapret_custom_firewall_nft()
@@ -33,6 +33,6 @@ zapret_custom_firewall_nft()
local f local f
local first_packet_only="$nft_connbytes 1" local first_packet_only="$nft_connbytes 1"
f="meta length 109-407 meta l4proto udp @ih,0,16 0x6431" f="udp length ge 13 meta l4proto udp @ih,0,16 0x6431-0x6432"
nft_fw_nfqws_post "$f $first_packet_only" "$f $first_packet_only" $QNUM_DHT4ALL nft_fw_nfqws_post "$f $first_packet_only" "$f $first_packet_only" $QNUM_DHT4ALL
} }

View File

@@ -0,0 +1 @@
udp.Length>=5 and udp.Payload[0]=0x64 and udp.Payload[1]>=0x31 and udp.Payload[1]<=0x32

View File

@@ -1,3 +1,3 @@
outbound and udp.PayloadLength=148 and udp.Payload[0]=0x01 or
udp.PayloadLength=148 and udp.PayloadLength=92 and udp.Payload[0]=0x02 or
udp.Payload[0]=0x01 udp.PayloadLength=64 and udp.Payload[0]=0x03

View File

@@ -122,7 +122,8 @@ function standard_detector_defaults(arg)
udp_in = tonumber(arg.udp_in) or 1, udp_in = tonumber(arg.udp_in) or 1,
udp_out = tonumber(arg.udp_out) or 4, udp_out = tonumber(arg.udp_out) or 4,
no_http_redirect = arg.no_http_redirect, no_http_redirect = arg.no_http_redirect,
no_rst = arg.no_rst no_rst = arg.no_rst,
reset = arg.reset
} }
end end
@@ -135,6 +136,7 @@ end
-- udp too much out with too few in -- udp too much out with too few in
-- arg: maxseq=<rseq> - tcp: test retransmissions only within this relative sequence. default is 32K -- arg: maxseq=<rseq> - tcp: test retransmissions only within this relative sequence. default is 32K
-- arg: retrans=N - tcp: retrans count threshold. default is 3 -- arg: retrans=N - tcp: retrans count threshold. default is 3
-- arg: reset - send RST to retransmitter to break long wait
-- arg: inseq=<rseq> - tcp: maximum relative sequence number to treat incoming RST as DPI reset. default is 4K -- arg: inseq=<rseq> - tcp: maximum relative sequence number to treat incoming RST as DPI reset. default is 4K
-- arg: no_http_redirect - tcp: disable http_reply dpi redirect trigger -- arg: no_http_redirect - tcp: disable http_reply dpi redirect trigger
-- arg: no_rst - tcp: disable incoming RST trigger -- arg: no_rst - tcp: disable incoming RST trigger
@@ -151,6 +153,19 @@ function standard_failure_detector(desync, crec)
crec.retrans = crec.retrans and (crec.retrans+1) or 1 crec.retrans = crec.retrans and (crec.retrans+1) or 1
DLOG("standard_failure_detector: retransmission "..crec.retrans.."/"..arg.retrans) DLOG("standard_failure_detector: retransmission "..crec.retrans.."/"..arg.retrans)
trigger = crec.retrans>=arg.retrans trigger = crec.retrans>=arg.retrans
if trigger and arg.reset then
local dis = deepcopy(desync.dis)
dis.payload = nil
dis_reverse(dis)
dis.tcp.th_flags = TH_RST
dis.tcp.th_win = desync.track and desync.track.pos.reverse.tcp.winsize or 64
dis.tcp.options = nil
if dis.ip6 then
dis.ip6.ip6_flow = (desync.track and desync.track.pos.reverse.ip6_flow) and desync.track.pos.reverse.ip6_flow or 0x60000000;
end
DLOG("standard_failure_detector: sending RST to retransmitter")
rawsend_dissect(dis, {ifout = desync.ifin})
end
end end
end end
else else

View File

@@ -762,6 +762,22 @@ function fix_ip6_next(ip6, last_proto)
end end
end end
-- reverses ip addresses, ports and seq/ack
function dis_reverse(dis)
if dis.ip then
dis.ip.ip_src, dis.ip.ip_dst = dis.ip.ip_dst, dis.ip.ip_src
end
if dis.ip6 then
dis.ip6.ip6_src, dis.ip6.ip6_dst = dis.ip6.ip6_dst, dis.ip6.ip6_src
end
if dis.tcp then
dis.tcp.th_sport, dis.tcp.th_dport = dis.tcp.th_dport, dis.tcp.th_sport
dis.tcp.th_ack, dis.tcp.th_seq = dis.tcp.th_seq, dis.tcp.th_ack
end
if dis.udp then
dis.udp.uh_sport, dis.udp.uh_dport = dis.udp.uh_dport, dis.udp.uh_sport
end
end
-- parse autottl : delta,min-max -- parse autottl : delta,min-max
function parse_autottl(s) function parse_autottl(s)
@@ -1300,7 +1316,7 @@ function wsize_rewrite(dis, arg)
local b = false local b = false
if arg.wsize then if arg.wsize then
local wsize = tonumber(arg.wsize) local wsize = tonumber(arg.wsize)
DLOG("window size "..dis.tcp.th_win.." => "..wsize) DLOG("wsize_rewrite: window size "..dis.tcp.th_win.." => "..wsize)
dis.tcp.th_win = tonumber(arg.wsize) dis.tcp.th_win = tonumber(arg.wsize)
b = true b = true
end end
@@ -1310,9 +1326,9 @@ function wsize_rewrite(dis, arg)
if i then if i then
local oldscale = u8(dis.tcp.options[i].data) local oldscale = u8(dis.tcp.options[i].data)
if scale>oldscale then if scale>oldscale then
DLOG("not increasing scale factor") DLOG("wsize_rewrite: not increasing scale factor")
elseif scale<oldscale then elseif scale<oldscale then
DLOG("scale factor "..oldscale.." => "..scale) DLOG("wsize_rewrite: scale factor "..oldscale.." => "..scale)
dis.tcp.options[i].data = bu8(scale) dis.tcp.options[i].data = bu8(scale)
b = true b = true
end end

View File

@@ -6,7 +6,6 @@ function pcap_write_packet(file, raw)
local sec, nsec = clock_gettime(); local sec, nsec = clock_gettime();
file:write(bu32(sec)..bu32(nsec)..bu32(#raw)..bu32(#raw)) file:write(bu32(sec)..bu32(nsec)..bu32(#raw)..bu32(#raw))
file:write(raw) file:write(raw)
file:close()
end end
function pcap_write(file, raw) function pcap_write(file, raw)
local pos = file:seek() local pos = file:seek()
@@ -36,4 +35,5 @@ function pcap(ctx, desync)
error("pcap: could not write to '".._G[fn_cache_name].."'") error("pcap: could not write to '".._G[fn_cache_name].."'")
end end
pcap_write(f, raw_packet(ctx)) pcap_write(f, raw_packet(ctx))
f:close()
end end

View File

@@ -2,64 +2,65 @@
#include "checksum.h" #include "checksum.h"
#include <netinet/in.h> #include <netinet/in.h>
//#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) // #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
//#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) // #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
static uint16_t from64to16(uint64_t x) static uint16_t from64to16(uint64_t x)
{ {
uint32_t u = (uint32_t)(uint16_t)x + (uint16_t)(x>>16) + (uint16_t)(x>>32) + (uint16_t)(x>>48); uint32_t u = (uint32_t)(uint16_t)x + (uint16_t)(x >> 16) + (uint16_t)(x >> 32) + (uint16_t)(x >> 48);
return (uint16_t)u + (uint16_t)(u>>16); return (uint16_t)u + (uint16_t)(u >> 16);
} }
// this function preserves data alignment requirements (otherwise it will be damn slow on mips arch) // this function preserves data alignment requirements (otherwise it will be damn slow on mips arch)
// and uses 64-bit arithmetics to improve speed // and uses 64-bit arithmetics to improve speed
// taken from linux source code // taken from linux source code
static uint16_t do_csum(const uint8_t * buff, size_t len) static uint16_t do_csum(const uint8_t *buff, size_t len)
{ {
uint8_t odd; uint8_t odd;
size_t count; size_t count;
uint64_t result,w,carry=0; uint64_t result, w, carry = 0;
uint16_t u16; uint16_t u16;
if (!len) return 0; if (!len)
return 0;
odd = (uint8_t)(1 & (size_t)buff); odd = (uint8_t)(1 & (size_t)buff);
if (odd) if (odd)
{ {
// any endian compatible // any endian compatible
u16 = 0; u16 = 0;
*((uint8_t*)&u16+1) = *buff; *((uint8_t *)&u16 + 1) = *buff;
result = u16; result = u16;
len--; len--;
buff++; buff++;
} }
else else
result = 0; result = 0;
count = len >> 1; /* nr of 16-bit words.. */ count = len >> 1; /* nr of 16-bit words.. */
if (count) if (count)
{ {
if (2 & (size_t) buff) if (2 & (size_t)buff)
{ {
result += *(uint16_t *) buff; result += *(uint16_t *)buff;
count--; count--;
len -= 2; len -= 2;
buff += 2; buff += 2;
} }
count >>= 1; /* nr of 32-bit words.. */ count >>= 1; /* nr of 32-bit words.. */
if (count) if (count)
{ {
if (4 & (size_t) buff) if (4 & (size_t)buff)
{ {
result += *(uint32_t *) buff; result += *(uint32_t *)buff;
count--; count--;
len -= 4; len -= 4;
buff += 4; buff += 4;
} }
count >>= 1; /* nr of 64-bit words.. */ count >>= 1; /* nr of 64-bit words.. */
if (count) if (count)
{ {
do do
{ {
w = *(uint64_t *) buff; w = *(uint64_t *)buff;
count--; count--;
buff += 8; buff += 8;
result += carry; result += carry;
@@ -71,13 +72,13 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
} }
if (len & 4) if (len & 4)
{ {
result += *(uint32_t *) buff; result += *(uint32_t *)buff;
buff += 4; buff += 4;
} }
} }
if (len & 2) if (len & 2)
{ {
result += *(uint16_t *) buff; result += *(uint16_t *)buff;
buff += 2; buff += 2;
} }
} }
@@ -85,54 +86,54 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
{ {
// any endian compatible // any endian compatible
u16 = 0; u16 = 0;
*(uint8_t*)&u16 = *buff; *(uint8_t *)&u16 = *buff;
result += u16; result += u16;
} }
u16 = from64to16(result); u16 = from64to16(result);
if (odd) u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8); if (odd)
u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8);
return u16; return u16;
} }
uint16_t csum_partial(const void *buff, size_t len) uint16_t csum_partial(const void *buff, size_t len)
{ {
return do_csum(buff,len); return do_csum(buff, len);
} }
uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum) uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum)
{ {
return ~from64to16((uint64_t)saddr + daddr + sum + htonl(len+proto)); return ~from64to16((uint64_t)saddr + daddr + sum + htonl(len + proto));
} }
uint16_t ip4_compute_csum(const void *buff, size_t len) uint16_t ip4_compute_csum(const void *buff, size_t len)
{ {
return ~from64to16(do_csum(buff,len)); return ~from64to16(do_csum(buff, len));
} }
void ip4_fix_checksum(struct ip *ip) void ip4_fix_checksum(struct ip *ip)
{ {
ip->ip_sum = 0; ip->ip_sum = 0;
ip->ip_sum = ip4_compute_csum(ip, ip->ip_hl<<2); ip->ip_sum = ip4_compute_csum(ip, ip->ip_hl << 2);
} }
uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum) uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum)
{ {
uint64_t a = (uint64_t)sum + htonl(len+proto) + uint64_t a = (uint64_t)sum + htonl(len + proto) +
*(uint32_t*)saddr + *((uint32_t*)saddr+1) + *((uint32_t*)saddr+2) + *((uint32_t*)saddr+3) + *(uint32_t *)saddr + *((uint32_t *)saddr + 1) + *((uint32_t *)saddr + 2) + *((uint32_t *)saddr + 3) +
*(uint32_t*)daddr + *((uint32_t*)daddr+1) + *((uint32_t*)daddr+2) + *((uint32_t*)daddr+3); *(uint32_t *)daddr + *((uint32_t *)daddr + 1) + *((uint32_t *)daddr + 2) + *((uint32_t *)daddr + 3);
return ~from64to16(a); return ~from64to16(a);
} }
void tcp4_fix_checksum(struct tcphdr *tcp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
void tcp4_fix_checksum(struct tcphdr *tcp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
{ {
tcp->th_sum = 0; tcp->th_sum = 0;
tcp->th_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_TCP,csum_partial(tcp,len)); tcp->th_sum = csum_tcpudp_magic(src_addr->s_addr, dest_addr->s_addr, len, IPPROTO_TCP, csum_partial(tcp, len));
} }
void tcp6_fix_checksum(struct tcphdr *tcp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr) void tcp6_fix_checksum(struct tcphdr *tcp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
{ {
tcp->th_sum = 0; tcp->th_sum = 0;
tcp->th_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp,len)); tcp->th_sum = csum_ipv6_magic(src_addr, dest_addr, len, IPPROTO_TCP, csum_partial(tcp, len));
} }
void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr) void tcp_fix_checksum(struct tcphdr *tcp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr)
{ {
if (ip) if (ip)
tcp4_fix_checksum(tcp, len, &ip->ip_src, &ip->ip_dst); tcp4_fix_checksum(tcp, len, &ip->ip_src, &ip->ip_dst);
@@ -140,17 +141,17 @@ void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const st
tcp6_fix_checksum(tcp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst); tcp6_fix_checksum(tcp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
} }
void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr) void udp4_fix_checksum(struct udphdr *udp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
{ {
udp->uh_sum = 0; udp->uh_sum = 0;
udp->uh_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_UDP,csum_partial(udp,len)); udp->uh_sum = csum_tcpudp_magic(src_addr->s_addr, dest_addr->s_addr, len, IPPROTO_UDP, csum_partial(udp, len));
} }
void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr) void udp6_fix_checksum(struct udphdr *udp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
{ {
udp->uh_sum = 0; udp->uh_sum = 0;
udp->uh_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_UDP,csum_partial(udp,len)); udp->uh_sum = csum_ipv6_magic(src_addr, dest_addr, len, IPPROTO_UDP, csum_partial(udp, len));
} }
void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr) void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr)
{ {
if (ip) if (ip)
udp4_fix_checksum(udp, len, &ip->ip_src, &ip->ip_dst); udp4_fix_checksum(udp, len, &ip->ip_src, &ip->ip_dst);

View File

@@ -70,24 +70,24 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s
p->pool = NULL; p->pool = NULL;
} }
void ConntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr) void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis)
{ {
memset(c, 0, sizeof(*c)); memset(c, 0, sizeof(*c));
if (ip) if (dis->ip)
{ {
c->l3proto = IPPROTO_IP; c->l3proto = IPPROTO_IP;
c->dst.ip = bReverse ? ip->ip_src : ip->ip_dst; c->dst.ip = bReverse ? dis->ip->ip_src : dis->ip->ip_dst;
c->src.ip = bReverse ? ip->ip_dst : ip->ip_src; c->src.ip = bReverse ? dis->ip->ip_dst : dis->ip->ip_src;
} }
else if (ip6) else if (dis->ip6)
{ {
c->l3proto = IPPROTO_IPV6; c->l3proto = IPPROTO_IPV6;
c->dst.ip6 = bReverse ? ip6->ip6_src : ip6->ip6_dst; c->dst.ip6 = bReverse ? dis->ip6->ip6_src : dis->ip6->ip6_dst;
c->src.ip6 = bReverse ? ip6->ip6_dst : ip6->ip6_src; c->src.ip6 = bReverse ? dis->ip6->ip6_dst : dis->ip6->ip6_src;
} }
else else
c->l3proto = -1; c->l3proto = -1;
extract_ports(tcphdr, udphdr, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport); extract_ports(dis->tcp, dis->udp, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport);
} }
@@ -127,7 +127,7 @@ static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c)
return ctnew; return ctnew;
} }
static void ConntrackApplyPos(const struct tcphdr *tcp, t_ctrack *t, bool bReverse, uint32_t len_payload) static void ConntrackApplyPos(t_ctrack *t, bool bReverse, const struct dissect *dis)
{ {
uint8_t scale; uint8_t scale;
uint16_t mss; uint16_t mss;
@@ -136,21 +136,23 @@ static void ConntrackApplyPos(const struct tcphdr *tcp, t_ctrack *t, bool bRever
direct = bReverse ? &t->pos.server : &t->pos.client; direct = bReverse ? &t->pos.server : &t->pos.client;
reverse = bReverse ? &t->pos.client : &t->pos.server; reverse = bReverse ? &t->pos.client : &t->pos.server;
scale = tcp_find_scale_factor(tcp); if (dis->ip6) direct->ip6flow = ntohl(dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_flow);
mss = ntohs(tcp_find_mss(tcp));
direct->seq_last = ntohl(tcp->th_seq); scale = tcp_find_scale_factor(dis->tcp);
direct->pos = direct->seq_last + len_payload; mss = ntohs(tcp_find_mss(dis->tcp));
reverse->pos = reverse->seq_last = ntohl(tcp->th_ack);
direct->seq_last = ntohl(dis->tcp->th_seq);
direct->pos = direct->seq_last + dis->len_payload;
reverse->pos = reverse->seq_last = ntohl(dis->tcp->th_ack);
if (t->pos.state == SYN) if (t->pos.state == SYN)
direct->uppos_prev = direct->uppos = direct->pos; direct->uppos_prev = direct->uppos = direct->pos;
else if (len_payload) else if (dis->len_payload)
{ {
direct->uppos_prev = direct->uppos; direct->uppos_prev = direct->uppos;
if (!((direct->pos - direct->uppos) & 0x80000000)) if (!((direct->pos - direct->uppos) & 0x80000000))
direct->uppos = direct->pos; direct->uppos = direct->pos;
} }
direct->winsize = ntohs(tcp->th_win); direct->winsize = ntohs(dis->tcp->th_win);
direct->winsize_calc = direct->winsize; direct->winsize_calc = direct->winsize;
if (direct->scale != SCALE_NONE) direct->winsize_calc <<= direct->scale; if (direct->scale != SCALE_NONE) direct->winsize_calc <<= direct->scale;
if (mss && !direct->mss) direct->mss = mss; if (mss && !direct->mss) direct->mss = mss;
@@ -162,8 +164,7 @@ static void ConntrackApplyPos(const struct tcphdr *tcp, t_ctrack *t, bool bRever
reverse->rseq_over_2G = true; reverse->rseq_over_2G = true;
} }
// non-tcp packets are passed with tcphdr=NULL but len_payload filled static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct dissect *dis)
static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr *tcphdr, uint32_t len_payload)
{ {
uint8_t scale; uint8_t scale;
uint16_t mss; uint16_t mss;
@@ -171,34 +172,34 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (bReverse) if (bReverse)
{ {
t->pos.server.pcounter++; t->pos.server.pcounter++;
t->pos.server.pdcounter += !!len_payload; t->pos.server.pdcounter += !!dis->len_payload;
t->pos.server.pbcounter += len_payload; t->pos.server.pbcounter += dis->len_payload;
} }
else else
{ {
t->pos.client.pcounter++; t->pos.client.pcounter++;
t->pos.client.pdcounter += !!len_payload; t->pos.client.pdcounter += !!dis->len_payload;
t->pos.client.pbcounter += len_payload; t->pos.client.pbcounter += dis->len_payload;
} }
if (tcphdr) if (dis->tcp)
{ {
if (tcp_syn_segment(tcphdr)) if (tcp_syn_segment(dis->tcp))
{ {
if (t->pos.state != SYN) ConntrackReInitTrack(t); // erase current entry if (t->pos.state != SYN) ConntrackReInitTrack(t); // erase current entry
t->pos.client.seq0 = ntohl(tcphdr->th_seq); t->pos.client.seq0 = ntohl(dis->tcp->th_seq);
} }
else if (tcp_synack_segment(tcphdr)) else if (tcp_synack_segment(dis->tcp))
{ {
// ignore SA dups // ignore SA dups
uint32_t seq0 = ntohl(tcphdr->th_ack) - 1; uint32_t seq0 = ntohl(dis->tcp->th_ack) - 1;
if (t->pos.state != SYN && t->pos.client.seq0 != seq0) if (t->pos.state != SYN && t->pos.client.seq0 != seq0)
ConntrackReInitTrack(t); // erase current entry ConntrackReInitTrack(t); // erase current entry
if (!t->pos.client.seq0) t->pos.client.seq0 = seq0; if (!t->pos.client.seq0) t->pos.client.seq0 = seq0;
t->pos.server.seq0 = ntohl(tcphdr->th_seq); t->pos.server.seq0 = ntohl(dis->tcp->th_seq);
} }
else if (tcphdr->th_flags & (TH_FIN | TH_RST)) else if (dis->tcp->th_flags & (TH_FIN | TH_RST))
{ {
t->pos.state = FIN; t->pos.state = FIN;
} }
@@ -207,11 +208,11 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (t->pos.state == SYN) if (t->pos.state == SYN)
{ {
t->pos.state = ESTABLISHED; t->pos.state = ESTABLISHED;
if (!bReverse && !t->pos.server.seq0) t->pos.server.seq0 = ntohl(tcphdr->th_ack) - 1; if (!bReverse && !t->pos.server.seq0) t->pos.server.seq0 = ntohl(dis->tcp->th_ack) - 1;
} }
} }
ConntrackApplyPos(tcphdr, t, bReverse, len_payload); ConntrackApplyPos(t, bReverse, dis);
} }
clock_gettime(CLOCK_REALTIME, &t->pos.t_last); clock_gettime(CLOCK_REALTIME, &t->pos.t_last);
@@ -219,12 +220,12 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (!t->t_start.tv_sec) t->t_start = t->pos.t_last; if (!t->t_start.tv_sec) t->t_start = t->pos.t_last;
} }
static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, t_ctrack **ctrack, bool *bReverse) static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct dissect *dis, t_ctrack **ctrack, bool *bReverse)
{ {
t_conn conn, connswp; t_conn conn, connswp;
t_conntrack_pool *ctr; t_conntrack_pool *ctr;
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr); ConntrackExtractConn(&conn, false, dis);
if ((ctr = ConntrackPoolSearch(*pp, &conn))) if ((ctr = ConntrackPoolSearch(*pp, &conn)))
{ {
if (bReverse) *bReverse = false; if (bReverse) *bReverse = false;
@@ -243,22 +244,22 @@ static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct ip
} }
return false; return false;
} }
bool ConntrackPoolDoubleSearch(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, t_ctrack **ctrack, bool *bReverse) bool ConntrackPoolDoubleSearch(t_conntrack *p, const struct dissect *dis, t_ctrack **ctrack, bool *bReverse)
{ {
return ConntrackPoolDoubleSearchPool(&p->pool, ip, ip6, tcphdr, udphdr, ctrack, bReverse); return ConntrackPoolDoubleSearchPool(&p->pool, dis, ctrack, bReverse);
} }
static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse) static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct dissect *dis, t_ctrack **ctrack, bool *bReverse)
{ {
t_conn conn, connswp; t_conn conn, connswp;
t_conntrack_pool *ctr; t_conntrack_pool *ctr;
bool b_rev; bool b_rev;
uint8_t proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP : IPPROTO_NONE; uint8_t proto = dis->tcp ? IPPROTO_TCP : dis->udp ? IPPROTO_UDP : IPPROTO_NONE;
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr); ConntrackExtractConn(&conn, false, dis);
if ((ctr = ConntrackPoolSearch(*pp, &conn))) if ((ctr = ConntrackPoolSearch(*pp, &conn)))
{ {
ConntrackFeedPacket(&ctr->track, (b_rev = false), tcphdr, len_payload); ConntrackFeedPacket(&ctr->track, (b_rev = false), dis);
goto ok; goto ok;
} }
else else
@@ -266,16 +267,16 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co
connswap(&conn, &connswp); connswap(&conn, &connswp);
if ((ctr = ConntrackPoolSearch(*pp, &connswp))) if ((ctr = ConntrackPoolSearch(*pp, &connswp)))
{ {
ConntrackFeedPacket(&ctr->track, (b_rev = true), tcphdr, len_payload); ConntrackFeedPacket(&ctr->track, (b_rev = true), dis);
goto ok; goto ok;
} }
} }
b_rev = tcphdr && tcp_synack_segment(tcphdr); b_rev = dis->tcp && tcp_synack_segment(dis->tcp);
if ((tcphdr && tcp_syn_segment(tcphdr)) || b_rev || udphdr) if ((dis->tcp && tcp_syn_segment(dis->tcp)) || b_rev || dis->udp)
{ {
if ((ctr = ConntrackNew(pp, b_rev ? &connswp : &conn))) if ((ctr = ConntrackNew(pp, b_rev ? &connswp : &conn)))
{ {
ConntrackFeedPacket(&ctr->track, b_rev, tcphdr, len_payload); ConntrackFeedPacket(&ctr->track, b_rev, dis);
goto ok; goto ok;
} }
} }
@@ -286,16 +287,16 @@ ok:
if (bReverse) *bReverse = b_rev; if (bReverse) *bReverse = b_rev;
return true; return true;
} }
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse) bool ConntrackPoolFeed(t_conntrack *p, const struct dissect *dis, t_ctrack **ctrack, bool *bReverse)
{ {
return ConntrackPoolFeedPool(&p->pool, ip, ip6, tcphdr, udphdr, len_payload, ctrack, bReverse); return ConntrackPoolFeedPool(&p->pool, dis, ctrack, bReverse);
} }
static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr) static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct dissect *dis)
{ {
t_conn conn, connswp; t_conn conn, connswp;
t_conntrack_pool *t; t_conntrack_pool *t;
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr); ConntrackExtractConn(&conn, false, dis);
if (!(t = ConntrackPoolSearch(*pp, &conn))) if (!(t = ConntrackPoolSearch(*pp, &conn)))
{ {
connswap(&conn, &connswp); connswap(&conn, &connswp);
@@ -305,9 +306,9 @@ static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct ip *ip, co
HASH_DEL(*pp, t); ConntrackFreeElem(t); HASH_DEL(*pp, t); ConntrackFreeElem(t);
return true; return true;
} }
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr) bool ConntrackPoolDrop(t_conntrack *p, const struct dissect *dis)
{ {
return ConntrackPoolDropPool(&p->pool, ip, ip6, tcphdr, udphdr); return ConntrackPoolDropPool(&p->pool, dis);
} }
void ConntrackPoolPurge(t_conntrack *p) void ConntrackPoolPurge(t_conntrack *p)

View File

@@ -19,6 +19,7 @@
#include "conntrack_base.h" #include "conntrack_base.h"
#include "packet_queue.h" #include "packet_queue.h"
#include "protocol.h" #include "protocol.h"
#include "darkmagic.h"
//#define HASH_BLOOM 20 //#define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1 #define HASH_NONFATAL_OOM 1
@@ -100,11 +101,11 @@ typedef struct
void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_syn, uint32_t timeout_established, uint32_t timeout_fin, uint32_t timeout_udp); void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_syn, uint32_t timeout_established, uint32_t timeout_fin, uint32_t timeout_udp);
void ConntrackPoolDestroy(t_conntrack *p); void ConntrackPoolDestroy(t_conntrack *p);
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse); bool ConntrackPoolFeed(t_conntrack *p, const struct dissect *dis, t_ctrack **ctrack, bool *bReverse);
// do not create, do not update. only find existing // do not create, do not update. only find existing
bool ConntrackPoolDoubleSearch(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, t_ctrack **ctrack, bool *bReverse); bool ConntrackPoolDoubleSearch(t_conntrack *p, const struct dissect *dis, t_ctrack **ctrack, bool *bReverse);
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr); bool ConntrackPoolDrop(t_conntrack *p, const struct dissect *dis);
void CaonntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr); void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis);
void ConntrackPoolDump(const t_conntrack *p); void ConntrackPoolDump(const t_conntrack *p);
void ConntrackPoolPurge(t_conntrack *p); void ConntrackPoolPurge(t_conntrack *p);
void ConntrackClearHostname(t_ctrack *track); void ConntrackClearHostname(t_ctrack *track);

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stdint.h>
#include <time.h> #include <time.h>
#define CTRACK_T_SYN 60 #define CTRACK_T_SYN 60
@@ -17,6 +18,7 @@ typedef struct
uint64_t pcounter; // packet counter uint64_t pcounter; // packet counter
uint64_t pdcounter; // data packet counter (with payload) uint64_t pdcounter; // data packet counter (with payload)
uint64_t pbcounter; // transferred byte counter. includes retransmissions. it's not the same as relative seq. uint64_t pbcounter; // transferred byte counter. includes retransmissions. it's not the same as relative seq.
uint32_t ip6flow;
// tcp only state, not used in udp // tcp only state, not used in udp
uint32_t pos; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current uint32_t pos; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current

View File

@@ -547,6 +547,33 @@ void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis)
} }
} }
void reverse_ip(struct ip *ip, struct ip6_hdr *ip6)
{
if (ip)
{
struct in_addr temp = ip->ip_src;
ip->ip_src = ip->ip_dst;
ip->ip_dst = temp;
ip4_fix_checksum(ip);
}
if (ip6)
{
struct in6_addr temp = ip6->ip6_src;
ip6->ip6_src = ip6->ip6_dst;
ip6->ip6_dst = temp;
}
}
void reverse_tcp(struct tcphdr *tcp)
{
uint16_t tport = tcp->th_sport;
tcp->th_sport = tcp->th_dport;
tcp->th_dport = tport;
uint32_t tseq = tcp->th_seq;
tcp->th_seq = tcp->th_ack;
tcp->th_ack = tseq;
}
uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6) uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6)
{ {
@@ -1277,14 +1304,21 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const
{ {
WINDIVERT_ADDRESS wa; WINDIVERT_ADDRESS wa;
if (!ifout) return false;
memset(&wa,0,sizeof(wa)); memset(&wa,0,sizeof(wa));
// pseudo interface id IfIdx.SubIfIdx // pseudo interface id IfIdx.SubIfIdx
if (sscanf(ifout,"%u.%u",&wa.Network.IfIdx,&wa.Network.SubIfIdx)!=2) if (ifout && *ifout)
{ {
errno = EINVAL; if (sscanf(ifout,"%u.%u",&wa.Network.IfIdx,&wa.Network.SubIfIdx)!=2)
return false; {
errno = EINVAL;
return false;
}
}
else
{
// 1 - typically loopback
wa.Network.IfIdx=1;
wa.Network.SubIfIdx=0;
} }
wa.Outbound=1; wa.Outbound=1;
wa.IPChecksum=1; wa.IPChecksum=1;

View File

@@ -162,6 +162,8 @@ struct dissect
size_t len_payload; size_t len_payload;
}; };
void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis); void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis);
void reverse_ip(struct ip *ip, struct ip6_hdr *ip6);
void reverse_tcp(struct tcphdr *tcp);
uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6); uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6);

View File

@@ -246,11 +246,13 @@ static bool is_retransmission(const t_ctrack_position *pos)
} }
// return true if retrans trigger fires // return true if retrans trigger fires
static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int threshold, const char *client_ip_port, t_l7proto l7proto) static bool auto_hostlist_retrans
(t_ctrack *ctrack, const struct dissect *dis, int threshold, const char *client_ip_port, t_l7proto l7proto,
const struct sockaddr *client, const char *ifclient)
{ {
if (ctrack && ctrack->dp && ctrack->hostname_ah_check && !ctrack->failure_detect_finalized && ctrack->req_retrans_counter != RETRANS_COUNTER_STOP) if (ctrack && ctrack->dp && ctrack->hostname_ah_check && !ctrack->failure_detect_finalized && ctrack->req_retrans_counter != RETRANS_COUNTER_STOP)
{ {
if (l4proto == IPPROTO_TCP && ctrack->pos.state!=SYN) if (dis->proto == IPPROTO_TCP && ctrack->pos.state!=SYN)
{ {
if (!seq_within(ctrack->pos.client.seq_last, ctrack->pos.client.seq0, ctrack->pos.client.seq0 + ctrack->dp->hostlist_auto_retrans_maxseq)) if (!seq_within(ctrack->pos.client.seq_last, ctrack->pos.client.seq0, ctrack->pos.client.seq0 + ctrack->dp->hostlist_auto_retrans_maxseq))
{ {
@@ -269,6 +271,46 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho
DLOG("retrans threshold reached : %u/%u\n", ctrack->req_retrans_counter, threshold); DLOG("retrans threshold reached : %u/%u\n", ctrack->req_retrans_counter, threshold);
ctrack_stop_retrans_counter(ctrack); ctrack_stop_retrans_counter(ctrack);
ctrack->failure_detect_finalized = true; ctrack->failure_detect_finalized = true;
if (dis->tcp && ctrack->dp->hostlist_auto_retrans_reset && (dis->ip || dis->ip6))
{
uint8_t pkt[sizeof(struct ip6_hdr)+sizeof(struct tcphdr)];
struct ip *ip;
struct ip6_hdr *ip6;
struct tcphdr *tcp;
uint16_t pktlen;
if (dis->ip)
{
ip = (struct ip*)pkt; ip6=NULL;
pktlen = sizeof(struct ip) + sizeof(struct tcphdr);
*ip = *dis->ip;
ip->ip_hl = sizeof(struct ip)/4; // remove ip options
ip->ip_len = htons(pktlen);
ip->ip_id=0;
tcp = (struct tcphdr*)(ip+1);
*tcp = *dis->tcp;
}
else if (dis->ip6)
{
ip6 = (struct ip6_hdr*)pkt; ip=NULL;
pktlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
*ip6 = *dis->ip6;
ip6->ip6_plen = htons(sizeof(struct tcphdr));
ip6->ip6_nxt = IPPROTO_TCP;
ip6->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(ctrack->pos.server.ip6flow ? ctrack->pos.server.ip6flow : 0x60000000);
tcp = (struct tcphdr*)(ip6+1);
*tcp = *dis->tcp;
}
reverse_ip(ip,ip6); // also fixes ip4 checksum
reverse_tcp(tcp);
tcp->th_off = sizeof(struct tcphdr)/4; // remove tcp options
tcp->th_flags = TH_RST;
tcp->th_win = ctrack->pos.server.winsize;
tcp_fix_checksum(tcp, sizeof(struct tcphdr), ip, ip6);
DLOG("sending RST to retransmitter. ifname=%s\n", ifclient ? ifclient : "");
rawsend(client,0,ifclient,pkt,pktlen);
}
return true; return true;
} }
DLOG("retrans counter : %u/%u\n", ctrack->req_retrans_counter, threshold); DLOG("retrans counter : %u/%u\n", ctrack->req_retrans_counter, threshold);
@@ -330,13 +372,13 @@ static void fill_client_ip_port(const struct sockaddr *client, char *client_ip_p
else else
*client_ip_port = 0; *client_ip_port = 0;
} }
static void process_retrans_fail(t_ctrack *ctrack, uint8_t proto, const struct sockaddr *client) static void process_retrans_fail(t_ctrack *ctrack, const struct dissect *dis, struct sockaddr *client, const char *ifclient)
{ {
if (params.server) return; // no autohostlists in server mode if (params.server) return; // no autohostlists in server mode
char client_ip_port[48]; char client_ip_port[48];
fill_client_ip_port(client, client_ip_port, sizeof(client_ip_port)); fill_client_ip_port(client, client_ip_port, sizeof(client_ip_port));
if (ctrack && ctrack->dp && ctrack->hostname && auto_hostlist_retrans(ctrack, proto, ctrack->dp->hostlist_auto_retrans_threshold, client_ip_port, ctrack->l7proto)) if (ctrack && ctrack->dp && ctrack->hostname && auto_hostlist_retrans(ctrack, dis, ctrack->dp->hostlist_auto_retrans_threshold, client_ip_port, ctrack->l7proto, client, ifclient))
{ {
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : retrans threshold reached", ctrack->hostname, ctrack->dp->n, PROFILE_NAME(ctrack->dp), client_ip_port, l7proto_str(ctrack->l7proto)); HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : retrans threshold reached", ctrack->hostname, ctrack->dp->n, PROFILE_NAME(ctrack->dp), client_ip_port, l7proto_str(ctrack->l7proto));
auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto); auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
@@ -1036,7 +1078,7 @@ static uint8_t dpi_desync_tcp_packet_play(
// in replay mode conntrack_replay is not NULL and ctrack is NULL // in replay mode conntrack_replay is not NULL and ctrack is NULL
//ConntrackPoolDump(&params.conntrack); //ConntrackPoolDump(&params.conntrack);
if (!ConntrackPoolDoubleSearch(&params.conntrack, dis->ip, dis->ip6, dis->tcp, NULL, &ctrack_replay, &bReverse) || bReverse) if (!ConntrackPoolDoubleSearch(&params.conntrack, dis, &ctrack_replay, &bReverse) || bReverse)
return verdict; return verdict;
bReverseFixed = bReverse ^ params.server; bReverseFixed = bReverse ^ params.server;
setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport); setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport);
@@ -1068,7 +1110,7 @@ static uint8_t dpi_desync_tcp_packet_play(
if (!params.ctrack_disable) if (!params.ctrack_disable)
{ {
ConntrackPoolPurge(&params.conntrack); ConntrackPoolPurge(&params.conntrack);
if (ConntrackPoolFeed(&params.conntrack, dis->ip, dis->ip6, dis->tcp, NULL, dis->len_payload, &ctrack, &bReverse)) if (ConntrackPoolFeed(&params.conntrack, dis, &ctrack, &bReverse))
{ {
dp = ctrack->dp; dp = ctrack->dp;
ctrack_replay = ctrack; ctrack_replay = ctrack;
@@ -1144,6 +1186,7 @@ static uint8_t dpi_desync_tcp_packet_play(
else else
bCheckDone = bCheckResult = bCheckExcluded = false; bCheckDone = bCheckResult = bCheckExcluded = false;
bool bHaveHost = false, bHostIsIp = false;
if (bReverse) if (bReverse)
{ {
// protocol detection // protocol detection
@@ -1215,7 +1258,6 @@ static uint8_t dpi_desync_tcp_packet_play(
struct blob_collection_head *fake; struct blob_collection_head *fake;
uint8_t *p, *phost = NULL; uint8_t *p, *phost = NULL;
int i; int i;
bool bHaveHost = false, bHostIsIp = false;
if (replay_piece_count) if (replay_piece_count)
{ {
@@ -1228,7 +1270,8 @@ static uint8_t dpi_desync_tcp_packet_play(
rlen_payload = ctrack->reasm_client.size_present; rlen_payload = ctrack->reasm_client.size_present;
} }
process_retrans_fail(ctrack, IPPROTO_TCP, (struct sockaddr*)&src); process_retrans_fail(ctrack, dis, (struct sockaddr*)&src, ifin);
if (IsHttp(rdata_payload, rlen_payload)) if (IsHttp(rdata_payload, rlen_payload))
{ {
DLOG("packet contains HTTP request\n"); DLOG("packet contains HTTP request\n");
@@ -1313,91 +1356,90 @@ static uint8_t dpi_desync_tcp_packet_play(
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload); protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
} }
if (bHaveHost) }
{
bHostIsIp = strip_host_to_ip(host);
DLOG("hostname: %s\n", host);
}
bool bDiscoveredL7; if (bHaveHost)
{
bHostIsIp = strip_host_to_ip(host);
DLOG("hostname: %s\n", host);
}
bool bDiscoveredL7;
if (ctrack_replay)
{
if ((bDiscoveredL7 = !ctrack_replay->l7proto_discovered && ctrack_replay->l7proto != L7_UNKNOWN))
ctrack_replay->l7proto_discovered = true;
}
else
bDiscoveredL7 = l7proto != L7_UNKNOWN;
if (bDiscoveredL7) DLOG("discovered l7 protocol\n");
bool bDiscoveredHostname = bHaveHost && !(ctrack_replay && ctrack_replay->hostname_discovered);
if (bDiscoveredHostname)
{
DLOG("discovered hostname\n");
if (ctrack_replay) if (ctrack_replay)
{ {
if ((bDiscoveredL7 = !ctrack_replay->l7proto_discovered && ctrack_replay->l7proto != L7_UNKNOWN)) free(ctrack_replay->hostname);
ctrack_replay->l7proto_discovered = true; ctrack_replay->hostname = strdup(host);
} ctrack_replay->hostname_is_ip = bHostIsIp;
else if (!ctrack_replay->hostname)
bDiscoveredL7 = l7proto != L7_UNKNOWN;
if (bDiscoveredL7) DLOG("discovered l7 protocol\n");
bool bDiscoveredHostname = bHaveHost && !(ctrack_replay && ctrack_replay->hostname_discovered);
if (bDiscoveredHostname)
{
DLOG("discovered hostname\n");
if (ctrack_replay)
{ {
free(ctrack_replay->hostname); DLOG_ERR("hostname dup : out of memory");
ctrack_replay->hostname = strdup(host); goto pass_reasm_cancel;
ctrack_replay->hostname_is_ip = bHostIsIp;
if (!ctrack_replay->hostname)
{
DLOG_ERR("hostname dup : out of memory");
goto pass_reasm_cancel;
}
ctrack_replay->hostname_discovered = true;
if (!ipcache_put_hostname(sdip4, sdip6, host, bHostIsIp))
goto pass_reasm_cancel;
} }
} ctrack_replay->hostname_discovered = true;
if (!ipcache_put_hostname(sdip4, sdip6, host, bHostIsIp))
goto pass_reasm_cancel;
}
}
if (bDiscoveredL7 || bDiscoveredHostname) if (bDiscoveredL7 || bDiscoveredHostname)
{
struct desync_profile *dp_prev = dp;
// search for desync profile again. it may have changed.
dp = dp_find(&params.desync_profiles, IPPROTO_TCP, sdip4, sdip6, sdport,
ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL,
ctrack_replay ? ctrack_replay->hostname_is_ip : bHostIsIp,
l7proto, ssid,
&bCheckDone, &bCheckResult, &bCheckExcluded);
if (ctrack_replay)
{ {
struct desync_profile *dp_prev = dp; ctrack_replay->dp = dp;
ctrack_replay->dp_search_complete = true;
// search for desync profile again. it may have changed. ctrack_replay->bCheckDone = bCheckDone;
dp = dp_find(&params.desync_profiles, IPPROTO_TCP, sdip4, sdip6, sdport, ctrack_replay->bCheckResult = bCheckResult;
ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL, ctrack_replay->bCheckExcluded = bCheckExcluded;
ctrack_replay ? ctrack_replay->hostname_is_ip : bHostIsIp, }
l7proto, ssid, if (!dp) goto pass_reasm_cancel;
&bCheckDone, &bCheckResult, &bCheckExcluded); if (dp != dp_prev)
{
dp_changed(ctrack_replay);
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
}
}
if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp))
{
if (!bCheckDone)
{
bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false);
bCheckDone = true;
if (ctrack_replay) if (ctrack_replay)
{ {
ctrack_replay->dp = dp;
ctrack_replay->dp_search_complete = true;
ctrack_replay->bCheckDone = bCheckDone; ctrack_replay->bCheckDone = bCheckDone;
ctrack_replay->bCheckResult = bCheckResult; ctrack_replay->bCheckResult = bCheckResult;
ctrack_replay->bCheckExcluded = bCheckExcluded; ctrack_replay->bCheckExcluded = bCheckExcluded;
} }
if (!dp) goto pass_reasm_cancel;
if (dp != dp_prev)
{
dp_changed(ctrack_replay);
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
}
} }
if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp)) if (bCheckResult)
ctrack_stop_retrans_counter(ctrack_replay);
else
{ {
if (!bCheckDone) if (ctrack_replay)
{ {
bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false); ctrack_replay->hostname_ah_check = dp->hostlist_auto && !bCheckExcluded;
bCheckDone = true; if (!ctrack_replay->hostname_ah_check)
if (ctrack_replay) ctrack_stop_retrans_counter(ctrack_replay);
{
ctrack_replay->bCheckDone = bCheckDone;
ctrack_replay->bCheckResult = bCheckResult;
ctrack_replay->bCheckExcluded = bCheckExcluded;
}
}
if (bCheckResult)
ctrack_stop_retrans_counter(ctrack_replay);
else
{
if (ctrack_replay)
{
ctrack_replay->hostname_ah_check = dp->hostlist_auto && !bCheckExcluded;
if (!ctrack_replay->hostname_ah_check)
ctrack_stop_retrans_counter(ctrack_replay);
}
} }
} }
} }
@@ -1430,6 +1472,25 @@ static void quic_reasm_cancel(t_ctrack *ctrack, const char *reason)
DLOG("%s\n", reason); DLOG("%s\n", reason);
} }
static void udp_standard_protocol_probe(const uint8_t *data_payload, size_t len_payload, t_ctrack *ctrack, t_l7proto *l7proto, t_l7payload *l7payload)
{
t_protocol_probe testers[] = {
{L7P_DISCORD_IP_DISCOVERY,L7_DISCORD,IsDiscordIpDiscoveryRequest,false},
{L7P_STUN,L7_STUN,IsStunMessage,false},
{L7P_DNS_QUERY,L7_DNS,IsDNSQuery,false},
{L7P_DNS_RESPONSE,L7_DNS,IsDNSResponse,false},
{L7P_DHT,L7_DHT,IsDht,false},
{L7P_DTLS_CLIENT_HELLO,L7_DTLS,IsDTLSClientHello,false},
{L7P_DTLS_SERVER_HELLO,L7_DTLS,IsDTLSServerHello,false},
{L7P_WIREGUARD_INITIATION,L7_WIREGUARD,IsWireguardHandshakeInitiation,false},
{L7P_WIREGUARD_RESPONSE,L7_WIREGUARD,IsWireguardHandshakeResponse,false},
{L7P_WIREGUARD_COOKIE,L7_WIREGUARD,IsWireguardHandshakeCookie,false},
{L7P_WIREGUARD_KEEPALIVE,L7_WIREGUARD,IsWireguardKeepalive,false},
{L7P_WIREGUARD_DATA,L7_WIREGUARD,IsWireguardData,true}};
protocol_probe(testers, sizeof(testers) / sizeof(*testers), data_payload, len_payload, ctrack, l7proto, l7payload);
}
static uint8_t dpi_desync_udp_packet_play( static uint8_t dpi_desync_udp_packet_play(
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset,
@@ -1480,7 +1541,7 @@ static uint8_t dpi_desync_udp_packet_play(
// in replay mode conntrack_replay is not NULL and ctrack is NULL // in replay mode conntrack_replay is not NULL and ctrack is NULL
//ConntrackPoolDump(&params.conntrack); //ConntrackPoolDump(&params.conntrack);
if (!ConntrackPoolDoubleSearch(&params.conntrack, dis->ip, dis->ip6, NULL, dis->udp, &ctrack_replay, &bReverse) || bReverse) if (!ConntrackPoolDoubleSearch(&params.conntrack, dis, &ctrack_replay, &bReverse) || bReverse)
return verdict; return verdict;
bReverseFixed = bReverse ^ params.server; bReverseFixed = bReverse ^ params.server;
setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport); setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport);
@@ -1512,7 +1573,7 @@ static uint8_t dpi_desync_udp_packet_play(
if (!params.ctrack_disable) if (!params.ctrack_disable)
{ {
ConntrackPoolPurge(&params.conntrack); ConntrackPoolPurge(&params.conntrack);
if (ConntrackPoolFeed(&params.conntrack, dis->ip, dis->ip6, NULL, dis->udp, dis->len_payload, &ctrack, &bReverse)) if (ConntrackPoolFeed(&params.conntrack, dis, &ctrack, &bReverse))
{ {
dp = ctrack->dp; dp = ctrack->dp;
ctrack_replay = ctrack; ctrack_replay = ctrack;
@@ -1589,24 +1650,14 @@ static uint8_t dpi_desync_udp_packet_play(
if (dis->len_payload) if (dis->len_payload)
{ {
bool bHaveHost = false, bHostIsIp = false;
if (bReverse) if (bReverse)
{ {
t_protocol_probe testers[] = { udp_standard_protocol_probe(dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
{L7P_DNS_RESPONSE,L7_DNS,IsDNSResponse,false},
{L7P_DHT,L7_DHT,IsDht,false},
{L7P_STUN,L7_STUN,IsStunMessage,false},
{L7P_WIREGUARD_INITIATION,L7_WIREGUARD,IsWireguardHandshakeInitiation,false},
{L7P_WIREGUARD_RESPONSE,L7_WIREGUARD,IsWireguardHandshakeResponse,false},
{L7P_WIREGUARD_COOKIE,L7_WIREGUARD,IsWireguardHandshakeCookie,false},
{L7P_WIREGUARD_KEEPALIVE,L7_WIREGUARD,IsWireguardKeepalive,false},
{L7P_WIREGUARD_DATA,L7_WIREGUARD,IsWireguardData,true}
};
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
} }
else else
{ {
struct blob_collection_head *fake; struct blob_collection_head *fake;
bool bHaveHost = false, bHostIsIp = false;
if (IsQUICInitial(dis->data_payload, dis->len_payload)) if (IsQUICInitial(dis->data_payload, dis->len_payload))
{ {
DLOG("packet contains QUIC initial\n"); DLOG("packet contains QUIC initial\n");
@@ -1739,115 +1790,97 @@ static uint8_t dpi_desync_udp_packet_play(
} }
else // not QUIC initial else // not QUIC initial
{ {
// received payload without host. it means we are out of the request retransmission phase. stop counter // not quic initial - stop reasm
ctrack_stop_retrans_counter(ctrack);
reasm_client_cancel(ctrack); reasm_client_cancel(ctrack);
t_protocol_probe testers[] = { udp_standard_protocol_probe(dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
{L7P_DISCORD_IP_DISCOVERY,L7_DISCORD,IsDiscordIpDiscoveryRequest,false},
{L7P_STUN,L7_STUN,IsStunMessage,false},
{L7P_DNS_QUERY,L7_DNS,IsDNSQuery,false},
{L7P_DHT,L7_DHT,IsDht,false},
{L7P_WIREGUARD_INITIATION,L7_WIREGUARD,IsWireguardHandshakeInitiation,false},
{L7P_WIREGUARD_RESPONSE,L7_WIREGUARD,IsWireguardHandshakeResponse,false},
{L7P_WIREGUARD_COOKIE,L7_WIREGUARD,IsWireguardHandshakeCookie,false},
{L7P_WIREGUARD_KEEPALIVE,L7_WIREGUARD,IsWireguardKeepalive,false},
{L7P_WIREGUARD_DATA,L7_WIREGUARD,IsWireguardData,true}
};
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
} }
}
if (bHaveHost) if (bHaveHost)
{ {
bHostIsIp = strip_host_to_ip(host); bHostIsIp = strip_host_to_ip(host);
DLOG("hostname: %s\n", host); DLOG("hostname: %s\n", host);
} }
bool bDiscoveredL7; bool bDiscoveredL7;
if (ctrack_replay)
{
if ((bDiscoveredL7 = !ctrack_replay->l7proto_discovered && l7proto != L7_UNKNOWN))
ctrack_replay->l7proto_discovered = true;
}
else
bDiscoveredL7 = l7proto != L7_UNKNOWN;
if (bDiscoveredL7) DLOG("discovered l7 protocol\n");
bool bDiscoveredHostname = bHaveHost && !(ctrack_replay && ctrack_replay->hostname_discovered);
if (bDiscoveredHostname)
{
DLOG("discovered hostname\n");
if (ctrack_replay) if (ctrack_replay)
{ {
if ((bDiscoveredL7 = !ctrack_replay->l7proto_discovered && l7proto != L7_UNKNOWN)) ctrack_replay->hostname_discovered = true;
ctrack_replay->l7proto_discovered = true; free(ctrack_replay->hostname);
} ctrack_replay->hostname = strdup(host);
else ctrack_replay->hostname_is_ip = bHostIsIp;
bDiscoveredL7 = l7proto != L7_UNKNOWN; if (!ctrack_replay->hostname)
if (bDiscoveredL7) DLOG("discovered l7 protocol\n");
bool bDiscoveredHostname = bHaveHost && !(ctrack_replay && ctrack_replay->hostname_discovered);
if (bDiscoveredHostname)
{
DLOG("discovered hostname\n");
if (ctrack_replay)
{ {
ctrack_replay->hostname_discovered = true; DLOG_ERR("hostname dup : out of memory");
free(ctrack_replay->hostname); goto pass;
ctrack_replay->hostname = strdup(host);
ctrack_replay->hostname_is_ip = bHostIsIp;
if (!ctrack_replay->hostname)
{
DLOG_ERR("hostname dup : out of memory");
goto pass;
}
if (!ipcache_put_hostname(sdip4, sdip6, host, bHostIsIp))
goto pass;
} }
if (!ipcache_put_hostname(sdip4, sdip6, host, bHostIsIp))
goto pass;
} }
}
if (bDiscoveredL7 || bDiscoveredHostname) if (bDiscoveredL7 || bDiscoveredHostname)
{
struct desync_profile *dp_prev = dp;
// search for desync profile again. it may have changed.
dp = dp_find(&params.desync_profiles, IPPROTO_UDP, sdip4, sdip6, sdport,
ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL,
ctrack_replay ? ctrack_replay->hostname_is_ip : bHostIsIp,
l7proto, ssid,
&bCheckDone, &bCheckResult, &bCheckExcluded);
if (ctrack_replay)
{ {
struct desync_profile *dp_prev = dp; ctrack_replay->dp = dp;
ctrack_replay->dp_search_complete = true;
ctrack_replay->bCheckDone = bCheckDone;
ctrack_replay->bCheckResult = bCheckResult;
ctrack_replay->bCheckExcluded = bCheckExcluded;
}
if (!dp)
goto pass_reasm_cancel;
if (dp != dp_prev)
{
dp_changed(ctrack_replay);
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
}
}
else if (ctrack_replay)
{
bCheckDone = ctrack_replay->bCheckDone;
bCheckResult = ctrack_replay->bCheckResult;
bCheckExcluded = ctrack_replay->bCheckExcluded;
}
// search for desync profile again. it may have changed. if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp))
dp = dp_find(&params.desync_profiles, IPPROTO_UDP, sdip4, sdip6, sdport, {
ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL, if (!bCheckDone)
ctrack_replay ? ctrack_replay->hostname_is_ip : bHostIsIp, {
l7proto, ssid, bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false);
&bCheckDone, &bCheckResult, &bCheckExcluded); bCheckDone = true;
if (ctrack_replay) if (ctrack_replay)
{ {
ctrack_replay->dp = dp;
ctrack_replay->dp_search_complete = true;
ctrack_replay->bCheckDone = bCheckDone; ctrack_replay->bCheckDone = bCheckDone;
ctrack_replay->bCheckResult = bCheckResult; ctrack_replay->bCheckResult = bCheckResult;
ctrack_replay->bCheckExcluded = bCheckExcluded; ctrack_replay->bCheckExcluded = bCheckExcluded;
} }
if (!dp)
goto pass_reasm_cancel;
if (dp != dp_prev)
{
dp_changed(ctrack_replay);
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
}
}
else if (ctrack_replay)
{
bCheckDone = ctrack_replay->bCheckDone;
bCheckResult = ctrack_replay->bCheckResult;
bCheckExcluded = ctrack_replay->bCheckExcluded;
}
if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp))
{
if (!bCheckDone)
{
bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false);
bCheckDone = true;
if (ctrack_replay)
{
ctrack_replay->bCheckDone = bCheckDone;
ctrack_replay->bCheckResult = bCheckResult;
ctrack_replay->bCheckExcluded = bCheckExcluded;
}
}
if (bCheckResult)
ctrack_stop_retrans_counter(ctrack_replay);
else
{
if (ctrack_replay)
ctrack_replay->hostname_ah_check = dp->hostlist_auto && !bCheckExcluded;
}
} }
if (!bCheckResult && ctrack_replay)
ctrack_replay->hostname_ah_check = dp->hostlist_auto && !bCheckExcluded;
} }
process_udp_fail(ctrack_replay, tpos, (struct sockaddr*)&src); process_udp_fail(ctrack_replay, tpos, (struct sockaddr*)&src);

View File

@@ -412,7 +412,7 @@ static int luacall_parse_hex(lua_State *L)
LUA_STACK_GUARD_ENTER(L) LUA_STACK_GUARD_ENTER(L)
size_t l; size_t l;
const char *hex = lua_tolstring(L,1,&l); const char *hex = luaL_checklstring(L,1,&l);
if ((l&1)) goto err; if ((l&1)) goto err;
l>>=1; l>>=1;
uint8_t *p = malloc(l); uint8_t *p = malloc(l);
@@ -1276,6 +1276,7 @@ void lua_pushf_ctrack_pos(const t_ctrack *ctrack, const t_ctrack_position *pos)
lua_pushf_lint("pcounter", pos->pcounter); lua_pushf_lint("pcounter", pos->pcounter);
lua_pushf_lint("pdcounter", pos->pdcounter); lua_pushf_lint("pdcounter", pos->pdcounter);
lua_pushf_lint("pbcounter", pos->pbcounter); lua_pushf_lint("pbcounter", pos->pbcounter);
if (pos->ip6flow) lua_pushf_int("ip6_flow", pos->ip6flow);
if (ctrack->ipproto == IPPROTO_TCP) if (ctrack->ipproto == IPPROTO_TCP)
{ {
lua_pushliteral(params.L, "tcp"); lua_pushliteral(params.L, "tcp");
@@ -1658,7 +1659,7 @@ bool lua_reconstruct_iphdr(int idx, struct ip *ip, size_t *len)
if (lua_type(params.L,-1)==LUA_TSTRING) if (lua_type(params.L,-1)==LUA_TSTRING)
{ {
p = lua_tolstring(params.L,-1,&lopt); p = lua_tolstring(params.L,-1,&lopt);
if (lopt) if (p && lopt)
{ {
if (lopt>40 || ((sizeof(struct ip) + ((lopt+3)&~3)) > *len)) goto err; if (lopt>40 || ((sizeof(struct ip) + ((lopt+3)&~3)) > *len)) goto err;
memcpy(ip+1,p,lopt); memcpy(ip+1,p,lopt);
@@ -1990,7 +1991,7 @@ bool lua_reconstruct_dissect(int idx, uint8_t *buf, size_t *len, bool badsum, bo
lua_getfield(params.L,idx,"payload"); lua_getfield(params.L,idx,"payload");
p = lua_tolstring(params.L,-1,&lpayload); p = lua_tolstring(params.L,-1,&lpayload);
if (lpayload) if (p && lpayload)
{ {
if (left<lpayload) goto err; if (left<lpayload) goto err;
memcpy(data,p,lpayload); memcpy(data,p,lpayload);
@@ -3004,6 +3005,8 @@ static void lua_init_const(void)
{"IPTOS_ECN_CE",IPTOS_ECN_CE}, {"IPTOS_ECN_CE",IPTOS_ECN_CE},
{"IPTOS_DSCP_MASK",0xF0}, {"IPTOS_DSCP_MASK",0xF0},
{"IP6F_MORE_FRAG",0x0001}, // in ip6.h it's defined depending of machine byte order {"IP6F_MORE_FRAG",0x0001}, // in ip6.h it's defined depending of machine byte order
{"IPV6_FLOWLABEL_MASK",0x000FFFFF},
{"IPV6_FLOWINFO_MASK",0x0FFFFFFF},
{"IPPROTO_IP",IPPROTO_IP}, {"IPPROTO_IP",IPPROTO_IP},
{"IPPROTO_IPV6",IPPROTO_IPV6}, {"IPPROTO_IPV6",IPPROTO_IPV6},

View File

@@ -538,7 +538,7 @@ static int dvt_main(void)
DLOG("\npacket: id=%u len=%zu ifin=%s ifout=%s\n", id, len, ifin, ifout); DLOG("\npacket: id=%u len=%zu ifin=%s ifout=%s\n", id, len, ifin, ifout);
modlen = sizeof(buf); modlen = sizeof(buf);
verdict = processPacketData(&mark, NULL, NULL, buf, len, buf, &modlen); verdict = processPacketData(&mark, ifin, ifout, buf, len, buf, &modlen);
switch (verdict & VERDICT_MASK) switch (verdict & VERDICT_MASK)
{ {
case VERDICT_PASS: case VERDICT_PASS:
@@ -726,6 +726,7 @@ ex:
static void exit_clean(int code) static void exit_clean(int code)
{ {
cleanup_params(&params); cleanup_params(&params);
exit(code); exit(code);
} }
@@ -1435,6 +1436,7 @@ static void exithelp(void)
" --hostlist-auto-fail-time=<int>\t\t\t; all failed attemps must be within these seconds (default : %d)\n" " --hostlist-auto-fail-time=<int>\t\t\t; all failed attemps must be within these seconds (default : %d)\n"
" --hostlist-auto-retrans-threshold=<int>\t\t; how many request retransmissions cause attempt to fail (default : %d)\n" " --hostlist-auto-retrans-threshold=<int>\t\t; how many request retransmissions cause attempt to fail (default : %d)\n"
" --hostlist-auto-retrans-maxseq=<int>\t\t\t; count retransmissions only within this relative sequence (default : %u)\n" " --hostlist-auto-retrans-maxseq=<int>\t\t\t; count retransmissions only within this relative sequence (default : %u)\n"
" --hostlist-auto-retrans-reset=[0|1]\t\t\t; send RST to retransmitter to break long wait (default: 1)\n"
" --hostlist-auto-incoming-maxseq=<int>\t\t\t; treat tcp connection as successful if incoming relative sequence exceedes this threshold (default : %u)\n" " --hostlist-auto-incoming-maxseq=<int>\t\t\t; treat tcp connection as successful if incoming relative sequence exceedes this threshold (default : %u)\n"
" --hostlist-auto-udp-out=<int>\t\t\t\t; udp failure condition : sent at least `udp_out` packets (default : %u)\n" " --hostlist-auto-udp-out=<int>\t\t\t\t; udp failure condition : sent at least `udp_out` packets (default : %u)\n"
" --hostlist-auto-udp-in=<int>\t\t\t\t; udp failure condition : received not more than `udp_in` packets (default : %u)\n" " --hostlist-auto-udp-in=<int>\t\t\t\t; udp failure condition : received not more than `udp_in` packets (default : %u)\n"
@@ -1553,6 +1555,7 @@ enum opt_indices {
IDX_HOSTLIST_AUTO_FAIL_TIME, IDX_HOSTLIST_AUTO_FAIL_TIME,
IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD, IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD,
IDX_HOSTLIST_AUTO_RETRANS_MAXSEQ, IDX_HOSTLIST_AUTO_RETRANS_MAXSEQ,
IDX_HOSTLIST_AUTO_RETRANS_RESET,
IDX_HOSTLIST_AUTO_INCOMING_MAXSEQ, IDX_HOSTLIST_AUTO_INCOMING_MAXSEQ,
IDX_HOSTLIST_AUTO_UDP_IN, IDX_HOSTLIST_AUTO_UDP_IN,
IDX_HOSTLIST_AUTO_UDP_OUT, IDX_HOSTLIST_AUTO_UDP_OUT,
@@ -1641,6 +1644,7 @@ static const struct option long_options[] = {
[IDX_HOSTLIST_AUTO_FAIL_TIME] = {"hostlist-auto-fail-time", required_argument, 0, 0}, [IDX_HOSTLIST_AUTO_FAIL_TIME] = {"hostlist-auto-fail-time", required_argument, 0, 0},
[IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD] = {"hostlist-auto-retrans-threshold", required_argument, 0, 0}, [IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD] = {"hostlist-auto-retrans-threshold", required_argument, 0, 0},
[IDX_HOSTLIST_AUTO_RETRANS_MAXSEQ] = {"hostlist-auto-retrans-maxseq", required_argument, 0, 0}, [IDX_HOSTLIST_AUTO_RETRANS_MAXSEQ] = {"hostlist-auto-retrans-maxseq", required_argument, 0, 0},
[IDX_HOSTLIST_AUTO_RETRANS_RESET] = {"hostlist-auto-retrans-reset", optional_argument, 0, 0},
[IDX_HOSTLIST_AUTO_INCOMING_MAXSEQ] = {"hostlist-auto-incoming-maxseq", required_argument, 0, 0}, [IDX_HOSTLIST_AUTO_INCOMING_MAXSEQ] = {"hostlist-auto-incoming-maxseq", required_argument, 0, 0},
[IDX_HOSTLIST_AUTO_UDP_IN] = {"hostlist-auto-udp-in", required_argument, 0, 0}, [IDX_HOSTLIST_AUTO_UDP_IN] = {"hostlist-auto-udp-in", required_argument, 0, 0},
[IDX_HOSTLIST_AUTO_UDP_OUT] = {"hostlist-auto-udp-out", required_argument, 0, 0}, [IDX_HOSTLIST_AUTO_UDP_OUT] = {"hostlist-auto-udp-out", required_argument, 0, 0},
@@ -2099,6 +2103,9 @@ int main(int argc, char **argv)
case IDX_HOSTLIST_AUTO_INCOMING_MAXSEQ: case IDX_HOSTLIST_AUTO_INCOMING_MAXSEQ:
dp->hostlist_auto_incoming_maxseq = (uint32_t)atoi(optarg); dp->hostlist_auto_incoming_maxseq = (uint32_t)atoi(optarg);
break; break;
case IDX_HOSTLIST_AUTO_RETRANS_RESET:
dp->hostlist_auto_retrans_reset = !optarg || !!atoi(optarg);
break;
case IDX_HOSTLIST_AUTO_UDP_OUT: case IDX_HOSTLIST_AUTO_UDP_OUT:
dp->hostlist_auto_udp_out = atoi(optarg); dp->hostlist_auto_udp_out = atoi(optarg);
break; break;

View File

@@ -350,6 +350,7 @@ void dp_init(struct desync_profile *dp)
dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT; dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT; dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
dp->hostlist_auto_retrans_maxseq = HOSTLIST_AUTO_RETRANS_MAXSEQ; dp->hostlist_auto_retrans_maxseq = HOSTLIST_AUTO_RETRANS_MAXSEQ;
dp->hostlist_auto_retrans_reset = true;
dp->hostlist_auto_incoming_maxseq = HOSTLIST_AUTO_INCOMING_MAXSEQ; dp->hostlist_auto_incoming_maxseq = HOSTLIST_AUTO_INCOMING_MAXSEQ;
dp->hostlist_auto_udp_out = HOSTLIST_AUTO_UDP_OUT; dp->hostlist_auto_udp_out = HOSTLIST_AUTO_UDP_OUT;
dp->hostlist_auto_udp_in = HOSTLIST_AUTO_UDP_IN; dp->hostlist_auto_udp_in = HOSTLIST_AUTO_UDP_IN;

View File

@@ -84,6 +84,7 @@ struct desync_profile
int hostlist_auto_fail_threshold, hostlist_auto_fail_time, hostlist_auto_retrans_threshold; int hostlist_auto_fail_threshold, hostlist_auto_fail_time, hostlist_auto_retrans_threshold;
int hostlist_auto_udp_in, hostlist_auto_udp_out; int hostlist_auto_udp_in, hostlist_auto_udp_out;
uint32_t hostlist_auto_retrans_maxseq, hostlist_auto_incoming_maxseq; uint32_t hostlist_auto_retrans_maxseq, hostlist_auto_incoming_maxseq;
bool hostlist_auto_retrans_reset;
hostfail_pool *hostlist_auto_fail_counters; hostfail_pool *hostlist_auto_fail_counters;

View File

@@ -29,7 +29,9 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **
return true; return true;
} }
static const char *l7proto_name[] = {"all","unknown","known","http","tls","quic","wireguard","dht","discord","stun","xmpp","dns","mtproto"}; static const char *l7proto_name[] = {
"all","unknown","known","http","tls","dtls","quic","wireguard","dht","discord","stun","xmpp","dns","mtproto"
};
const char *l7proto_str(t_l7proto l7) const char *l7proto_str(t_l7proto l7)
{ {
if (l7>=L7_LAST) return NULL; if (l7>=L7_LAST) return NULL;
@@ -46,7 +48,11 @@ bool l7_proto_match(t_l7proto l7proto, uint64_t filter_l7)
} }
static const char *l7payload_name[] = { static const char *l7payload_name[] = {
"all","unknown","empty","known","http_req","http_reply","tls_client_hello","tls_server_hello","quic_initial", "all","unknown","empty","known",
"http_req","http_reply",
"tls_client_hello","tls_server_hello",
"dtls_client_hello","dtls_server_hello",
"quic_initial",
"wireguard_initiation","wireguard_response","wireguard_cookie","wireguard_keepalive","wireguard_data", "wireguard_initiation","wireguard_response","wireguard_cookie","wireguard_keepalive","wireguard_data",
"dht","discord_ip_discovery","stun", "dht","discord_ip_discovery","stun",
"xmpp_stream", "xmpp_starttls", "xmpp_proceed", "xmpp_features", "xmpp_stream", "xmpp_starttls", "xmpp_proceed", "xmpp_features",
@@ -458,9 +464,10 @@ bool IsTLSRecordFull(const uint8_t *data, size_t len)
} }
bool IsTLSHandshakeHello(const uint8_t *data, size_t len, uint8_t type, bool bPartialIsOK) bool IsTLSHandshakeHello(const uint8_t *data, size_t len, uint8_t type, bool bPartialIsOK)
{ {
// return len >= 1 && (type && data[0]==type || !type && (data[0]==0x01 || data[0]==0x02)) && (bPartialIsOK || IsTLSHandshakeFull(data,len)); return len >= 6 &&
(type && data[0]==type || !type && (data[0]==0x01 || data[0]==0x02)) &&
return len >= 1 && (type && data[0]==type || !type && (data[0]==0x01 || data[0]==0x02)) && (bPartialIsOK || IsTLSHandshakeFull(data,len)); data[4]==0x03 && data[5] <= 0x03 &&
(bPartialIsOK || IsTLSHandshakeFull(data,len));
} }
bool IsTLSHandshakeClientHello(const uint8_t *data, size_t len, bool bPartialIsOK) bool IsTLSHandshakeClientHello(const uint8_t *data, size_t len, bool bPartialIsOK)
{ {
@@ -1401,7 +1408,11 @@ bool IsWireguardKeepalive(const uint8_t *data, size_t len)
} }
bool IsDht(const uint8_t *data, size_t len) bool IsDht(const uint8_t *data, size_t len)
{ {
return len>=7 && data[0]=='d' && (data[1]=='1' || data[1]=='2') && data[2]==':' && data[len-1]=='e'; return len>=5 && data[0]=='d' && data[2]==':' && data[len-1]=='e' &&
(data[1]=='1' && data[3]=='a' && data[4]=='d' ||
data[1]=='1' && data[3]=='r' && data[4]=='d' ||
data[1]=='2' && data[3]=='i' && data[4]=='p' ||
data[1]=='1' && data[3]=='e' && data[4]=='l');
} }
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len) bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len)
{ {
@@ -1445,3 +1456,22 @@ bool IsMTProto(const uint8_t *data, size_t len)
} }
return false; return false;
} }
bool IsDTLS(const uint8_t *data, size_t len)
{
return ((len > 13) &&
(data[0]>=0x14 && data[0]<=0x17) && /* Handshake, change-cipher-spec, Application-Data, Alert */
((data[1] == 0xfe && data[2] == 0xff) || /* Versions */
(data[1] == 0xfe && data[2] == 0xfd) ||
(data[1] == 0xfe && data[2] == 0xfc) ||
(data[1] == 0x01 && data[2] == 0x00)) &&
(pntoh16(data+11)+13)<=len);
}
bool IsDTLSClientHello(const uint8_t *data, size_t len)
{
return IsDTLS(data,len) && data[0]==0x16 && data[13]==1;
}
bool IsDTLSServerHello(const uint8_t *data, size_t len)
{
return IsDTLS(data,len) && data[0]==0x16 && data[13]==2;
}

View File

@@ -11,6 +11,7 @@ typedef enum {
L7_KNOWN, L7_KNOWN,
L7_HTTP, L7_HTTP,
L7_TLS, L7_TLS,
L7_DTLS,
L7_QUIC, L7_QUIC,
L7_WIREGUARD, L7_WIREGUARD,
L7_DHT, L7_DHT,
@@ -34,6 +35,8 @@ typedef enum {
L7P_HTTP_REPLY, L7P_HTTP_REPLY,
L7P_TLS_CLIENT_HELLO, L7P_TLS_CLIENT_HELLO,
L7P_TLS_SERVER_HELLO, L7P_TLS_SERVER_HELLO,
L7P_DTLS_CLIENT_HELLO,
L7P_DTLS_SERVER_HELLO,
L7P_QUIC_INITIAL, L7P_QUIC_INITIAL,
L7P_WIREGUARD_INITIATION, L7P_WIREGUARD_INITIATION,
L7P_WIREGUARD_RESPONSE, L7P_WIREGUARD_RESPONSE,
@@ -155,6 +158,10 @@ bool IsDht(const uint8_t *data, size_t len);
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len); bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len);
bool IsStunMessage(const uint8_t *data, size_t len); bool IsStunMessage(const uint8_t *data, size_t len);
bool IsMTProto(const uint8_t *data, size_t len); bool IsMTProto(const uint8_t *data, size_t len);
bool IsDTLS(const uint8_t *data, size_t len);
bool IsDTLSClientHello(const uint8_t *data, size_t len);
bool IsDTLSServerHello(const uint8_t *data, size_t len);
#define QUIC_MAX_CID_LENGTH 20 #define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid { typedef struct quic_cid {