Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-15 14:36:09 +00:00

13 Commits
v0.3 ... v0.4

Author SHA1 Message Date
bol-van
7f4bdd5eb4 update changes.txt 2025-12-05 11:09:48 +03:00
bol-van
0588240d8d nfqws2: LUA_COMPAT_VER tracking 2025-12-05 11:07:14 +03:00
bol-van
b9e03ef71b nfqws2: --template <name> , --cookie 2025-12-05 10:23:33 +03:00
bol-van
9c0c7cfa8c init.d: remove stun_binding_req 2025-12-04 23:24:05 +03:00
bol-van
807ad5953b nfqws2: profile templates, remove stun_bindin_req detalisation 2025-12-04 23:22:27 +03:00
bol-van
ee031db3a1 blockcheck2: fix broken DNS cache 2025-12-04 14:57:00 +03:00
bol-van
93e4df72e5 zapret-lib: apply_arg_prefix, posdebug, argdebug 2025-12-03 16:08:12 +03:00
bol-van
e62d3919f4 nfqws2: proper conntrack position of replay pieces 2025-12-03 16:07:10 +03:00
bol-van
63414f8608 zapret-lib: typo 2025-12-02 21:55:09 +03:00
bol-van
18974e6c1f zapret-lib: separate execution plan replay function 2025-12-02 21:54:28 +03:00
bol-van
e61967ac2b nfqws2: profile names 2025-12-02 21:38:45 +03:00
bol-van
6010307667 nfqws2: post payload filter and range in exec plan, zapret-lib: duplicate range check logic 2025-12-02 20:48:03 +03:00
bol-van
04ceb589e0 nfqws2: desync orchestration luacalls 2025-12-02 17:49:23 +03:00
24 changed files with 1134 additions and 483 deletions

View File

@@ -275,44 +275,45 @@ mdig_cache()
mdig_resolve()
{
# $1 - ip version 4/6
# $2 - hostname, possibly with uri : rutracker.org/xxx/xxxx
local hostvar cachevar countvar count ip n sdom
# $2 - var to receive result
# $3 - hostname, possibly with uri : rutracker.org/xxx/xxxx
local hostvar cachevar countvar count n sdom
split_by_separator "$2" / sdom
split_by_separator "$3" / sdom
mdig_vars "$1" "$sdom"
if [ -n "$count" ]; then
n=$(random 0 $(($count-1)))
eval ip=\$${cachevar}_$n
echo $ip
eval $2=\$${cachevar}_$n
return 0
else
mdig_cache "$1" "$sdom" && mdig_resolve "$1" "$sdom"
mdig_cache "$1" "$sdom" && mdig_resolve "$1" "$2" "$sdom"
fi
}
mdig_resolve_all()
{
# $1 - ip version 4/6
# $2 - hostname
# $2 - var to receive result
# $3 - hostname
local hostvar cachevar countvar count ip ips n sdom
local hostvar cachevar countvar count ip__ ips__ n sdom
split_by_separator "$2" / sdom
split_by_separator "$3" / sdom
mdig_vars "$1" "$sdom"
if [ -n "$count" ]; then
n=0
while [ "$n" -le $count ]; do
eval ip=\$${cachevar}_$n
if [ -n "$ips" ]; then
ips="$ips $ip"
eval ip__=\$${cachevar}_$n
if [ -n "$ips__" ]; then
ips__="$ips__ $ip__"
else
ips="$ip"
ips__="$ip__"
fi
n=$(($n + 1))
done
echo "$ips"
eval $2="\$ips__"
return 0
else
mdig_cache "$1" "$sdom" && mdig_resolve_all "$1" "$sdom"
mdig_cache "$1" "$sdom" && mdig_resolve_all "$1" "$2" "$sdom"
fi
}
@@ -640,7 +641,7 @@ curl_with_dig()
local sdom suri ip
split_by_separator "$dom" / sdom suri
ip=$(mdig_resolve $1 $sdom)
mdig_resolve $1 ip $sdom
shift ; shift ; shift
if [ -n "$ip" ]; then
curl_with_subst_ip "$sdom" "$port" "$ip" "$@"
@@ -965,7 +966,7 @@ check_domain_port_block()
echo
echo \* port block tests ipv$IPV $1:$2
if netcat_setup; then
ips=$(mdig_resolve_all $IPV $1)
mdig_resolve_all $IPV ips $1
if [ -n "$ips" ]; then
for ip in $ips; do
if netcat_test $ip $2; then
@@ -1254,7 +1255,7 @@ check_dpi_ip_block()
echo "> testing $UNBLOCKED_DOM on it's original ip"
if curl_test $1 $UNBLOCKED_DOM; then
unblocked_ip=$(mdig_resolve $IPV $UNBLOCKED_DOM)
mdig_resolve $IPV unblocked_ip $UNBLOCKED_DOM
[ -n "$unblocked_ip" ] || {
echo $UNBLOCKED_DOM does not resolve. tests not possible.
return 1
@@ -1263,7 +1264,7 @@ check_dpi_ip_block()
echo "> testing $blocked_dom on $unblocked_ip ($UNBLOCKED_DOM)"
curl_test $1 $blocked_dom $unblocked_ip detail
blocked_ips=$(mdig_resolve_all $IPV $blocked_dom)
mdig_resolve_all $IPV blocked_ips $blocked_dom
for blocked_ip in $blocked_ips; do
echo "> testing $UNBLOCKED_DOM on $blocked_ip ($blocked_dom)"
curl_test $1 $UNBLOCKED_DOM $blocked_ip detail
@@ -1314,6 +1315,8 @@ check_domain_http_tcp()
# $3 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk
# $4 - domain
local ips
# in case was interrupted before
pktws_ipt_unprepare_tcp $2
ws_kill
@@ -1325,7 +1328,8 @@ check_domain_http_tcp()
[ "$SKIP_PKTWS" = 1 ] || {
echo
echo preparing $PKTWSD redirection
pktws_ipt_prepare_tcp $2 "$(mdig_resolve_all $IPV $4)"
mdig_resolve_all $IPV ips $4
pktws_ipt_prepare_tcp $2 "$ips"
pktws_check_domain_http_bypass $1 $3 $4
@@ -1339,6 +1343,8 @@ check_domain_http_udp()
# $2 - port
# $3 - domain
local ips
# in case was interrupted before
pktws_ipt_unprepare_udp $2
ws_kill
@@ -1348,7 +1354,8 @@ check_domain_http_udp()
[ "$SKIP_PKTWS" = 1 ] || {
echo
echo preparing $PKTWSD redirection
pktws_ipt_prepare_udp $2 "$(mdig_resolve_all $IPV $3)"
mdig_resolve_all $IPV ips $4
pktws_ipt_prepare_udp $2 "$ips"
pktws_check_domain_http3_bypass $1 $3

View File

@@ -36,6 +36,16 @@ v0.2
* zapret-pcap
v0.3
* init.d launch scripts
* init.d: 40-webserver custom script
* install_easy
v0.4
* nfqws2: profile names and cookies
* nfqws2: profile templates
* nfqws2: remove stun_binding_req, replace to stun. no more message type details
* nfqws2: proper conntack position for replayed packets
* blockcheck2: fix broken dns cache
* nfqws2: LUA_COMPAT_VER tracking

7
docs/changes_compat.txt Normal file
View File

@@ -0,0 +1,7 @@
Here listed all api breaking changes.
When something changes capable of breaking things NFQWS2_COMPAT_VER increases.
v2
* removed "stun_binding_req" specialized payload. replaced with common "stun" - any stun packets, not only binding request.
every LUA relying on desync.l7payload should be revised.
nfqws2 --payload option and init.d custom scripts must be updated.

View File

@@ -361,7 +361,7 @@ start "zapret: http,https,quic" /min "%~dp0winws2.exe" ^
--new ^
--filter-l7=wireguard,stun,discord ^
--out-range=-d10 ^
--payload=wireguard_initiation,wireguard_cookie,stun_binding_req,discord_ip_discovery ^
--payload=wireguard_initiation,wireguard_cookie,stun,discord_ip_discovery ^
--lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2
```

View File

@@ -2,7 +2,7 @@
# 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 :
NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---payload stun_binding_req --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---payload stun --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
alloc_dnum DNUM_STUN4ALL
alloc_qnum QNUM_STUN4ALL

View File

@@ -35,7 +35,135 @@ function pktdebug(ctx, desync)
DLOG("desync:")
var_debug(desync)
end
-- basic desync function
-- prints function args
function argdebug(ctx,desync)
var_debug(desync.arg)
end
-- basic desync function
-- prints conntrack positions to DLOG
function posdebug(ctx,desync)
local s="posdebug:"
for i,pos in pairs({'n','d','b','s'}) do
s=s.." "..pos..pos_get(desync,pos)
end
s=s.." payload "..#desync.dis.payload
if desync.reasm_data then
s=s.." reasm "..#desync.reasm_data
end
if desync.decrypt_data then
s=s.." decrypt "..#desync.decrypt_data
end
if desync.replay_piece_count then
s=s.." replay "..desync.replay_piece.."/"..desync.replay_piece_count
end
DLOG(s)
end
-- applies # and $ prefixes. #var means var length, %var means var value
function apply_arg_prefix(arg)
for a,v in pairs(arg) do
local c = string.sub(v,1,1)
if v=='#' then
arg[a] = #_G[string.sub(v,2)]
elseif v=='%' then
arg[a] = _G[string.sub(v,2)]
elseif v=='\\' then
c = string.sub(v,2,2);
if c=='#' or c=='%' then
arg[a] = string.sub(v,2)
end
end
end
end
-- copy instance identification and args from execution plan to desync table
function apply_execution_plan(desync, plan)
desync.func = plan.func
desync.func_n = plan.func_n
desync.func_instance = plan.func_instance
desync.arg = deepcopy(plan.arg)
apply_arg_prefix(desync.arg)
end
-- redo what whould be done without orchestration
function replay_execution_plan(desync, plan)
for i=1,#plan do
if not payload_match_filter(desync.l7payload, plan[i].payload_filter) then
DLOG("orchestrator: not calling '"..desync.func_instance.."' because payload '"..desync.l7payload.."' does not match filter '"..plan[i].payload_filter.."'")
elseif not pos_check_range(desync, plan[i].range) then
DLOG("orchestrator: not calling '"..desync.func_instance.."' because pos "..pos_str(desync,plan[i].range.from).." "..pos_str(desync,plan[i].range.to).." is out of range '"..pos_range_str(plan[i].range).."'")
else
apply_execution_plan(desync, plan[i])
DLOG("orchestrator: executing '"..desync.func_instance.."'")
_G[plan[i].func](ctx, desync)
end
end
end
-- this function demonstrates how to stop execution of upcoming desync instances and take over their job
-- this can be used, for example, for orchestrating conditional processing without modifying of desync functions code
-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-desync=desync_orchestrator_example --lua-desync=pass --lua-desync=pass
function desync_orchestrator_example(ctx, desync)
local plan = execution_plan(ctx)
if #plan>0 then
DLOG("orchestrator: taking over upcoming desync instances")
local desync_copy = deepcopy(desync)
execution_plan_cancel(ctx)
replay_execution_plan(desync_copy, plan)
end
end
-- these function duplicate range check logic from C code
-- mode must be n,d,b,s,x,a
-- pos is {mode,pos}
-- range is {from={mode,pos}, to={mode,pos}, upper_cutoff}
-- upper_cutoff = true means non-inclusive upper boundary
function pos_get(desync, mode)
if desync.track then
if mode=='n' then
return desync.outgoing and desync.track.pcounter_orig or desync.track.pcounter_reply
elseif mode=='d' then
return desync.outgoing and desync.track.pdcounter_orig or desync.track.pdcounter_reply
elseif mode=='b' then
return desync.outgoing and desync.track.pbcounter_orig or desync.track.pbcounter_reply
elseif mode=='s' and desync.track.tcp then
return desync.outgoing and (desync.track.tcp.seq - desync.track.tcp.seq0) or (desync.track.tcp.ack - desync.track.tcp.ack0)
end
end
return 0
end
function pos_check_from(desync, range)
if range.from.mode == 'x' then return false end
if range.from.mode ~= 'a' then
if desync.track then
return pos_get(desync, range.from.mode) >= range.from.pos
else
return false
end
end
return true;
end
function pos_check_to(desync, range)
local ps
if range.to.mode == 'x' then return false end
if range.to.mode ~= 'a' then
if desync.track then
ps = pos_get(desync, range.to.mode)
return (ps < range.to.pos) or not range.upper_cutoff and (ps == range.to.pos)
else
return false
end
end
return true;
end
function pos_check_range(desync, range)
return pos_check_from(desync,range) and pos_check_to(desync,range)
end
function pos_range_str(range)
return range.from.mode..range.from.pos..(range.upper_cutoff and '<' or '-')..range.to.mode..range.to.pos
end
function pos_str(desync, pos)
return pos.mode..pos_get(desync, pos.mode)
end
-- prepare standard rawsend options from desync
@@ -802,17 +930,21 @@ function direction_cutoff_opposite(ctx, desync, def)
instance_cutoff(ctx, true)
end
end
-- return true if l7payload matches filter l7payload_filter - comma separated list of payload types
function payload_match_filter(l7payload, l7payload_filter, def)
local argpl = l7payload_filter or def or "known"
local neg = string.sub(argpl,1,1)=="~"
local pl = neg and string.sub(argpl,2) or argpl
return neg ~= (in_list(pl, "all") or in_list(pl, l7payload) or in_list(pl, "known") and l7payload~="unknown" and l7payload~="empty")
end
-- check if desync payload type comply with payload type list in arg.payload
-- if arg.payload is not present - check for known payload - not empty and not unknown (nfqws1 behavior without "--desync-any-protocol" option)
-- if arg.payload is prefixed with '~' - it means negation
function payload_check(desync, def)
local b
local argpl = desync.arg.payload or def or "known"
local neg = string.sub(argpl,1,1)=="~"
local pl = neg and string.sub(argpl,2) or argpl
b = neg ~= (in_list(pl, "all") or in_list(pl, desync.l7payload) or in_list(pl, "known") and desync.l7payload~="unknown" and desync.l7payload~="empty")
if not b then
local b = payload_match_filter(desync.l7payload, desync.arg.payload, def)
if not b and b_debug then
local argpl = desync.arg.payload or def or "known"
DLOG("payload_check: payload '"..desync.l7payload.."' does not pass '"..argpl.."' filter")
end
return b
@@ -1031,4 +1163,3 @@ function ipfrag2(dis, ipfrag_options)
return {dis1,dis2}
end

View File

@@ -102,8 +102,8 @@ static void ConntrackInitTrack(t_ctrack *t)
{
memset(t, 0, sizeof(*t));
t->l7proto = L7_UNKNOWN;
t->scale_orig = t->scale_reply = SCALE_NONE;
time(&t->t_start);
t->pos.scale_orig = t->pos.scale_reply = SCALE_NONE;
time(&t->pos.t_start);
rawpacket_queue_init(&t->delayed);
lua_newtable(params.L);
t->lua_state = luaL_ref(params.L, LUA_REGISTRYINDEX);
@@ -136,86 +136,86 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (bReverse)
{
t->pcounter_reply++;
t->pdcounter_reply += !!len_payload;
t->pbcounter_reply += len_payload;
t->pos.pcounter_reply++;
t->pos.pdcounter_reply += !!len_payload;
t->pos.pbcounter_reply += len_payload;
}
else
{
t->pcounter_orig++;
t->pdcounter_orig += !!len_payload;
t->pbcounter_orig += len_payload;
t->pos.pcounter_orig++;
t->pos.pdcounter_orig += !!len_payload;
t->pos.pbcounter_orig += len_payload;
}
if (tcphdr)
{
if (tcp_syn_segment(tcphdr))
{
if (t->state != SYN) ConntrackReInitTrack(t); // erase current entry
t->seq0 = ntohl(tcphdr->th_seq);
if (t->pos.state != SYN) ConntrackReInitTrack(t); // erase current entry
t->pos.seq0 = ntohl(tcphdr->th_seq);
}
else if (tcp_synack_segment(tcphdr))
{
// ignore SA dups
uint32_t seq0 = ntohl(tcphdr->th_ack) - 1;
if (t->state != SYN && t->seq0 != seq0)
if (t->pos.state != SYN && t->pos.seq0 != seq0)
ConntrackReInitTrack(t); // erase current entry
if (!t->seq0) t->seq0 = seq0;
t->ack0 = ntohl(tcphdr->th_seq);
if (!t->pos.seq0) t->pos.seq0 = seq0;
t->pos.ack0 = ntohl(tcphdr->th_seq);
}
else if (tcphdr->th_flags & (TH_FIN | TH_RST))
{
t->state = FIN;
t->pos.state = FIN;
}
else
{
if (t->state == SYN)
if (t->pos.state == SYN)
{
t->state = ESTABLISHED;
if (!bReverse && !t->ack0) t->ack0 = ntohl(tcphdr->th_ack) - 1;
t->pos.state = ESTABLISHED;
if (!bReverse && !t->pos.ack0) t->pos.ack0 = ntohl(tcphdr->th_ack) - 1;
}
}
scale = tcp_find_scale_factor(tcphdr);
mss = ntohs(tcp_find_mss(tcphdr));
if (bReverse)
{
t->pos_orig = t->seq_last = ntohl(tcphdr->th_ack);
t->ack_last = ntohl(tcphdr->th_seq);
t->pos_reply = t->ack_last + len_payload;
t->winsize_reply = ntohs(tcphdr->th_win);
t->winsize_reply_calc = t->winsize_reply;
if (t->scale_reply != SCALE_NONE) t->winsize_reply_calc <<= t->scale_reply;
if (mss && !t->mss_reply) t->mss_reply = mss;
if (scale != SCALE_NONE) t->scale_reply = scale;
t->pos.pos_orig = t->pos.seq_last = ntohl(tcphdr->th_ack);
t->pos.ack_last = ntohl(tcphdr->th_seq);
t->pos.pos_reply = t->pos.ack_last + len_payload;
t->pos.winsize_reply = ntohs(tcphdr->th_win);
t->pos.winsize_reply_calc = t->pos.winsize_reply;
if (t->pos.scale_reply != SCALE_NONE) t->pos.winsize_reply_calc <<= t->pos.scale_reply;
if (mss && !t->pos.mss_reply) t->pos.mss_reply = mss;
if (scale != SCALE_NONE) t->pos.scale_reply = scale;
}
else
{
t->seq_last = ntohl(tcphdr->th_seq);
t->pos_orig = t->seq_last + len_payload;
t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack);
t->winsize_orig = ntohs(tcphdr->th_win);
t->winsize_orig_calc = t->winsize_orig;
if (t->scale_orig != SCALE_NONE) t->winsize_orig_calc <<= t->scale_orig;
if (mss && !t->mss_reply) t->mss_orig = mss;
if (scale != SCALE_NONE) t->scale_orig = scale;
t->pos.seq_last = ntohl(tcphdr->th_seq);
t->pos.pos_orig = t->pos.seq_last + len_payload;
t->pos.pos_reply = t->pos.ack_last = ntohl(tcphdr->th_ack);
t->pos.winsize_orig = ntohs(tcphdr->th_win);
t->pos.winsize_orig_calc = t->pos.winsize_orig;
if (t->pos.scale_orig != SCALE_NONE) t->pos.winsize_orig_calc <<= t->pos.scale_orig;
if (mss && !t->pos.mss_reply) t->pos.mss_orig = mss;
if (scale != SCALE_NONE) t->pos.scale_orig = scale;
}
}
else
{
if (bReverse)
{
t->ack_last = t->pos_reply;
t->pos_reply += len_payload;
t->pos.ack_last = t->pos.pos_reply;
t->pos.pos_reply += len_payload;
}
else
{
t->seq_last = t->pos_orig;
t->pos_orig += len_payload;
t->pos.seq_last = t->pos.pos_orig;
t->pos.pos_orig += len_payload;
}
}
time(&t->t_last);
time(&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)
@@ -317,12 +317,12 @@ void ConntrackPoolPurge(t_conntrack *p)
if ((tnow - p->t_last_purge) >= p->t_purge_interval)
{
HASH_ITER(hh, p->pool, t, tmp) {
tidle = tnow - t->track.t_last;
tidle = tnow - t->track.pos.t_last;
if (t->track.b_cutoff ||
(t->conn.l4proto == IPPROTO_TCP && (
(t->track.state == SYN && tidle >= p->timeout_syn) ||
(t->track.state == ESTABLISHED && tidle >= p->timeout_established) ||
(t->track.state == FIN && tidle >= p->timeout_fin))
(t->track.pos.state == SYN && tidle >= p->timeout_syn) ||
(t->track.pos.state == ESTABLISHED && tidle >= p->timeout_established) ||
(t->track.pos.state == FIN && tidle >= p->timeout_fin))
) || (t->conn.l4proto == IPPROTO_UDP && tidle >= p->timeout_udp)
)
{
@@ -349,21 +349,21 @@ void ConntrackPoolDump(const t_conntrack *p)
printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu orig=d%llu/n%llu/b%llu reply=d%llu/n%llu/b%lld ",
proto_name(t->conn.l4proto),
sa1, t->conn.sport, sa2, t->conn.dport,
t->conn.l4proto == IPPROTO_TCP ? connstate_s[t->track.state] : "-",
(unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last),
(unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig, (unsigned long long)t->track.pbcounter_orig,
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply, (unsigned long long)t->track.pbcounter_reply);
t->conn.l4proto == IPPROTO_TCP ? connstate_s[t->track.pos.state] : "-",
(unsigned long long)t->track.pos.t_start, (unsigned long long)(t->track.pos.t_last - t->track.pos.t_start), (unsigned long long)(tnow - t->track.pos.t_last),
(unsigned long long)t->track.pos.pdcounter_orig, (unsigned long long)t->track.pos.pcounter_orig, (unsigned long long)t->track.pos.pbcounter_orig,
(unsigned long long)t->track.pos.pdcounter_reply, (unsigned long long)t->track.pos.pcounter_reply, (unsigned long long)t->track.pos.pbcounter_reply);
if (t->conn.l4proto == IPPROTO_TCP)
printf("seq0=%u rseq=%u pos_orig=%u ack0=%u rack=%u pos_reply=%u mss_orig=%u mss_reply=%u wsize_orig=%u:%d wsize_reply=%u:%d",
t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0,
t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0,
t->track.mss_orig, t->track.mss_reply,
t->track.winsize_orig, t->track.scale_orig == SCALE_NONE ? -1 : t->track.scale_orig,
t->track.winsize_reply, t->track.scale_reply == SCALE_NONE ? -1 : t->track.scale_reply);
t->track.pos.seq0, t->track.pos.seq_last - t->track.pos.seq0, t->track.pos.pos_orig - t->track.pos.seq0,
t->track.pos.ack0, t->track.pos.ack_last - t->track.pos.ack0, t->track.pos.pos_reply - t->track.pos.ack0,
t->track.pos.mss_orig, t->track.pos.mss_reply,
t->track.pos.winsize_orig, t->track.pos.scale_orig == SCALE_NONE ? -1 : t->track.pos.scale_orig,
t->track.pos.winsize_reply, t->track.pos.scale_reply == SCALE_NONE ? -1 : t->track.pos.scale_reply);
else
printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u",
t->track.seq_last, t->track.pos_orig,
t->track.ack_last, t->track.pos_reply);
t->track.pos.seq_last, t->track.pos.pos_orig,
t->track.pos.ack_last, t->track.pos.pos_reply);
printf(" req_retrans=%u cutoff=%u lua_in_cutoff=%u lua_out_cutoff=%u hostname=%s l7proto=%s\n",
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_lua_in_cutoff, t->track.b_lua_out_cutoff, t->track.hostname, l7proto_str(t->track.l7proto));
};

View File

@@ -8,7 +8,6 @@
#include <stdint.h>
#include <ctype.h>
#include <sys/types.h>
#include <time.h>
#include <netinet/in.h>
#define __FAVOR_BSD
@@ -17,6 +16,7 @@
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include "conntrack_base.h"
#include "packet_queue.h"
#include "protocol.h"
@@ -48,35 +48,18 @@ typedef struct {
size_t size_present; // how many bytes already stored in 'packet'
} t_reassemble;
// SYN - SYN or SYN/ACK received
// ESTABLISHED - any except SYN or SYN/ACK received
// FIN - FIN or RST received
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
typedef struct
{
bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache
uint8_t ipproto;
// this block of data can change between delayed (queued) packets. need to remeber this data for each packet for further replay
t_ctrack_position pos;
struct desync_profile *dp; // desync profile cache
bool dp_search_complete;
// common state
time_t t_start, t_last;
uint64_t pcounter_orig, pcounter_reply; // packet counter
uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload)
uint64_t pbcounter_orig, pbcounter_reply; // transferred byte counter. includes retransmissions. it's not the same as relative seq.
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
// tcp only state, not used in udp
t_connstate state;
uint32_t seq0, ack0; // starting seq and ack
uint16_t winsize_orig, winsize_reply; // last seen window size
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
uint32_t winsize_orig_calc, winsize_reply_calc; // calculated window size
uint16_t mss_orig, mss_reply;
uint8_t req_retrans_counter; // number of request retransmissions
bool req_seq_present,req_seq_finalized,req_seq_abandoned;
uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions)

32
nfq2/conntrack_base.h Normal file
View File

@@ -0,0 +1,32 @@
#pragma once
#include <time.h>
#define CTRACK_T_SYN 60
#define CTRACK_T_FIN 60
#define CTRACK_T_EST 300
#define CTRACK_T_UDP 60
// SYN - SYN or SYN/ACK received
// ESTABLISHED - any except SYN or SYN/ACK received
// FIN - FIN or RST received
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
typedef struct
{
time_t t_last, t_start;
uint64_t pcounter_orig, pcounter_reply; // packet counter
uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload)
uint64_t pbcounter_orig, pbcounter_reply; // transferred byte counter. includes retransmissions. it's not the same as relative seq.
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
// tcp only state, not used in udp
t_connstate state;
uint32_t seq0, ack0; // starting seq and ack
uint16_t winsize_orig, winsize_reply; // last seen window size
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
uint32_t winsize_orig_calc, winsize_reply_calc; // calculated window size
uint16_t mss_orig, mss_reply;
} t_ctrack_position;

View File

@@ -209,7 +209,7 @@ static struct desync_profile *dp_find(
{
if (dp_match(&dpl->dp, l3proto, ip, ip6, port, hostname, bNoSubdom, l7proto, ssid, bCheckDone, bCheckResult, bExcluded))
{
DLOG("desync profile %u matches\n", dpl->dp.n);
DLOG("desync profile %u (%s) matches\n", dpl->dp.n, PROFILE_NAME(&dpl->dp));
return &dpl->dp;
}
}
@@ -234,8 +234,8 @@ static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const ch
if (fail_counter)
{
HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter);
DLOG("auto hostlist (profile %u) : %s : fail counter reset. website is working.\n", dp->n, hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : fail counter reset. website is working.", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
DLOG("auto hostlist (profile %u (%s)) : %s : fail counter reset. website is working.\n", dp->n, PROFILE_NAME(dp), hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : fail counter reset. website is working.", hostname, dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto));
}
}
}
@@ -249,9 +249,9 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho
{
if (!ctrack->req_seq_finalized || ctrack->req_seq_abandoned)
return false;
if (!seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end))
if (!seq_within(ctrack->pos.seq_last, ctrack->req_seq_start, ctrack->req_seq_end))
{
DLOG("req retrans : tcp seq %u not within the req range %u-%u. stop tracking.\n", ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end);
DLOG("req retrans : tcp seq %u not within the req range %u-%u. stop tracking.\n", ctrack->pos.seq_last, ctrack->req_seq_start, ctrack->req_seq_end);
ctrack_stop_retrans_counter(ctrack);
auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, l7proto);
return false;
@@ -283,19 +283,19 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
}
}
fail_counter->counter++;
DLOG("auto hostlist (profile %u) : %s : fail counter %d/%d\n", dp->n, hostname, fail_counter->counter, dp->hostlist_auto_fail_threshold);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : fail counter %d/%d", hostname, dp->n, client_ip_port, l7proto_str(l7proto), fail_counter->counter, dp->hostlist_auto_fail_threshold);
DLOG("auto hostlist (profile %u (%s)) : %s : fail counter %d/%d\n", dp->n, PROFILE_NAME(dp), hostname, fail_counter->counter, dp->hostlist_auto_fail_threshold);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : fail counter %d/%d", hostname, dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto), fail_counter->counter, dp->hostlist_auto_fail_threshold);
if (fail_counter->counter >= dp->hostlist_auto_fail_threshold)
{
DLOG("auto hostlist (profile %u) : fail threshold reached. about to add %s to auto hostlist\n", dp->n, hostname);
DLOG("auto hostlist (profile %u (%s)) : fail threshold reached. about to add %s to auto hostlist\n", dp->n, PROFILE_NAME(dp), hostname);
HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter);
DLOG("auto hostlist (profile %u) : rechecking %s to avoid duplicates\n", dp->n, hostname);
DLOG("auto hostlist (profile %u (%s)) : rechecking %s to avoid duplicates\n", dp->n, PROFILE_NAME(dp), hostname);
bool bExcluded = false;
if (!HostlistCheck(dp, hostname, bNoSubdom, &bExcluded, false) && !bExcluded)
{
DLOG("auto hostlist (profile %u) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : adding to %s", hostname, dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
if (!HostlistPoolAddStr(&dp->hostlist_auto->hostlist, hostname, 0))
{
DLOG_ERR("StrPoolAddStr out of memory\n");
@@ -312,7 +312,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
else
{
DLOG("auto hostlist (profile %u) : NOT adding %s\n", dp->n, hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : NOT adding, duplicate detected", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : NOT adding, duplicate detected", hostname, dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto));
}
}
}
@@ -328,7 +328,7 @@ static void process_retrans_fail(t_ctrack *ctrack, uint8_t proto, const struct s
*client_ip_port = 0;
if (ctrack && ctrack->dp && ctrack->hostname && auto_hostlist_retrans(ctrack, proto, ctrack->dp->hostlist_auto_retrans_threshold, client_ip_port, ctrack->l7proto))
{
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : retrans threshold reached", ctrack->hostname, ctrack->dp->n, 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);
}
}
@@ -344,14 +344,14 @@ static bool send_delayed(t_ctrack *ctrack)
return true;
}
static bool rawpacket_queue_csum_fix(struct rawpacket_tailhead *q, const struct dissect *dis, const struct sockaddr_storage* dst, uint32_t fwmark, uint32_t desync_fwmark, const char *ifin, const char *ifout)
static bool rawpacket_queue_csum_fix(struct rawpacket_tailhead *q, const struct dissect *dis, const t_ctrack_position *pos, const struct sockaddr_storage* dst, uint32_t fwmark, uint32_t desync_fwmark, const char *ifin, const char *ifout)
{
// this breaks const pointer to l4 header
if (dis->tcp)
verdict_tcp_csum_fix(VERDICT_PASS, (struct tcphdr *)dis->tcp, dis->transport_len, dis->ip, dis->ip6);
else if (dis->udp)
verdict_udp_csum_fix(VERDICT_PASS, (struct udphdr *)dis->udp, dis->transport_len, dis->ip, dis->ip6);
return rawpacket_queue(q, dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload);
return rawpacket_queue(q, dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, pos);
}
@@ -360,7 +360,7 @@ static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, si
ReasmClear(reasm);
if (sz <= szMax)
{
uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->seq_last : 0;
uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->pos.seq_last : 0;
if (ReasmInit(reasm, sz, seq))
{
ReasmFeed(reasm, seq, data_payload, len_payload);
@@ -382,7 +382,7 @@ static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, con
{
if (ctrack && !ReasmIsEmpty(reasm))
{
uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->seq_last : (uint32_t)reasm->size_present;
uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->pos.seq_last : (uint32_t)reasm->size_present;
if (ReasmFeed(reasm, seq, data_payload, len_payload))
{
DLOG("reassemble : feeding data payload size=%zu. now we have %zu/%zu\n", len_payload, reasm->size_present, reasm->size);
@@ -429,7 +429,7 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, const struct dissect *
// if used in postnat chain, dropping initial packet will cause conntrack connection teardown
// so we need to workaround this.
// SYN and SYN,ACK checks are for conntrack-less mode
if (ctrack && (params.server ? ctrack->pcounter_reply : ctrack->pcounter_orig) == 1 || dis->tcp && (tcp_syn_segment(dis->tcp) || tcp_synack_segment(dis->tcp)))
if (ctrack && (params.server ? ctrack->pos.pcounter_reply : ctrack->pos.pcounter_orig) == 1 || dis->tcp && (tcp_syn_segment(dis->tcp) || tcp_synack_segment(dis->tcp)))
{
if (dis->len_pkt > *len_mod_pkt)
DLOG_ERR("linux postnat conntrack workaround cannot be applied\n");
@@ -458,60 +458,60 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, const struct dissect *
}
static uint64_t pos_get(const t_ctrack *ctrack, char mode, bool bReply)
static uint64_t pos_get(const t_ctrack_position *pos, char mode, bool bReply)
{
if (ctrack)
if (pos)
{
switch (mode)
{
case 'n': return bReply ? ctrack->pcounter_reply : ctrack->pcounter_orig;
case 'd': return bReply ? ctrack->pdcounter_reply : ctrack->pdcounter_orig;
case 's': return bReply ? (ctrack->ack_last - ctrack->ack0) : (ctrack->seq_last - ctrack->seq0);
case 'b': return bReply ? ctrack->pbcounter_reply : ctrack->pbcounter_orig;
case 'n': return bReply ? pos->pcounter_reply : pos->pcounter_orig;
case 'd': return bReply ? pos->pdcounter_reply : pos->pdcounter_orig;
case 's': return bReply ? (pos->ack_last - pos->ack0) : (pos->seq_last - pos->seq0);
case 'b': return bReply ? pos->pbcounter_reply : pos->pbcounter_orig;
}
}
return 0;
}
static bool check_pos_from(const t_ctrack *ctrack, bool bReply, const struct packet_range *range)
static bool check_pos_from(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
{
uint64_t pos;
uint64_t ps;
if (range->from.mode == 'x') return false;
if (range->from.mode != 'a')
{
if (ctrack)
if (pos)
{
pos = pos_get(ctrack, range->from.mode, bReply);
return pos >= range->from.pos;
ps = pos_get(pos, range->from.mode, bReply);
return ps >= range->from.pos;
}
else
return false;
}
return true;
}
static bool check_pos_to(const t_ctrack *ctrack, bool bReply, const struct packet_range *range)
static bool check_pos_to(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
{
uint64_t pos;
uint64_t ps;
if (range->to.mode == 'x') return false;
if (range->to.mode != 'a')
{
if (ctrack)
if (pos)
{
pos = pos_get(ctrack, range->to.mode, bReply);
return (pos < range->to.pos) || !range->upper_cutoff && (pos == range->to.pos);
ps = pos_get(pos, range->to.mode, bReply);
return (ps < range->to.pos) || !range->upper_cutoff && (ps == range->to.pos);
}
else
return false;
}
return true;
}
static bool check_pos_cutoff(const t_ctrack *ctrack, bool bReply, const struct packet_range *range)
static bool check_pos_cutoff(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
{
bool bto = check_pos_to(ctrack, bReply, range);
return ctrack ? !bto : (!bto || !check_pos_from(ctrack, bReply, range));
bool bto = check_pos_to(pos, bReply, range);
return pos ? !bto : (!bto || !check_pos_from(pos, bReply, range));
}
static bool check_pos_range(const t_ctrack *ctrack, bool bReply, const struct packet_range *range)
static bool check_pos_range(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
{
return check_pos_from(ctrack, bReply, range) && check_pos_to(ctrack, bReply, range);
return check_pos_from(pos, bReply, range) && check_pos_to(pos, bReply, range);
}
@@ -638,10 +638,6 @@ err:
lua_pop(params.L, rescount);
return false;
}
static void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size)
{
snprintf(instance, inst_size, "%s_%u_%u", func, dp_n, func_n);
}
static uint8_t desync(
struct desync_profile *dp,
uint32_t fwmark,
@@ -649,6 +645,7 @@ static uint8_t desync(
const char *ifout,
bool bIncoming,
t_ctrack *ctrack,
const t_ctrack_position *pos,
t_l7payload l7payload,
const struct dissect *dis,
uint8_t *mod_pkt, size_t *len_mod_pkt,
@@ -659,7 +656,7 @@ static uint8_t desync(
struct func_list *func;
int ref_arg = LUA_NOREF, status;
bool b, b_cutoff_all, b_unwanted_payload;
t_lua_desync_context ctx = { .dp = dp, .ctrack = ctrack, .dis = dis };
t_lua_desync_context ctx = { .dp = dp, .ctrack = ctrack, .dis = dis, .cancel = false, .incoming = bIncoming };
const char *sDirection = bIncoming ? "in" : "out";
struct packet_range *range;
size_t l;
@@ -678,17 +675,16 @@ static uint8_t desync(
DLOG("lua out cutoff\n");
return verdict;
}
if (!pos) pos = &ctrack->pos;
}
if (LIST_FIRST(&dp->lua_desync))
{
unsigned int func_n;
b_cutoff_all = b_unwanted_payload = true;
func_n = 1;
ctx.func_n = 1;
LIST_FOREACH(func, &dp->lua_desync, next)
{
ctx.func = func->func;
desync_instance(func->func, dp->n, func_n, instance, sizeof(instance));
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance));
ctx.instance = instance;
range = bIncoming ? &func->range_in : &func->range_out;
@@ -699,12 +695,12 @@ static uint8_t desync(
{
if (lua_instance_cutoff_check(&ctx, bIncoming))
DLOG("* lua '%s' : voluntary cutoff\n", instance);
else if (check_pos_cutoff(ctrack, bIncoming, range))
else if (check_pos_cutoff(pos, bIncoming, range))
{
DLOG("* lua '%s' : %s pos %c%llu %c%llu is beyond range %c%u%c%c%u (ctrack %s)\n",
instance, sDirection,
range->from.mode, pos_get(ctrack, range->from.mode, bIncoming),
range->to.mode, pos_get(ctrack, range->to.mode, bIncoming),
range->from.mode, pos_get(pos, range->from.mode, bIncoming),
range->to.mode, pos_get(pos, range->to.mode, bIncoming),
range->from.mode, range->from.pos,
range->upper_cutoff ? '<' : '-',
range->to.mode, range->to.pos,
@@ -713,7 +709,7 @@ static uint8_t desync(
else
b_cutoff_all = false;
}
func_n++;
ctx.func_n++;
}
if (b_cutoff_all)
{
@@ -725,10 +721,14 @@ static uint8_t desync(
else
{
// create arg table that persists across multiple desync function calls
lua_createtable(params.L, 0, 12 + !!ctrack + !!dis->tcp + 3*!!replay_piece_count);
lua_newtable(params.L);
lua_pushf_dissect(dis);
lua_pushf_ctrack(ctrack);
lua_pushf_ctrack(ctrack, pos);
lua_pushf_int("profile_n", dp->n);
if (dp->name) lua_pushf_str("profile_name", dp->name);
if (dp->n_tpl) lua_pushf_int("template_n", dp->n_tpl);
if (dp->name_tpl) lua_pushf_str("template_name", dp->name_tpl);
if (dp->cookie) lua_pushf_str("cookie", dp->cookie);
lua_pushf_bool("outgoing", !bIncoming);
lua_pushf_str("ifin", (ifin && *ifin) ? ifin : NULL);
lua_pushf_str("ifout", (ifout && *ifout) ? ifout : NULL);
@@ -748,29 +748,29 @@ static uint8_t desync(
if (dis->tcp)
{
// recommended mss value for generated packets
if (ctrack && ctrack->mss_orig)
lua_pushf_int("tcp_mss", ctrack->mss_orig);
if (pos && pos->mss_orig)
lua_pushf_int("tcp_mss", pos->mss_orig);
else
lua_pushf_global("tcp_mss", "DEFAULT_MSS");
}
ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX);
func_n = 1;
ctx.func_n = 1;
LIST_FOREACH(func, &dp->lua_desync, next)
{
ctx.func = func->func;
desync_instance(func->func, dp->n, func_n, instance, sizeof(instance));
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance));
ctx.instance = instance;
if (!lua_instance_cutoff_check(&ctx, bIncoming))
{
range = bIncoming ? &func->range_in : &func->range_out;
if (check_pos_range(ctrack, bIncoming, range))
if (check_pos_range(pos, bIncoming, range))
{
DLOG("* lua '%s' : %s pos %c%llu %c%llu in range %c%u%c%c%u\n",
instance, sDirection,
range->from.mode, pos_get(ctrack, range->from.mode, bIncoming),
range->to.mode, pos_get(ctrack, range->to.mode, bIncoming),
range->from.mode, pos_get(pos, range->from.mode, bIncoming),
range->to.mode, pos_get(pos, range->to.mode, bIncoming),
range->from.mode, range->from.pos,
range->upper_cutoff ? '<' : '-',
range->to.mode, range->to.pos);
@@ -789,7 +789,7 @@ static uint8_t desync(
lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg);
lua_pushf_args(&func->args, -1);
lua_pushf_str("func", func->func);
lua_pushf_int("func_n", func_n);
lua_pushf_int("func_n", ctx.func_n);
lua_pushf_str("func_instance", instance);
int initial_stack_top = lua_gettop(params.L);
status = lua_pcall(params.L, 2, LUA_MULTRET, 0);
@@ -808,37 +808,6 @@ static uint8_t desync(
case VERDICT_DROP:
verdict = VERDICT_DROP;
}
if (ctrack)
{
// lua cutoff
lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg);
lua_getfield(params.L, -1, "track");
if (lua_istable(params.L, -1))
{
if (!ctrack->b_lua_in_cutoff)
{
lua_getfield(params.L, -1, "lua_in_cutoff");
if (lua_toboolean(params.L, -1))
{
ctrack->b_lua_in_cutoff = true;
DLOG("* lua in cutoff set\n");
}
lua_pop(params.L, 1);
}
if (!ctrack->b_lua_out_cutoff)
{
lua_getfield(params.L, -1, "lua_out_cutoff");
if (lua_toboolean(params.L, -1))
{
ctrack->b_lua_out_cutoff = true;
DLOG("* lua out cutoff set\n");
}
lua_pop(params.L, 1);
}
}
lua_pop(params.L, 2);
}
}
else
DLOG("* lua '%s' : payload_type '%s' does not satisfy filter\n", instance, l7payload_str(l7payload));
@@ -846,13 +815,14 @@ static uint8_t desync(
else
DLOG("* lua '%s' : %s pos %c%llu %c%llu out of range %c%u%c%c%u\n",
instance, sDirection,
range->from.mode, pos_get(ctrack, range->from.mode, bIncoming),
range->to.mode, pos_get(ctrack, range->to.mode, bIncoming),
range->from.mode, pos_get(pos, range->from.mode, bIncoming),
range->to.mode, pos_get(pos, range->to.mode, bIncoming),
range->from.mode, range->from.pos,
range->upper_cutoff ? '<' : '-',
range->to.mode, range->to.pos);
}
func_n++;
if (ctx.cancel) break;
ctx.func_n++;
}
}
@@ -940,7 +910,13 @@ static void setup_direction(
}
}
static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, const struct dissect *dis, uint8_t *mod_pkt, size_t *len_mod_pkt)
static uint8_t dpi_desync_tcp_packet_play(
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset,
uint32_t fwmark,
const char *ifin, const char *ifout,
const t_ctrack_position *pos,
const struct dissect *dis,
uint8_t *mod_pkt, size_t *len_mod_pkt)
{
uint8_t verdict = VERDICT_PASS;
@@ -979,7 +955,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
l7proto = ctrack_replay->l7proto;
dp = ctrack_replay->dp;
if (dp)
DLOG("using cached desync profile %u\n", dp->n);
DLOG("using cached desync profile %u (%s)\n", dp->n, PROFILE_NAME(dp));
else if (!ctrack_replay->dp_search_complete)
{
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_TCP, sdip4, sdip6, sdport, ctrack_replay->hostname, ctrack_replay->hostname_is_ip, l7proto, ssid, NULL, NULL, NULL);
@@ -1007,7 +983,6 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
// in absence of conntrack guess direction by presence of interface names. won't work on BSD
bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && ifin && (!ifout || !*ifout));
setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport);
ifname = bReverse ? ifin : ifout;
#ifdef HAS_FILTER_SSID
ssid = wlan_ssid_search_ifname(ifname);
@@ -1015,7 +990,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
#endif
if (ctrack) l7proto = ctrack->l7proto;
if (dp)
DLOG("using cached desync profile %u\n", dp->n);
DLOG("using cached desync profile %u (%s)\n", dp->n, PROFILE_NAME(dp));
else if (!ctrack || !ctrack->dp_search_complete)
{
const char *hostname = NULL;
@@ -1027,7 +1002,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
if (!hostname && !bReverse)
{
if (ipcache_get_hostname(sdip4, sdip6, host, sizeof(host), &hostname_is_ip) && *host)
if (!(hostname = ctrack_replay->hostname = strdup(host)))
if (!(hostname = ctrack->hostname = strdup(host)))
DLOG_ERR("strdup(host): out of memory\n");
}
}
@@ -1096,7 +1071,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
// process reply packets for auto hostlist mode
// by looking at RSTs or HTTP replies we decide whether original request looks like DPI blocked
// we only process first-sequence replies. do not react to subsequent redirects or RSTs
if (!params.server && ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->ack_last - ctrack->ack0) == 1)
if (!params.server && ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->pos.ack_last - ctrack->pos.ack0) == 1)
{
bool bFail = false;
@@ -1109,7 +1084,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
if (dis->tcp->th_flags & TH_RST)
{
DLOG("incoming RST detected for hostname %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : incoming RST", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(l7proto));
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : incoming RST", ctrack->hostname, ctrack->dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto));
bFail = true;
}
else if (dis->len_payload && l7proto == L7_HTTP)
@@ -1121,7 +1096,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
if (bFail)
{
DLOG("redirect to another domain detected. possibly DPI redirect.\n");
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : redirect to another domain", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(l7proto));
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : redirect to another domain", ctrack->hostname, ctrack->dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto));
}
else
DLOG("local or in-domain redirect detected. it's not a DPI redirect.\n");
@@ -1186,8 +1161,8 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
// we do not reassemble http
if (!ctrack->req_seq_present)
{
ctrack->req_seq_start = ctrack->seq_last;
ctrack->req_seq_end = ctrack->pos_orig - 1;
ctrack->req_seq_start = ctrack->pos.seq_last;
ctrack->req_seq_end = ctrack->pos.pos_orig - 1;
ctrack->req_seq_present = ctrack->req_seq_finalized = true;
DLOG("req retrans : tcp seq interval %u-%u\n", ctrack->req_seq_start, ctrack->req_seq_end);
}
@@ -1211,7 +1186,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
{
// do not reasm retransmissions
if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_orig) && !ctrack->req_seq_abandoned &&
!(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
!(ctrack->req_seq_finalized && seq_within(ctrack->pos.seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
{
// do not reconstruct unexpected large payload (they are feeding garbage ?)
if (!reasm_orig_start(ctrack, IPPROTO_TCP, TLSRecordLen(dis->data_payload), TCP_MAX_REASM, dis->data_payload, dis->len_payload))
@@ -1222,19 +1197,19 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
if (!ctrack->req_seq_present)
{
// lower bound of request seq interval
ctrack->req_seq_start = ctrack->seq_last;
ctrack->req_seq_start = ctrack->pos.seq_last;
ctrack->req_seq_present = true;
}
// upper bound of request seq interval
// it can grow on every packet until request is complete. then interval is finalized and never touched again.
ctrack->req_seq_end = ctrack->pos_orig - 1;
ctrack->req_seq_end = ctrack->pos.pos_orig - 1;
DLOG("req retrans : seq interval %u-%u\n", ctrack->req_seq_start, ctrack->req_seq_end);
ctrack->req_seq_finalized |= bReqFull;
}
if (!ReasmIsEmpty(&ctrack->reasm_orig))
{
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &dst, fwmark, desync_fwmark, ifin, ifout))
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
}
@@ -1252,7 +1227,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
}
}
}
else if (ctrack && (ctrack->seq_last - ctrack->seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload))
else if (ctrack && (ctrack->pos.seq_last - ctrack->pos.seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload))
{
DLOG("packet contains telegram mtproto2 initial\n");
// mtproto detection requires aes. react only on the first tcp data packet. do not detect if ctrack unavailable.
@@ -1273,7 +1248,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
}
if (ctrack && ctrack->req_seq_finalized)
{
uint32_t dseq = ctrack->seq_last - ctrack->req_seq_end;
uint32_t dseq = ctrack->pos.seq_last - ctrack->req_seq_end;
// do not react to 32-bit overflowed sequence numbers. allow 16 Mb grace window then cutoff.
if (dseq >= 0x1000000 && !(dseq & 0x80000000)) ctrack->req_seq_abandoned = true;
}
@@ -1379,7 +1354,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2));
DLOG("dpi desync src=%s dst=%s track_direction=%s fixed_direction=%s connection_proto=%s payload_type=%s\n", s1, s2, bReverse ? "in" : "out", bReverseFixed ? "in" : "out", l7proto_str(l7proto), l7payload_str(l7payload));
}
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, l7payload, dis, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, rdata_payload, rlen_payload, NULL, 0);
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, dis, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, rdata_payload, rlen_payload, NULL, 0);
pass:
return (!bReverseFixed && (verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt) : verdict;
@@ -1396,7 +1371,13 @@ static void quic_reasm_cancel(t_ctrack *ctrack, const char *reason)
}
static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, const struct dissect *dis, uint8_t *mod_pkt, size_t *len_mod_pkt)
static uint8_t dpi_desync_udp_packet_play(
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset,
uint32_t fwmark,
const char *ifin, const char *ifout,
const t_ctrack_position *pos,
const struct dissect *dis,
uint8_t *mod_pkt, size_t *len_mod_pkt)
{
uint8_t verdict = VERDICT_PASS;
@@ -1452,7 +1433,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
l7proto = ctrack_replay->l7proto;
dp = ctrack_replay->dp;
if (dp)
DLOG("using cached desync profile %u\n", dp->n);
DLOG("using cached desync profile %u (%s)\n", dp->n, PROFILE_NAME(dp));
else if (!ctrack_replay->dp_search_complete)
{
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_UDP, sdip4, sdip6, sdport, ctrack_replay->hostname, ctrack_replay->hostname_is_ip, l7proto, ssid, NULL, NULL, NULL);
@@ -1488,7 +1469,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
#endif
if (ctrack) l7proto = ctrack->l7proto;
if (dp)
DLOG("using cached desync profile %u\n", dp->n);
DLOG("using cached desync profile %u (%s)\n", dp->n, PROFILE_NAME(dp));
else if (!ctrack || !ctrack->dp_search_complete)
{
const char *hostname = NULL;
@@ -1500,7 +1481,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
if (!hostname && !bReverse)
{
if (ipcache_get_hostname(sdip4, sdip6, host, sizeof(host), &hostname_is_ip) && *host)
if (!(hostname = ctrack_replay->hostname = strdup(host)))
if (!(hostname = ctrack->hostname = strdup(host)))
DLOG_ERR("strdup(host): out of memory\n");
}
}
@@ -1553,6 +1534,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
t_protocol_probe testers[] = {
{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},
@@ -1629,7 +1611,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
}
if (!ReasmIsEmpty(&ctrack->reasm_orig))
{
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &dst, fwmark, desync_fwmark, ifin, ifout))
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
}
@@ -1669,7 +1651,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
if (!reasm_orig_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
goto pass_reasm_cancel;
}
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &dst, fwmark, desync_fwmark, ifin, ifout))
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
}
@@ -1704,7 +1686,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
t_protocol_probe testers[] = {
{L7P_DISCORD_IP_DISCOVERY,L7_DISCORD,IsDiscordIpDiscoveryRequest,false},
{L7P_STUN_BINDING_REQ,L7_STUN,IsStunBindingRequest,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},
@@ -1828,7 +1810,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2));
DLOG("dpi desync src=%s dst=%s track_direction=%s fixed_direction=%s connection_proto=%s payload_type=%s\n", s1, s2, bReverse ? "in" : "out", bReverseFixed ? "in" : "out", l7proto_str(l7proto), l7payload_str(l7payload));
}
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, l7payload, dis, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, NULL, 0, data_decrypt, len_decrypt);
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, dis, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, NULL, 0, data_decrypt, len_decrypt);
pass:
return (!bReverse && (verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt) : verdict;
@@ -1877,6 +1859,7 @@ static void packet_debug(bool replay, const struct dissect *dis)
static uint8_t dpi_desync_packet_play(
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout,
const t_ctrack_position *pos,
const uint8_t *data_pkt, size_t len_pkt,
uint8_t *mod_pkt, size_t *len_mod_pkt)
{
@@ -1892,7 +1875,7 @@ static uint8_t dpi_desync_packet_play(
case IPPROTO_TCP:
if (dis.tcp)
{
verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt);
verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, pos, &dis, mod_pkt, len_mod_pkt);
// we fix csum before pushing to replay queue
if (!replay_piece_count) verdict_tcp_csum_fix(verdict, (struct tcphdr *)dis.tcp, dis.transport_len, dis.ip, dis.ip6);
}
@@ -1900,7 +1883,7 @@ static uint8_t dpi_desync_packet_play(
case IPPROTO_UDP:
if (dis.udp)
{
verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt);
verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, pos, &dis, mod_pkt, len_mod_pkt);
// we fix csum before pushing to replay queue
if (!replay_piece_count) verdict_udp_csum_fix(verdict, (struct udphdr *)dis.udp, dis.transport_len, dis.ip, dis.ip6);
}
@@ -1912,7 +1895,7 @@ static uint8_t dpi_desync_packet_play(
uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout, const uint8_t *data_pkt, size_t len_pkt, uint8_t *mod_pkt, size_t *len_mod_pkt)
{
ipcachePurgeRateLimited(&params.ipcache, params.ipcache_lifetime);
return dpi_desync_packet_play(0, 0, 0, fwmark, ifin, ifout, data_pkt, len_pkt, mod_pkt, len_mod_pkt);
return dpi_desync_packet_play(0, 0, 0, fwmark, ifin, ifout, NULL, data_pkt, len_pkt, mod_pkt, len_mod_pkt);
}
@@ -1930,7 +1913,7 @@ static bool replay_queue(struct rawpacket_tailhead *q)
{
DLOG("REPLAYING delayed packet #%u offset %zu\n", i+1, offset);
modlen = sizeof(mod);
uint8_t verdict = dpi_desync_packet_play(i, count, offset, rp->fwmark_orig, rp->ifin, rp->ifout, rp->packet, rp->len, mod, &modlen);
uint8_t verdict = dpi_desync_packet_play(i, count, offset, rp->fwmark_orig, rp->ifin, rp->ifout, rp->pos_present ? &rp->pos : NULL, rp->packet, rp->len, mod, &modlen);
switch (verdict & VERDICT_MASK)
{
case VERDICT_MODIFY:

View File

@@ -258,7 +258,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
// return : true = apply fooling, false = do not apply
bool HostlistCheck(const struct desync_profile *dp, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
{
DLOG("* hostlist check for profile %u\n",dp->n);
DLOG("* hostlist check for profile %u (%s)\n",dp->n,PROFILE_NAME(dp));
return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, no_match_subdomains, excluded, bSkipReloadCheck);
}
@@ -301,13 +301,34 @@ struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude,
filename);
}
static void HostlistsDebugProfile(const struct desync_profile *dp, const char *entity)
{
struct hostlist_item *hl_item;
LIST_FOREACH(hl_item, &dp->hl_collection, next)
if (hl_item->hfile!=dp->hostlist_auto)
{
if (hl_item->hfile->filename)
DLOG("%s %u (%s) include hostlist %s%s\n",entity, dp->n, PROFILE_NAME(dp), hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
else
DLOG("%s %u (%s) include fixed hostlist%s\n",entity, dp->n, PROFILE_NAME(dp), hl_item->hfile->hostlist ? "" : " (empty)");
}
LIST_FOREACH(hl_item, &dp->hl_collection_exclude, next)
{
if (hl_item->hfile->filename)
DLOG("%s %u (%s) exclude hostlist %s%s\n",entity, dp->n,PROFILE_NAME(dp),hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
else
DLOG("%s %u (%s) exclude fixed hostlist%s\n",entity, dp->n,PROFILE_NAME(dp),hl_item->hfile->hostlist ? "" : " (empty)");
}
if (dp->hostlist_auto)
DLOG("%s %u (%s) auto hostlist %s%s\n",entity, dp->n,PROFILE_NAME(dp),dp->hostlist_auto->filename,dp->hostlist_auto->hostlist ? "" : " (empty)");
}
void HostlistsDebug()
{
if (!params.debug) return;
struct hostlist_file *hfile;
struct desync_profile_list *dpl;
struct hostlist_item *hl_item;
LIST_FOREACH(hfile, &params.hostlists, next)
{
@@ -319,22 +340,10 @@ void HostlistsDebug()
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
LIST_FOREACH(hl_item, &dpl->dp.hl_collection, next)
if (hl_item->hfile!=dpl->dp.hostlist_auto)
{
if (hl_item->hfile->filename)
DLOG("profile %u include hostlist %s%s\n",dpl->dp.n, hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
else
DLOG("profile %u include fixed hostlist%s\n",dpl->dp.n, hl_item->hfile->hostlist ? "" : " (empty)");
}
LIST_FOREACH(hl_item, &dpl->dp.hl_collection_exclude, next)
{
if (hl_item->hfile->filename)
DLOG("profile %u exclude hostlist %s%s\n",dpl->dp.n,hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
else
DLOG("profile %u exclude fixed hostlist%s\n",dpl->dp.n,hl_item->hfile->hostlist ? "" : " (empty)");
}
if (dpl->dp.hostlist_auto)
DLOG("profile %u auto hostlist %s%s\n",dpl->dp.n,dpl->dp.hostlist_auto->filename,dpl->dp.hostlist_auto->hostlist ? "" : " (empty)");
HostlistsDebugProfile(&dpl->dp, "profile");
}
LIST_FOREACH(dpl, &params.desync_templates, next)
{
HostlistsDebugProfile(&dpl->dp, "template");
}
}

View File

@@ -235,7 +235,7 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
if (PROFILE_IPSETS_ABSENT(dp)) return true;
DLOG("* ipset check for profile %u\n",dp->n);
DLOG("* ipset check for profile %u (%s)\n",dp->n,PROFILE_NAME(dp));
return IpsetCheck_(&dp->ips_collection,&dp->ips_collection_exclude,ipv4,ipv6);
}
@@ -287,13 +287,31 @@ static const char *dbg_ipset_fill(const ipset *ips)
else
return "empty";
}
void IpsetsDebugProfile(const struct desync_profile *dp, const char *entity)
{
struct ipset_item *ips_item;
LIST_FOREACH(ips_item, &dp->ips_collection, next)
{
if (ips_item->hfile->filename)
DLOG("%s %u (%s) include ipset %s (%s)\n",entity,dp->n,PROFILE_NAME(dp),ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
else
DLOG("%s %u (%s) include fixed ipset (%s)\n",entity,dp->n,PROFILE_NAME(dp),dbg_ipset_fill(&ips_item->hfile->ipset));
}
LIST_FOREACH(ips_item, &dp->ips_collection_exclude, next)
{
if (ips_item->hfile->filename)
DLOG("%s %u (%s) exclude ipset %s (%s)\n",entity,dp->n,PROFILE_NAME(dp),ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
else
DLOG("%s %u (%s) exclude fixed ipset (%s)\n",entity,dp->n,PROFILE_NAME(dp),dbg_ipset_fill(&ips_item->hfile->ipset));
}
}
void IpsetsDebug()
{
if (!params.debug) return;
struct ipset_file *hfile;
struct desync_profile_list *dpl;
struct ipset_item *ips_item;
LIST_FOREACH(hfile, &params.ipsets, next)
{
@@ -305,15 +323,10 @@ void IpsetsDebug()
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
LIST_FOREACH(ips_item, &dpl->dp.ips_collection, next)
if (ips_item->hfile->filename)
DLOG("profile %u include ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
else
DLOG("profile %u include fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset));
LIST_FOREACH(ips_item, &dpl->dp.ips_collection_exclude, next)
if (ips_item->hfile->filename)
DLOG("profile %u exclude ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
else
DLOG("profile %u exclude fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset));
IpsetsDebugProfile(&dpl->dp, "profile");
}
LIST_FOREACH(dpl, &params.desync_templates, next)
{
IpsetsDebugProfile(&dpl->dp, "template");
}
}

View File

@@ -19,6 +19,11 @@
#include "crypto/aes-ctr.h"
void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size)
{
snprintf(instance, inst_size, "%s_%u_%u", func, dp_n, func_n);
}
static void lua_check_argc(lua_State *L, const char *where, int argc)
{
int num_args = lua_gettop(L);
@@ -639,7 +644,7 @@ static int luacall_instance_cutoff(lua_State *L)
int argc=lua_gettop(L);
bool bIn,bOut;
if (argc>=2)
if (argc>=2 && lua_type(L,2)!=LUA_TNIL)
{
luaL_checktype(L,2,LUA_TBOOLEAN);
bOut = lua_toboolean(L,2);
@@ -705,6 +710,102 @@ bool lua_instance_cutoff_check(const t_lua_desync_context *ctx, bool bIn)
return b;
}
static int luacall_lua_cutoff(lua_State *L)
{
lua_check_argc_range(L,"lua_cutoff",1,2);
LUA_STACK_GUARD_ENTER(L)
t_lua_desync_context *ctx;
if (!lua_islightuserdata(L,1))
luaL_error(L, "lua_cutoff expect desync context in the first argument");
ctx = lua_touserdata(L,1);
int argc=lua_gettop(L);
bool bIn,bOut;
if (argc>=2 && lua_type(L,2)!=LUA_TNIL)
{
luaL_checktype(L,2,LUA_TBOOLEAN);
bOut = lua_toboolean(L,2);
bIn = !bOut;
}
else
bIn = bOut = true;
if (ctx->ctrack)
{
DLOG("lua cutoff from '%s' in=%u out=%u\n",ctx->instance,bIn,bOut);
// lua cutoff is one way transition
if (bIn) ctx->ctrack->b_lua_in_cutoff = true;
if (bOut) ctx->ctrack->b_lua_out_cutoff = true;
}
else
DLOG("lua cutoff requested from '%s' in=%u out=%u but not possible without conntrack\n",ctx->instance,bIn,bOut);
LUA_STACK_GUARD_RETURN(L,0)
}
static int luacall_execution_plan(lua_State *L)
{
lua_check_argc(L,"execution_plan",1);
LUA_STACK_GUARD_ENTER(L)
const t_lua_desync_context *ctx;
if (!lua_islightuserdata(L,1))
luaL_error(L, "execution_plan expect desync context in the first argument");
ctx = lua_touserdata(L,1);
lua_newtable(L);
struct func_list *func;
char instance[256], pls[2048];
struct packet_range *range;
unsigned int n=1;
LIST_FOREACH(func, &ctx->dp->lua_desync, next)
{
if (n > ctx->func_n)
{
desync_instance(func->func, ctx->dp->n, n, instance, sizeof(instance));
range = ctx->incoming ? &func->range_in : &func->range_out;
lua_pushinteger(params.L, n - ctx->func_n);
lua_createtable(params.L, 0, 6);
lua_pushf_args(&func->args, -1);
lua_pushf_str("func", func->func);
lua_pushf_int("func_n", ctx->func_n);
lua_pushf_str("func_instance", instance);
lua_pushf_range("range", range);
if (l7_payload_str_list(func->payload_type, pls, sizeof(pls)))
lua_pushf_str("payload_filter", pls);
else
lua_pushf_nil("payload_filter");
lua_rawset(params.L,-3);
}
n++;
}
LUA_STACK_GUARD_RETURN(L,1)
}
static int luacall_execution_plan_cancel(lua_State *L)
{
lua_check_argc(L,"execution_plan_cancel",1);
t_lua_desync_context *ctx;
if (!lua_islightuserdata(L,1))
luaL_error(L, "execution_plan_cancel expect desync context in the first argument");
ctx = lua_touserdata(L,1);
DLOG("execution plan cancel from '%s'\n",ctx->instance);
ctx->cancel = true;
return 0;
}
static int luacall_raw_packet(lua_State *L)
{
lua_check_argc(L,"raw_packet",1);
@@ -1066,21 +1167,23 @@ void lua_pushf_dissect(const struct dissect *dis)
lua_rawset(params.L,-3);
}
void lua_pushf_ctrack(const t_ctrack *ctrack)
void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos)
{
LUA_STACK_GUARD_ENTER(params.L)
if (!pos) pos = &ctrack->pos;
lua_pushliteral(params.L, "track");
if (ctrack)
{
lua_createtable(params.L, 0, 13 + (ctrack->ipproto == IPPROTO_TCP));
lua_pushf_int("pcounter_orig", ctrack->pcounter_orig);
lua_pushf_int("pdcounter_orig", ctrack->pdcounter_orig);
lua_pushf_int("pbcounter_orig", ctrack->pbcounter_orig);
lua_pushf_int("pcounter_reply", ctrack->pcounter_reply);
lua_pushf_int("pdcounter_reply", ctrack->pdcounter_reply);
lua_pushf_int("pbcounter_reply", ctrack->pbcounter_reply);
lua_pushf_int("pcounter_orig", pos->pcounter_orig);
lua_pushf_int("pdcounter_orig", pos->pdcounter_orig);
lua_pushf_int("pbcounter_orig", pos->pbcounter_orig);
lua_pushf_int("pcounter_reply", pos->pcounter_reply);
lua_pushf_int("pdcounter_reply", pos->pdcounter_reply);
lua_pushf_int("pbcounter_reply", pos->pbcounter_reply);
if (ctrack->incoming_ttl)
lua_pushf_int("incoming_ttl", ctrack->incoming_ttl);
else
@@ -1096,20 +1199,20 @@ void lua_pushf_ctrack(const t_ctrack *ctrack)
{
lua_pushliteral(params.L, "tcp");
lua_createtable(params.L, 0, 14);
lua_pushf_int("seq0", ctrack->seq0);
lua_pushf_int("seq", ctrack->seq_last);
lua_pushf_int("ack0", ctrack->ack0);
lua_pushf_int("ack", ctrack->ack_last);
lua_pushf_int("pos_orig", ctrack->pos_orig - ctrack->seq0);
lua_pushf_int("winsize_orig", ctrack->winsize_orig);
lua_pushf_int("winsize_orig_calc", ctrack->winsize_orig_calc);
lua_pushf_int("scale_orig", ctrack->scale_orig);
lua_pushf_int("mss_orig", ctrack->mss_orig);
lua_pushf_int("pos_reply", ctrack->pos_reply - ctrack->ack0);
lua_pushf_int("winsize_reply", ctrack->winsize_reply);
lua_pushf_int("winsize_reply_calc", ctrack->winsize_reply_calc);
lua_pushf_int("scale_reply", ctrack->scale_reply);
lua_pushf_int("mss_reply", ctrack->mss_reply);
lua_pushf_int("seq0", pos->seq0);
lua_pushf_int("seq", pos->seq_last);
lua_pushf_int("ack0", pos->ack0);
lua_pushf_int("ack", pos->ack_last);
lua_pushf_int("pos_orig", pos->pos_orig - pos->seq0);
lua_pushf_int("winsize_orig", pos->winsize_orig);
lua_pushf_int("winsize_orig_calc", pos->winsize_orig_calc);
lua_pushf_int("scale_orig", pos->scale_orig);
lua_pushf_int("mss_orig", pos->mss_orig);
lua_pushf_int("pos_reply", pos->pos_reply - pos->ack0);
lua_pushf_int("winsize_reply", pos->winsize_reply);
lua_pushf_int("winsize_reply_calc", pos->winsize_reply_calc);
lua_pushf_int("scale_reply", pos->scale_reply);
lua_pushf_int("mss_reply", pos->mss_reply);
lua_rawset(params.L,-3);
}
}
@@ -1120,7 +1223,7 @@ void lua_pushf_ctrack(const t_ctrack *ctrack)
LUA_STACK_GUARD_LEAVE(params.L, 0)
}
void lua_pushf_args(const struct ptr_list_head *args, int idx_desync)
void lua_pushf_args(const struct str2_list_head *args, int idx_desync)
{
// var=val - pass val string
// var=%val - subst 'val' blob
@@ -1130,7 +1233,7 @@ void lua_pushf_args(const struct ptr_list_head *args, int idx_desync)
LUA_STACK_GUARD_ENTER(params.L)
struct ptr_list *arg;
struct str2_list *arg;
const char *var, *val;
idx_desync = lua_absindex(params.L, idx_desync);
@@ -1139,8 +1242,8 @@ void lua_pushf_args(const struct ptr_list_head *args, int idx_desync)
lua_newtable(params.L);
LIST_FOREACH(arg, args, next)
{
var = (char*)arg->ptr1;
val = arg->ptr2 ? (char*)arg->ptr2 : "";
var = arg->str1;
val = arg->str2 ? arg->str2 : "";
if (val[0]=='\\' && (val[1]=='%' || val[1]=='#'))
// escape char
lua_pushf_str(var, val+1);
@@ -1160,7 +1263,33 @@ void lua_pushf_args(const struct ptr_list_head *args, int idx_desync)
LUA_STACK_GUARD_LEAVE(params.L, 0)
}
void lua_pushf_pos(const char *name, const struct packet_pos *pos)
{
LUA_STACK_GUARD_ENTER(params.L)
char smode[2]="?";
lua_pushf_table(name);
lua_getfield(params.L,-1,name);
*smode=pos->mode;
lua_pushf_str("mode",smode);
lua_pushf_int("pos",pos->pos);
lua_pop(params.L,1);
LUA_STACK_GUARD_LEAVE(params.L, 0)
}
void lua_pushf_range(const char *name, const struct packet_range *range)
{
LUA_STACK_GUARD_ENTER(params.L)
lua_pushf_table(name);
lua_getfield(params.L,-1,"range");
lua_pushf_bool("upper_cutoff",range->upper_cutoff);
lua_pushf_pos("from", &range->from);
lua_pushf_pos("to", &range->to);
lua_pop(params.L,1);
LUA_STACK_GUARD_LEAVE(params.L, 0)
}
static void lua_reconstruct_extract_options(lua_State *L, int idx, bool *badsum, bool *ip6_preserve_next, uint8_t *ip6_last_proto)
@@ -2663,6 +2792,21 @@ static void lua_init_const(void)
{
LUA_STACK_GUARD_ENTER(params.L)
const struct
{
const char *name, *v;
} cstr[] = {
{"NFQWS2_VER",params.verstr}
};
DLOG("LUA STR:");
for (int i=0;i<sizeof(cstr)/sizeof(*cstr);i++)
{
lua_pushstring(params.L, cstr[i].v);
lua_setglobal(params.L, cstr[i].name);
DLOG(" %s", cstr[i].name);
}
const struct
{
const char *name;
@@ -2674,6 +2818,7 @@ static void lua_init_const(void)
{"divert_port",params.port},
#endif
{"desync_fwmark",params.desync_fwmark},
{"NFQWS2_COMPAT_VER",LUA_COMPAT_VER},
{"VERDICT_PASS",VERDICT_PASS},
{"VERDICT_MODIFY",VERDICT_MODIFY},
@@ -2735,7 +2880,7 @@ static void lua_init_const(void)
{"IPPROTO_SHIM6",IPPROTO_SHIM6},
{"IPPROTO_NONE",IPPROTO_NONE}
};
DLOG("LUA NUMERIC:");
DLOG("\nLUA NUMERIC:");
for (int i=0;i<sizeof(cuint)/sizeof(*cuint);i++)
{
lua_pushinteger(params.L, (lua_Integer)cuint[i].v);
@@ -2836,6 +2981,12 @@ static void lua_init_functions(void)
// voluntarily stop receiving packets
{"instance_cutoff",luacall_instance_cutoff},
// voluntarily stop receiving packets of the current connection for all instances
{"lua_cutoff",luacall_lua_cutoff},
// get info about upcoming desync instances and their arguments
{"execution_plan",luacall_execution_plan},
// cancel execution of upcoming desync instances and their arguments
{"execution_plan_cancel",luacall_execution_plan_cancel},
// get raw packet data
{"raw_packet",luacall_raw_packet},

View File

@@ -28,6 +28,9 @@
#define LUA_STACK_GUARD_RETURN(L,N) LUA_STACK_GUARD_LEAVE(L,N); return N;
void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size);
bool lua_test_init_script_files(void);
bool lua_init(void);
void lua_shutdown(void);
@@ -68,8 +71,10 @@ void lua_pushf_iphdr(const struct ip *ip, size_t len);
void lua_pushf_ip6hdr(const struct ip6_hdr *ip6, size_t len);
void lua_push_dissect(const struct dissect *dis);
void lua_pushf_dissect(const struct dissect *dis);
void lua_pushf_ctrack(const t_ctrack *ctrack);
void lua_pushf_args(const struct ptr_list_head *args, int idx_desync);
void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos);
void lua_pushf_args(const struct str2_list_head *args, int idx_desync);
void lua_pushf_pos(const char *name, const struct packet_pos *pos);
void lua_pushf_range(const char *name, const struct packet_range *range);
void lua_pushf_global(const char *field, const char *global);
bool lua_reconstruct_ip6hdr(int idx, struct ip6_hdr *ip6, size_t *len, uint8_t last_proto, bool preserve_next);
@@ -79,10 +84,12 @@ bool lua_reconstruct_udphdr(int idx, struct udphdr *udp);
bool lua_reconstruct_dissect(int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next);
typedef struct {
unsigned int func_n;
const char *func, *instance;
const struct desync_profile *dp;
const t_ctrack *ctrack;
const struct dissect *dis;
t_ctrack *ctrack;
bool incoming,cancel;
} t_lua_desync_context;
bool lua_instance_cutoff_check(const t_lua_desync_context *ctx, bool bIn);

View File

@@ -48,11 +48,6 @@
#define NF_ACCEPT 1
#endif
#define CTRACK_T_SYN 60
#define CTRACK_T_FIN 60
#define CTRACK_T_EST 300
#define CTRACK_T_UDP 60
#define MAX_CONFIG_FILE_SIZE 16384
struct params_s params;
@@ -99,7 +94,7 @@ static void onusr2(int sig)
struct desync_profile_list *dpl;
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
printf("\nDESYNC profile %u\n", dpl->dp.n);
printf("\nDESYNC profile %u (%s)\n", dpl->dp.n, PROFILE_NAME(&dpl->dp));
HostFailPoolDump(dpl->dp.hostlist_auto_fail_counters);
}
printf("\nIPCACHE\n");
@@ -1007,27 +1002,28 @@ static bool parse_pf_list(char *opt, struct port_filters_head *pfl)
return true;
}
bool lua_call_param_add(char *opt, struct ptr_list_head *args)
bool lua_call_param_add(char *opt, struct str2_list_head *args)
{
char c,*p;
struct ptr_list *arg;
struct str2_list *arg;
if ((p = strchr(opt,'=')))
{
c = *p; *p = 0;
}
if (!is_identifier(opt) || !(arg=ptrlist_add(args)))
if (!is_identifier(opt) || !(arg=str2list_add(args)))
{
if (p) *p = c;
return false;
}
arg->ptr1 = strdup(opt);
arg->str1 = strdup(opt);
if (p)
{
arg->ptr2 = strdup(p+1);
arg->str2 = strdup(p+1);
*p = c;
if (!arg->str2) return false;
}
return arg->ptr1;
return !!arg->str1;
}
struct func_list *parse_lua_call(char *opt, struct func_list_head *flist)
@@ -1053,7 +1049,6 @@ struct func_list *parse_lua_call(char *opt, struct func_list_head *flist)
last = !*e;
c = *e;
*e = 0;
b = lua_call_param_add(p, &f->args);
if (!last) *e++ = c;
if (!b) goto err;
@@ -1156,21 +1151,21 @@ static void BlobDebug()
}
}
static void LuaDesyncDebug(struct desync_profile *dp)
static void LuaDesyncDebug(struct desync_profile *dp, const char *entity)
{
if (params.debug)
{
struct func_list *func;
struct ptr_list *arg;
struct str2_list *arg;
int n,i;
LIST_FOREACH(func, &dp->lua_desync, next)
{
DLOG("profile %u lua %s(",dp->n,func->func);
DLOG("%s %u (%s) lua %s(",entity,dp->n,PROFILE_NAME(dp),func->func);
n=0;
LIST_FOREACH(arg, &func->args, next)
{
if (n) DLOG(",");
DLOG(arg->ptr2 ? "%s=\"%s\"" : "%s=\"\"", (char*)arg->ptr1, (char*)arg->ptr2);
DLOG(arg->str2 ? "%s=\"%s\"" : "%s=\"\"", arg->str1, arg->str2);
n++;
}
DLOG(" range_in=%c%u%c%c%u range_out=%c%u%c%c%u payload_type=",
@@ -1412,8 +1407,12 @@ static void exithelp(void)
" --lua-init=@<filename>|<lua_text>\t\t\t; load LUA program from a file or string. if multiple parameters present order of execution is preserved.\n"
" --lua-gc=<int>\t\t\t\t\t\t; forced garbage collection every N sec. default %u sec. triggers only when a packet arrives. 0 = disable.\n"
"\nMULTI-STRATEGY:\n"
" --new\t\t\t\t\t\t\t; begin new strategy\n"
" --skip\t\t\t\t\t\t\t; do not use this strategy\n"
" --new\t\t\t\t\t\t\t; begin new profile\n"
" --skip\t\t\t\t\t\t\t; do not use this profile\n"
" --name=<name>\t\t\t\t\t\t; set profile name\n"
" --template[=<name>]\t\t\t\t\t; use this profile as template (must be named or will be useless)\n"
" --cookie[=<string>]\t\t\t\t\t; pass this profile-bound string to LUA\n"
" --import=<name>\t\t\t\t\t; populate current profile with template data\n"
" --filter-l3=ipv4|ipv6\t\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
" --filter-tcp=[~]port1[-port2]|*\t\t\t; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list allowed.\n"
" --filter-udp=[~]port1[-port2]|*\t\t\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list allowed.\n"
@@ -1500,22 +1499,6 @@ static void ApplyDefaultBlobs(struct blob_collection_head *blobs)
load_const_blob_to_collection("fake_default_quic",buf,620,blobs,0);
}
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
#ifdef __ANDROID__
#define PRINT_VER printf("github android version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#else
#define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
#endif
#else
#ifdef __ANDROID__
#define PRINT_VER printf("self-built android version %s %s\n\n", __DATE__, __TIME__)
#else
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
#endif
#endif
enum opt_indices {
IDX_DEBUG,
IDX_DRY_RUN,
@@ -1563,6 +1546,10 @@ enum opt_indices {
IDX_HOSTLIST_AUTO_DEBUG,
IDX_NEW,
IDX_SKIP,
IDX_NAME,
IDX_TEMPLATE,
IDX_IMPORT,
IDX_COOKIE,
IDX_FILTER_L3,
IDX_FILTER_TCP,
IDX_FILTER_UDP,
@@ -1643,6 +1630,10 @@ static const struct option long_options[] = {
[IDX_HOSTLIST_AUTO_DEBUG] = {"hostlist-auto-debug", required_argument, 0, 0},
[IDX_NEW] = {"new", no_argument, 0, 0},
[IDX_SKIP] = {"skip", no_argument, 0, 0},
[IDX_NAME] = {"name", required_argument, 0, 0},
[IDX_TEMPLATE] = {"template", optional_argument, 0, 0},
[IDX_IMPORT] = {"import", required_argument, 0, 0},
[IDX_COOKIE] = {"cookie", required_argument, 0, 0},
[IDX_FILTER_L3] = {"filter-l3", required_argument, 0, 0},
[IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0},
[IDX_FILTER_UDP] = {"filter-udp", required_argument, 0, 0},
@@ -1679,16 +1670,26 @@ static const struct option long_options[] = {
[IDX_LAST] = {NULL, 0, NULL, 0},
};
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
#ifdef __ANDROID__
#define MAKE_VER(s,size) snprintf(s,size,"github android version %s (%s) lua_compat_ver %u", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH), LUA_COMPAT_VER)
#else
#define MAKE_VER(s,size) snprintf(s,size,"github version %s (%s) lua_compat_ver %u", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH), LUA_COMPAT_VER)
#endif
#else
#ifdef __ANDROID__
#define MAKE_VER(s,size) snprintf(s,size,"self-built android version %s %s lua_compat_ver %u", __DATE__, __TIME__, LUA_COMPAT_VER)
#else
#define MAKE_VER(s,size) snprintf(s,size,"self-built version %s %s lua_compat_ver %u", __DATE__, __TIME__, LUA_COMPAT_VER)
#endif
#endif
int main(int argc, char **argv)
{
if (argc < 2) exithelp();
aes_init_keygen_tables(); // required for aes
set_console_io_buffering();
set_env_exedir(argv[0]);
#ifdef __CYGWIN__
prepare_low_appdata();
if (service_run(argc, argv))
{
// we were running as service. now exit.
@@ -1697,7 +1698,7 @@ int main(int argc, char **argv)
#endif
int result, v;
int option_index = 0;
bool bSkip = false, bDry = false;
bool bSkip = false, bDry = false, bTemplate;
struct hostlist_file *anon_hl = NULL, *anon_hl_exclude = NULL;
struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL;
uint64_t payload_type=0;
@@ -1709,17 +1710,29 @@ int main(int argc, char **argv)
unsigned int hash_wf_tcp_in = 0, hash_wf_udp_in = 0, hash_wf_tcp_out = 0, hash_wf_udp_out = 0, hash_wf_raw = 0, hash_wf_raw_part = 0, hash_ssid_filter = 0, hash_nlm_filter = 0;
#endif
if (argc < 2) exithelp();
srandom(time(NULL));
aes_init_keygen_tables(); // required for aes
mask_from_preflen6_prepare();
set_env_exedir(argv[0]);
set_console_io_buffering();
#ifdef __CYGWIN__
prepare_low_appdata();
#endif
PRINT_VER;
init_params(&params);
memset(&params, 0, sizeof(params));
MAKE_VER(params.verstr, sizeof(params.verstr));
printf("%s\n\n",params.verstr);
ApplyDefaultBlobs(&params.blobs);
struct desync_profile_list *dpl;
struct desync_profile *dp;
unsigned int desync_profile_count = 0;
unsigned int desync_profile_count = 0, desync_template_count = 0;
bTemplate = false;
if (!(dpl = dp_list_add(&params.desync_profiles)))
{
DLOG_ERR("desync_profile_add: out of memory\n");
@@ -1728,39 +1741,6 @@ int main(int argc, char **argv)
dp = &dpl->dp;
dp->n = ++desync_profile_count;
#ifdef __linux__
params.qnum = -1;
#elif defined(BSD)
params.port = 0;
#endif
params.desync_fwmark = DPI_DESYNC_FWMARK_DEFAULT;
params.ctrack_t_syn = CTRACK_T_SYN;
params.ctrack_t_est = CTRACK_T_EST;
params.ctrack_t_fin = CTRACK_T_FIN;
params.ctrack_t_udp = CTRACK_T_UDP;
params.ipcache_lifetime = IPCACHE_LIFETIME;
params.lua_gc = LUA_GC_INTERVAL;
LIST_INIT(&params.hostlists);
LIST_INIT(&params.ipsets);
LIST_INIT(&params.blobs);
LIST_INIT(&params.lua_init_scripts);
ApplyDefaultBlobs(&params.blobs);
#ifdef __CYGWIN__
LIST_INIT(&params.ssid_filter);
LIST_INIT(&params.nlm_filter);
LIST_INIT(&params.wf_raw_part);
#else
if (can_drop_root())
{
params.uid = params.gid[0] = 0x7FFFFFFF; // default uid:gid
params.gid_count = 1;
params.droproot = true;
}
#endif
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
if (argc >= 2 && (argv[1][0] == '@' || argv[1][0] == '$'))
{
@@ -2120,23 +2100,83 @@ int main(int argc, char **argv)
else
{
check_dp(dp);
if (bTemplate)
{
if (dp->name && dp_list_search_name(&params.desync_templates, dp->name))
{
DLOG_ERR("template '%s' already present\n", dp->name);
exit_clean(1);
}
dpl->dp.n = ++desync_template_count;
dp_list_move(&params.desync_templates, dpl);
}
else
{
desync_profile_count++;
}
if (!(dpl = dp_list_add(&params.desync_profiles)))
{
DLOG_ERR("desync_profile_add: out of memory\n");
exit_clean(1);
}
dp = &dpl->dp;
dp->n = ++desync_profile_count;
dp->n = desync_profile_count;
}
anon_hl = anon_hl_exclude = NULL;
anon_ips = anon_ips_exclude = NULL;
payload_type = 0;
range_in = PACKET_RANGE_NEVER;
range_out = PACKET_RANGE_ALWAYS;
bTemplate = false;
break;
case IDX_SKIP:
bSkip = true;
break;
case IDX_TEMPLATE:
bTemplate = true;
case IDX_NAME:
if (optarg)
{
free(dp->name);
if (!(dp->name = strdup(optarg)))
{
DLOG_ERR("out of memory\n");
exit_clean(1);
}
}
break;
case IDX_COOKIE:
free(dp->cookie);
if (!(dp->cookie = strdup(optarg)))
{
DLOG_ERR("out of memory\n");
exit_clean(1);
}
break;
case IDX_IMPORT:
{
struct desync_profile_list *tpl = dp_list_search_name(&params.desync_templates, optarg);
if (!tpl)
{
DLOG_ERR("template '%s' not found\n", optarg);
exit_clean(1);
}
if (!dp_list_copy(dp, &tpl->dp))
{
DLOG_ERR("could not copy template\n");
exit_clean(1);
}
dp->n = desync_profile_count;
free(dp->name_tpl);
if (tpl->dp.name && !(dp->name_tpl = strdup(tpl->dp.name)))
{
DLOG_ERR("out of memory\n");
exit_clean(1);
}
dp->n_tpl = tpl->dp.n;
}
break;
case IDX_FILTER_L3:
if (!wf_make_l3(optarg, &dp->filter_ipv4, &dp->filter_ipv6))
@@ -2399,7 +2439,20 @@ int main(int argc, char **argv)
desync_profile_count--;
}
else
{
check_dp(dp);
if (bTemplate)
{
if (dp->name && dp_list_search_name(&params.desync_templates, dp->name))
{
DLOG_ERR("template '%s' already present\n", dp->name);
exit_clean(1);
}
dpl->dp.n = ++desync_template_count;
dp_list_move(&params.desync_templates, dpl);
desync_profile_count--;
}
}
// do not need args from file anymore
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
@@ -2423,13 +2476,14 @@ int main(int argc, char **argv)
DLOG("adding low-priority default empty desync profile\n");
// add default empty profile
if (!(dpl = dp_list_add(&params.desync_profiles)))
if (!(dpl = dp_list_add(&params.desync_profiles)) || !(dpl->dp.name=strdup("no_action")))
{
DLOG_ERR("desync_profile_add: out of memory\n");
exit_clean(1);
}
DLOG_CONDUP("we have %d user defined desync profile(s) and default low priority profile 0\n", desync_profile_count);
DLOG_CONDUP("we have %u user defined desync profile(s) and default low priority profile 0\n", desync_profile_count);
DLOG_CONDUP("we have %u user defined desync template(s)\n", desync_template_count);
if (params.writeable_dir_enable)
{
@@ -2463,11 +2517,16 @@ int main(int argc, char **argv)
if (params.droproot)
#endif
{
if (dp->hostlist_auto && ensure_file_access(dp->hostlist_auto->filename))
if (dp->hostlist_auto && !ensure_file_access(dp->hostlist_auto->filename))
DLOG_ERR("could not make '%s' accessible. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename);
}
LuaDesyncDebug(dp);
LuaDesyncDebug(dp,"profile");
}
LIST_FOREACH(dpl, &params.desync_templates, next)
{
dp = &dpl->dp;
LuaDesyncDebug(dp,"template");
}
if (!test_list_files())
@@ -2493,6 +2552,9 @@ int main(int argc, char **argv)
BlobDebug();
DLOG("\n");
// not required anymore. free memory
dp_list_destroy(&params.desync_templates);
#ifdef __CYGWIN__
if (!*params.windivert_filter)
{

View File

@@ -10,3 +10,6 @@
extern bool bQuit;
#endif
int main(int argc, char *argv[]);
// when something changes that can break LUA compatibility this version should be increased
#define LUA_COMPAT_VER 2

View File

@@ -26,7 +26,7 @@ void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
while((rp = rawpacket_dequeue(q))) rawpacket_free(rp);
}
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload)
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload,const t_ctrack_position *pos)
{
struct rawpacket *rp = malloc(sizeof(struct rawpacket));
if (!rp) return NULL;
@@ -52,6 +52,15 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
memcpy(rp->packet,data,len);
rp->len=len;
rp->len_payload=len_payload;
// make a copy for replay
if (pos)
{
rp->pos = *pos;
rp->pos_present = true;
}
else
rp->pos_present = false;
TAILQ_INSERT_TAIL(q, rp, next);

View File

@@ -6,6 +6,8 @@
#include <net/if.h>
#include <sys/socket.h>
#include "conntrack_base.h"
struct rawpacket
{
struct sockaddr_storage dst;
@@ -14,6 +16,8 @@ struct rawpacket
uint32_t fwmark;
size_t len, len_payload;
uint8_t *packet;
t_ctrack_position pos;
bool pos_present;
TAILQ_ENTRY(rawpacket) next;
};
TAILQ_HEAD(rawpacket_tailhead, rawpacket);
@@ -22,6 +26,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q);
void rawpacket_queue_destroy(struct rawpacket_tailhead *q);
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q);
unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q);
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload);
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload,const t_ctrack_position *pos);
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q);
void rawpacket_free(struct rawpacket *rp);

View File

@@ -322,7 +322,7 @@ void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
}
}
void dp_init(struct desync_profile *dp)
void dp_init_dynamic(struct desync_profile *dp)
{
LIST_INIT(&dp->hl_collection);
LIST_INIT(&dp->hl_collection_exclude);
@@ -331,33 +331,25 @@ void dp_init(struct desync_profile *dp)
LIST_INIT(&dp->pf_tcp);
LIST_INIT(&dp->pf_udp);
LIST_INIT(&dp->lua_desync);
#ifdef HAS_FILTER_SSID
LIST_INIT(&dp->filter_ssid);
#endif
}
void dp_init(struct desync_profile *dp)
{
dp_init_dynamic(dp);
dp->hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
dp->filter_ipv4 = dp->filter_ipv6 = true;
}
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
{
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
if (!entry) return NULL;
dp_init(&entry->dp);
// add to the tail
struct desync_profile_list *dpn,*dpl=LIST_FIRST(&params.desync_profiles);
if (dpl)
{
while ((dpn=LIST_NEXT(dpl,next))) dpl = dpn;
LIST_INSERT_AFTER(dpl, entry, next);
}
else
LIST_INSERT_HEAD(&params.desync_profiles, entry, next);
return entry;
}
static void dp_clear_dynamic(struct desync_profile *dp)
{
free(dp->name);
free(dp->name_tpl);
free(dp->cookie);
hostlist_collection_destroy(&dp->hl_collection);
hostlist_collection_destroy(&dp->hl_collection_exclude);
ipset_collection_destroy(&dp->ips_collection);
@@ -389,6 +381,67 @@ void dp_list_destroy(struct desync_profile_list_head *head)
dp_entry_destroy(entry);
}
}
static struct desync_profile_list *desync_profile_entry_alloc()
{
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
if (entry) dp_init(&entry->dp);
return entry;
}
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
{
struct desync_profile_list *entry = desync_profile_entry_alloc();
if (!entry) return false;
struct desync_profile_list *tail, *item;
LIST_TAIL(head, tail, item);
LIST_INSERT_TAIL(head, tail, entry, next);
return entry;
}
bool dp_list_copy(struct desync_profile *to, const struct desync_profile *from)
{
// clear everything in target
dp_clear(to);
// first copy all simple type values
*to = *from;
// prepare empty dynamic structures
dp_init_dynamic(to);
// copy dynamic structures
if (from->name && !(to->name = strdup(from->name))) return false;
if (from->name_tpl && !(to->name_tpl = strdup(from->name_tpl))) return false;
if (from->cookie && !(to->cookie = strdup(from->cookie))) return false;
if (
#ifdef HAS_FILTER_SSID
!strlist_copy(&to->filter_ssid, &from->filter_ssid) ||
#endif
!funclist_copy(&to->lua_desync, &from->lua_desync) ||
!ipset_collection_copy(&to->ips_collection, &from->ips_collection) ||
!ipset_collection_copy(&to->ips_collection_exclude, &from->ips_collection_exclude) ||
!hostlist_collection_copy(&to->hl_collection, &from->hl_collection) ||
!hostlist_collection_copy(&to->hl_collection_exclude, &from->hl_collection_exclude))
{
return false;
}
return true;
}
void dp_list_move(struct desync_profile_list_head *target, struct desync_profile_list *dpl)
{
struct desync_profile_list *tail, *item;
LIST_TAIL(target, tail, item);
LIST_REMOVE(dpl, next);
LIST_INSERT_TAIL(target, tail, dpl, next);
}
struct desync_profile_list *dp_list_search_name(struct desync_profile_list_head *head, const char *name)
{
struct desync_profile_list *dpl;
if (name)
LIST_FOREACH(dpl, head, next)
if (dpl->dp.name && !strcmp(dpl->dp.name, name))
return dpl;
return NULL;
}
bool dp_list_have_autohostlist(struct desync_profile_list_head *head)
{
struct desync_profile_list *dpl;
@@ -427,6 +480,7 @@ void cleanup_params(struct params_s *params)
ConntrackPoolDestroy(&params->conntrack);
dp_list_destroy(&params->desync_profiles);
dp_list_destroy(&params->desync_templates);
hostlist_files_destroy(&params->hostlists);
ipset_files_destroy(&params->ipsets);
ipcacheDestroy(&params->ipcache);
@@ -440,3 +494,40 @@ void cleanup_params(struct params_s *params)
free(params->user); params->user=NULL;
#endif
}
void init_params(struct params_s *params)
{
memset(params, 0, sizeof(*params));
#ifdef __linux__
params->qnum = -1;
#elif defined(BSD)
params->port = 0;
#endif
params->desync_fwmark = DPI_DESYNC_FWMARK_DEFAULT;
params->ctrack_t_syn = CTRACK_T_SYN;
params->ctrack_t_est = CTRACK_T_EST;
params->ctrack_t_fin = CTRACK_T_FIN;
params->ctrack_t_udp = CTRACK_T_UDP;
params->ipcache_lifetime = IPCACHE_LIFETIME;
params->lua_gc = LUA_GC_INTERVAL;
LIST_INIT(&params->hostlists);
LIST_INIT(&params->ipsets);
LIST_INIT(&params->blobs);
LIST_INIT(&params->lua_init_scripts);
#ifdef __CYGWIN__
LIST_INIT(&params->ssid_filter);
LIST_INIT(&params->nlm_filter);
LIST_INIT(&params->wf_raw_part);
#else
if (can_drop_root())
{
params->uid = params->gid[0] = 0x7FFFFFFF; // default uid:gid
params->gid_count = 1;
params->droproot = true;
}
#endif
}

View File

@@ -6,6 +6,7 @@
#include "desync.h"
#include "protocol.h"
#include "helpers.h"
#include "sec.h"
#include <sys/param.h>
#include <sys/types.h>
@@ -53,6 +54,10 @@ enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG, LOG_
struct desync_profile
{
unsigned int n; // number of the profile
char *name; // optional malloced name string
unsigned int n_tpl; // number of imported template
char *name_tpl; // imported template name
char *cookie; // optional malloced string
bool filter_ipv4,filter_ipv6;
struct port_filters_head pf_tcp,pf_udp;
@@ -78,6 +83,7 @@ struct desync_profile
struct func_list_head lua_desync;
};
#define PROFILE_NAME(dp) ((dp)->name ? (dp)->name : "noname")
#define PROFILE_IPSETS_ABSENT(dp) (!LIST_FIRST(&(dp)->ips_collection) && !LIST_FIRST(&(dp)->ips_collection_exclude))
#define PROFILE_IPSETS_EMPTY(dp) (ipset_collection_is_empty(&(dp)->ips_collection) && ipset_collection_is_empty(&(dp)->ips_collection_exclude))
@@ -89,6 +95,9 @@ struct desync_profile_list {
};
LIST_HEAD(desync_profile_list_head, desync_profile_list);
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head);
void dp_list_move(struct desync_profile_list_head *target, struct desync_profile_list *dpl);
bool dp_list_copy(struct desync_profile *to, const struct desync_profile *from);
struct desync_profile_list *dp_list_search_name(struct desync_profile_list_head *head, const char *name);
void dp_entry_destroy(struct desync_profile_list *entry);
void dp_list_destroy(struct desync_profile_list_head *head);
bool dp_list_have_autohostlist(struct desync_profile_list_head *head);
@@ -104,6 +113,7 @@ struct params_s
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
wordexp_t wexp; // for file based config
#endif
char verstr[128];
enum log_target debug_target;
char debug_logfile[PATH_MAX];
@@ -119,7 +129,7 @@ struct params_s
bool bind_fix4,bind_fix6;
uint32_t desync_fwmark; // unused in BSD
struct desync_profile_list_head desync_profiles;
struct desync_profile_list_head desync_profiles, desync_templates;
#ifdef __CYGWIN__
struct str_list_head ssid_filter,nlm_filter;
@@ -170,6 +180,8 @@ struct params_s
extern struct params_s params;
extern const char *progname;
void init_params(struct params_s *params);
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
void cleanup_args(struct params_s *params);
#endif

View File

@@ -155,20 +155,33 @@ bool strlist_add(struct str_list_head *head, const char *str)
LIST_INSERT_HEAD(head, entry, next);
return true;
}
static struct str_list *strlist_entry_copy(const struct str_list *entry)
{
return strlist_entry_alloc(entry->str);
}
bool strlist_copy(struct str_list_head *to, const struct str_list_head *from)
{
struct str_list *tail, *item, *entry;
LIST_TAIL(to, tail, item);
LIST_FOREACH(item, from, next)
{
if (!(entry = strlist_entry_copy(item))) return false;
LIST_INSERT_TAIL(to, tail, entry, next);
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
}
return true;
}
bool strlist_add_tail(struct str_list_head *head, const char *str)
{
struct str_list *entry = strlist_entry_alloc(str);
if (!entry) return false;
// add to the tail
struct str_list *strn,*strl=LIST_FIRST(head);
if (strl)
{
while ((strn=LIST_NEXT(strl,next))) strl = strn;
LIST_INSERT_AFTER(strl, entry, next);
}
else
LIST_INSERT_HEAD(head, entry, next);
struct str_list *tail, *item;
LIST_TAIL(head, tail, item);
LIST_INSERT_TAIL(head, tail, entry, next);
return true;
}
static void strlist_entry_destroy(struct str_list *entry)
@@ -200,35 +213,77 @@ bool strlist_search(const struct str_list_head *head, const char *str)
}
static struct ptr_list *ptrlist_entry_alloc()
static void str2list_entry_destroy(struct str2_list *entry)
{
return (struct ptr_list*)calloc(1,sizeof(struct ptr_list));
free(entry->str1);
free(entry->str2);
free(entry);
}
void str2list_destroy(struct str2_list_head *head)
{
struct str2_list *entry;
while ((entry = LIST_FIRST(head)))
{
LIST_REMOVE(entry, next);
str2list_entry_destroy(entry);
}
}
static struct str2_list *str2list_entry_alloc()
{
return (struct str2_list*)calloc(1,sizeof(struct str2_list));
}
struct ptr_list *ptrlist_add(struct ptr_list_head *head)
struct str2_list *str2list_add(struct str2_list_head *head)
{
struct ptr_list *entry = ptrlist_entry_alloc();
struct str2_list *entry = str2list_entry_alloc();
if (!entry) return NULL;
LIST_INSERT_HEAD(head, entry, next);
return entry;
}
static void ptrlist_entry_destroy(struct ptr_list *entry)
static struct str2_list *str2list_entry_copy(const struct str2_list *entry)
{
free(entry->ptr1);
free(entry->ptr2);
struct str2_list *e2 = str2list_entry_alloc();
if (!e2) return NULL;
e2->str1 = strdup(entry->str1);
e2->str2 = strdup(entry->str2);
if (!e2->str1 || !e2->str2)
{
str2list_entry_destroy(e2);
return false;
}
return e2;
}
bool str2list_copy(struct str2_list_head *to, const struct str2_list_head *from)
{
struct str2_list *tail, *item, *entry;
LIST_TAIL(to, tail, item);
LIST_FOREACH(item, from, next)
{
if (!(entry = str2list_entry_copy(item))) return false;
LIST_INSERT_TAIL(to, tail, entry, next);
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
}
return true;
}
static void funclist_entry_destroy(struct func_list *entry)
{
free(entry->func);
str2list_destroy(&entry->args);
free(entry);
}
void ptrlist_destroy(struct ptr_list_head *head)
void funclist_destroy(struct func_list_head *head)
{
struct ptr_list *entry;
struct func_list *entry;
while ((entry = LIST_FIRST(head)))
{
LIST_REMOVE(entry, next);
ptrlist_entry_destroy(entry);
funclist_entry_destroy(entry);
}
}
static struct func_list *funclist_entry_alloc(const char *func)
{
struct func_list *entry = malloc(sizeof(struct func_list));
@@ -250,31 +305,38 @@ struct func_list *funclist_add_tail(struct func_list_head *head, const char *fun
struct func_list *entry = funclist_entry_alloc(func);
if (!entry) return NULL;
// add to the tail
struct func_list *funcn,*funcl=LIST_FIRST(head);
if (funcl)
{
while ((funcn=LIST_NEXT(funcl,next))) funcl = funcn;
LIST_INSERT_AFTER(funcl, entry, next);
}
else
LIST_INSERT_HEAD(head, entry, next);
struct func_list *tail, *item;
LIST_TAIL(head, tail, item);
LIST_INSERT_TAIL(head, tail, entry, next);
return entry;
}
static void funclist_entry_destroy(struct func_list *entry)
static struct func_list *funclist_entry_copy(const struct func_list *entry)
{
free(entry->func);
ptrlist_destroy(&entry->args);
free(entry);
}
void funclist_destroy(struct func_list_head *head)
{
struct func_list *entry;
while ((entry = LIST_FIRST(head)))
struct func_list *e2 = funclist_entry_alloc(entry->func);
if (!e2) return NULL;
e2->payload_type = entry->payload_type;
e2->range_in = entry->range_in;
e2->range_out = entry->range_out;
if (!str2list_copy(&e2->args, &entry->args))
{
LIST_REMOVE(entry, next);
funclist_entry_destroy(entry);
funclist_entry_destroy(e2);
return false;
}
return e2;
}
bool funclist_copy(struct func_list_head *to, const struct func_list_head *from)
{
struct func_list *tail, *item, *entry;
LIST_TAIL(to, tail, item);
LIST_FOREACH(item, from, next)
{
if (!(entry = funclist_entry_copy(item))) return false;
LIST_INSERT_TAIL(to, tail, entry, next);
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
}
return true;
}
@@ -333,16 +395,36 @@ void hostlist_files_reset_modtime(struct hostlist_files_head *list)
FILE_MOD_RESET(&hfile->mod_sig);
}
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile)
static struct hostlist_item *hostlist_collection_entry_alloc(struct hostlist_file *hfile)
{
struct hostlist_item *entry = malloc(sizeof(struct hostlist_item));
if (entry)
{
entry->hfile = hfile;
LIST_INSERT_HEAD(head, entry, next);
}
if (entry) entry->hfile = hfile;
return entry;
}
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile)
{
struct hostlist_item *entry = hostlist_collection_entry_alloc(hfile);
if (entry) LIST_INSERT_HEAD(head, entry, next);
return entry;
}
static struct hostlist_item *hostlist_collection_entry_copy(const struct hostlist_item *entry)
{
return hostlist_collection_entry_alloc(entry->hfile);
}
bool hostlist_collection_copy(struct hostlist_collection_head *to, const struct hostlist_collection_head *from)
{
struct hostlist_item *tail, *item, *entry;
LIST_TAIL(to, tail, item);
LIST_FOREACH(item, from, next)
{
if (!(entry = hostlist_collection_entry_copy(item))) return false;
LIST_INSERT_TAIL(to, tail, entry, next);
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
}
return true;
}
void hostlist_collection_destroy(struct hostlist_collection_head *head)
{
struct hostlist_item *entry;
@@ -579,16 +661,36 @@ void ipset_files_reset_modtime(struct ipset_files_head *list)
FILE_MOD_RESET(&hfile->mod_sig);
}
struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile)
static struct ipset_item *ipset_collection_entry_alloc(struct ipset_file *hfile)
{
struct ipset_item *entry = malloc(sizeof(struct ipset_item));
if (entry)
{
entry->hfile = hfile;
LIST_INSERT_HEAD(head, entry, next);
}
if (entry) entry->hfile = hfile;
return entry;
}
struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile)
{
struct ipset_item *entry = ipset_collection_entry_alloc(hfile);
if (entry) LIST_INSERT_HEAD(head, entry, next);
return entry;
}
static struct ipset_item *ipset_collection_entry_copy(const struct ipset_item *entry)
{
return ipset_collection_entry_alloc(entry->hfile);
}
bool ipset_collection_copy(struct ipset_collection_head *to, const struct ipset_collection_head *from)
{
struct ipset_item *tail, *item, *entry;
LIST_TAIL(to, tail, item);
LIST_FOREACH(item, from, next)
{
if (!(entry = ipset_collection_entry_copy(item))) return false;
LIST_INSERT_TAIL(to, tail, entry, next);
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
}
return true;
}
void ipset_collection_destroy(struct ipset_collection_head *head)
{
struct ipset_item *entry;
@@ -645,7 +747,7 @@ bool port_filters_in_range(const struct port_filters_head *head, uint16_t port)
{
const struct port_filter_item *item;
if (!LIST_FIRST(head)) return true;
if (LIST_EMPTY(head)) return true;
LIST_FOREACH(item, head, next)
{
if (pf_in_range(port, &item->pf))
@@ -656,7 +758,7 @@ bool port_filters_in_range(const struct port_filters_head *head, uint16_t port)
bool port_filters_deny_if_empty(struct port_filters_head *head)
{
port_filter pf;
if (LIST_FIRST(head)) return true;
if (!LIST_EMPTY(head)) return true;
return pf_parse("0",&pf) && port_filter_add(head,&pf);
}
@@ -667,15 +769,9 @@ struct blob_item *blob_collection_add(struct blob_collection_head *head)
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
if (entry)
{
// insert to the end
struct blob_item *itemc,*iteml=LIST_FIRST(head);
if (iteml)
{
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
LIST_INSERT_AFTER(iteml, entry, next);
}
else
LIST_INSERT_HEAD(head, entry, next);
struct blob_item *tail, *item;
LIST_TAIL(head, tail, item);
LIST_INSERT_TAIL(head, tail, entry, next);
}
return entry;
}
@@ -693,14 +789,9 @@ struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, co
entry->size_buf = size+size_reserve;
// insert to the end
struct blob_item *itemc,*iteml=LIST_FIRST(head);
if (iteml)
{
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
LIST_INSERT_AFTER(iteml, entry, next);
}
else
LIST_INSERT_HEAD(head, entry, next);
struct blob_item *tail, *item;
LIST_TAIL(head, tail, item);
LIST_INSERT_TAIL(head, tail, entry, next);
return entry;
}
@@ -725,7 +816,7 @@ void blob_collection_destroy(struct blob_collection_head *head)
}
bool blob_collection_empty(const struct blob_collection_head *head)
{
return !LIST_FIRST(head);
return LIST_EMPTY(head);
}
struct blob_item *blob_collection_search_name(struct blob_collection_head *head, const char *name)
{

View File

@@ -17,6 +17,17 @@
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
#define LIST_TAIL(head, tail, temp) {\
tail=LIST_FIRST(head); \
if (tail) while ((temp=LIST_NEXT(tail,next))) tail = temp; }
#define LIST_INSERT_TAIL(head, tail, elm, field) { \
if (LIST_FIRST(head)) \
LIST_INSERT_AFTER(tail, elm, field); \
else \
LIST_INSERT_HEAD(head, elm, field); }
typedef struct hostlist_pool {
char *str; /* key */
uint32_t flags; /* custom data */
@@ -38,25 +49,28 @@ bool strlist_add(struct str_list_head *head, const char *str);
bool strlist_add_tail(struct str_list_head *head, const char *str);
void strlist_destroy(struct str_list_head *head);
bool strlist_search(const struct str_list_head *head, const char *str);
bool strlist_copy(struct str_list_head *to, const struct str_list_head *from);
struct ptr_list {
void *ptr1,*ptr2;
LIST_ENTRY(ptr_list) next;
struct str2_list {
char *str1,*str2;
LIST_ENTRY(str2_list) next;
};
LIST_HEAD(ptr_list_head, ptr_list);
LIST_HEAD(str2_list_head, str2_list);
struct ptr_list *ptrlist_add(struct ptr_list_head *head);
void ptrlist_destroy(struct ptr_list_head *head);
struct str2_list *str2list_add(struct str2_list_head *head);
bool str2list_copy(struct str2_list_head *to, const struct str2_list_head *from);
void str2list_destroy(struct str2_list_head *head);
struct func_list {
char *func;
uint64_t payload_type;
struct packet_range range_in, range_out;
struct ptr_list_head args;
struct str2_list_head args;
LIST_ENTRY(func_list) next;
};
LIST_HEAD(func_list_head, func_list);
struct func_list *funclist_add_tail(struct func_list_head *head, const char *func);
bool funclist_copy(struct func_list_head *to, const struct func_list_head *from);
void funclist_destroy(struct func_list_head *head);
@@ -96,6 +110,7 @@ struct hostlist_item {
LIST_HEAD(hostlist_collection_head, hostlist_item);
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile);
void hostlist_collection_destroy(struct hostlist_collection_head *head);
bool hostlist_collection_copy(struct hostlist_collection_head *to, const struct hostlist_collection_head *from);
struct hostlist_item *hostlist_collection_search(struct hostlist_collection_head *head, const char *filename);
bool hostlist_collection_is_empty(const struct hostlist_collection_head *head);
@@ -158,6 +173,7 @@ struct ipset_item {
};
LIST_HEAD(ipset_collection_head, ipset_item);
struct ipset_item * ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile);
bool ipset_collection_copy(struct ipset_collection_head *to, const struct ipset_collection_head *from);
void ipset_collection_destroy(struct ipset_collection_head *head);
struct ipset_item *ipset_collection_search(struct ipset_collection_head *head, const char *filename);
bool ipset_collection_is_empty(const struct ipset_collection_head *head);

View File

@@ -48,7 +48,7 @@ bool l7_proto_match(t_l7proto l7proto, uint64_t filter_l7)
static const char *l7payload_name[] = {
"all","unknown","empty","known","http_req","http_reply","tls_client_hello","tls_server_hello","quic_initial",
"wireguard_initiation","wireguard_response","wireguard_cookie","wireguard_keepalive","wireguard_data",
"dht","discord_ip_discovery","stun_binding_req",
"dht","discord_ip_discovery","stun",
"xmpp_stream", "xmpp_starttls", "xmpp_proceed", "xmpp_features",
"dns_query", "dns_response",
"mtproto_initial"};
@@ -66,6 +66,35 @@ bool l7_payload_match(t_l7payload l7payload, uint64_t filter_l7p)
{
return filter_l7p==L7P_ALL || (filter_l7p & (1<<l7payload)) || (filter_l7p & (1<<L7P_KNOWN)) && l7payload>L7P_KNOWN && l7payload<L7P_LAST;
}
bool l7_payload_str_list(uint64_t l7p, char *buf, size_t size)
{
char *p;
const char *pstr;
size_t lstr;
t_l7payload pl;
if (!size) return false;
if (l7p==L7P_ALL)
{
if (size<4) return false;
memcpy(buf,"all",4);
return true;
}
for(pl=0, p=buf, *buf=0 ; pl<L7P_LAST ; pl++)
{
if (l7p & (1<<pl))
{
pstr = l7payload_str(pl);
lstr = strlen(pstr);
if (size < ((p!=buf) + lstr + 1)) return false;
if (p!=buf) *p++=','; // not first
memcpy(p,pstr,lstr);
p[lstr]=0;
p+=lstr;
}
}
return true;
}
static const char *posmarker_names[] = {"abs","host","endhost","sld","midsld","endsld","method","extlen","sniext"};
@@ -1380,11 +1409,11 @@ bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len)
!memcmp(data+8,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",64);
// address is not set in request
}
bool IsStunBindingRequest(const uint8_t *data, size_t len)
bool IsStunMessage(const uint8_t *data, size_t len)
{
return len>=20 && // header size
data[0]==0 && data[1]==1 &&
(data[3]&0b11)==0 && // length must be a multiple of 4
(data[0]&0xC0)==0 && // 2 most significant bits must be zeroes
(data[3]&3)==0 && // length must be a multiple of 4
ntohl(*(uint32_t*)(&data[4]))==0x2112A442 && // magic cookie
ntohs(*(uint16_t*)(&data[2]))==len-20;
}

View File

@@ -42,7 +42,7 @@ typedef enum {
L7P_WIREGUARD_DATA,
L7P_DHT,
L7P_DISCORD_IP_DISCOVERY,
L7P_STUN_BINDING_REQ,
L7P_STUN,
L7P_XMPP_STREAM,
L7P_XMPP_STARTTLS,
L7P_XMPP_PROCEED,
@@ -55,6 +55,7 @@ typedef enum {
t_l7payload l7payload_from_name(const char *name);
const char *l7payload_str(t_l7payload l7);
bool l7_payload_match(t_l7payload l7payload, uint64_t filter_l7p);
bool l7_payload_str_list(uint64_t l7p, char *buf, size_t size);
typedef enum {
PM_ABS=0,
@@ -152,7 +153,7 @@ bool IsWireguardKeepalive(const uint8_t *data, size_t len);
bool IsWireguardData(const uint8_t *data, size_t len);
bool IsDht(const uint8_t *data, size_t len);
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len);
bool IsStunBindingRequest(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);
#define QUIC_MAX_CID_LENGTH 20