nfqws: autottl cache, --dup-autottl, --orig-autottl

This commit is contained in:
bol-van 2025-05-03 12:01:49 +03:00
parent 5b625fa709
commit 5cc888cd2c
13 changed files with 501 additions and 111 deletions

View File

@ -482,7 +482,11 @@ nfqws: multiple mods for multiple TLS fakes
init.d: remove 50-discord init.d: remove 50-discord
blockcheck: use tpws --fix-seg on linux for multiple splits blockcheck: use tpws --fix-seg on linux for multiple splits
v70.7 v71
nfqws,tpws: debug tls version, alpn, ech nfqws,tpws: debug tls version, alpn, ech
nfqws: --dpi-desync-fake-tls=! means default tls fake nfqws: --dpi-desync-fake-tls=! means default tls fake
nfqws: --dup*
nfqws: --orig*
nfqws: autottl cache
nfqws: autottl disable path length check

View File

@ -77,7 +77,8 @@ typedef struct
bool req_seq_present,req_seq_finalized,req_seq_abandoned; 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) uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions)
uint8_t incoming_ttl, autottl; uint8_t incoming_ttl, desync_autottl, orig_autottl, dup_autottl;
bool b_autottl_discovered;
bool b_cutoff; // mark for deletion bool b_cutoff; // mark for deletion
bool b_wssize_cutoff, b_desync_cutoff, b_dup_cutoff, b_orig_mod_cutoff; bool b_wssize_cutoff, b_desync_cutoff, b_dup_cutoff, b_orig_mod_cutoff;

View File

@ -1832,17 +1832,15 @@ bool rawsend_queue(struct rawpacket_tailhead *q)
} }
// return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling uint8_t hop_count_guess(uint8_t ttl)
// ttl = TTL of incoming packet
uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
{ {
uint8_t orig, path, fake;
int d;
// 18.65.168.125 ( cloudfront ) 255 // 18.65.168.125 ( cloudfront ) 255
// 157.254.246.178 128 // 157.254.246.178 128
// 1.1.1.1 64 // 1.1.1.1 64
// guess original ttl. consider path lengths less than 32 hops // guess original ttl. consider path lengths less than 32 hops
uint8_t orig;
if (ttl>223) if (ttl>223)
orig=255; orig=255;
else if (ttl<128 && ttl>96) else if (ttl<128 && ttl>96)
@ -1852,15 +1850,22 @@ uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
else else
return 0; return 0;
path = orig - ttl; return orig - ttl;
}
// return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling
uint8_t autottl_eval(uint8_t hop_count, const autottl *attl)
{
uint8_t fake;
int d;
d = (int)path + attl->delta; d = (int)hop_count + attl->delta;
if (d<attl->min) fake=attl->min; if (d<attl->min) fake=attl->min;
else if (d>attl->max) fake=attl->max; else if (d>attl->max) fake=attl->max;
else fake=(uint8_t)d; else fake=(uint8_t)d;
if (attl->delta<0 && fake>=path || attl->delta>=0 && fake<path) // path length check disabled
return 0; // if (attl->delta<0 && fake>=hop_count || attl->delta>=0 && fake<hop_count)
// return 0;
return fake; return fake;
} }

View File

@ -261,13 +261,10 @@ typedef struct
int8_t delta; int8_t delta;
uint8_t min, max; uint8_t min, max;
} autottl; } autottl;
#define AUTOTTL_DEFAULT_DELTA -1
#define AUTOTTL_DEFAULT_MIN 3
#define AUTOTTL_DEFAULT_MAX 20
#define AUTOTTL_ENABLED(a) (!!(a).delta) #define AUTOTTL_ENABLED(a) (!!(a).delta)
#define AUTOTTL_SET_DEFAULT(a) {(a).delta=AUTOTTL_DEFAULT_DELTA; (a).min=AUTOTTL_DEFAULT_MIN; (a).max=AUTOTTL_DEFAULT_MAX;}
uint8_t autottl_guess(uint8_t ttl, const autottl *attl); uint8_t hop_count_guess(uint8_t ttl);
uint8_t autottl_eval(uint8_t hop_count, const autottl *attl);
void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6); void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6);
void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr); void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr);

View File

@ -745,21 +745,57 @@ static size_t pos_normalize(size_t split_pos, size_t reasm_offset, size_t len_pa
return (split_pos>reasm_offset && (split_pos-reasm_offset)<len_payload) ? split_pos-reasm_offset : 0; return (split_pos>reasm_offset && (split_pos-reasm_offset)<len_payload) ? split_pos-reasm_offset : 0;
} }
static void autottl_discover(t_ctrack *ctrack, bool bIpv6) static uint8_t autottl_guess(autottl *attl, uint8_t hop_count, const char *attl_kind)
{ {
if (ctrack && ctrack->incoming_ttl)
{
autottl *attl = bIpv6 ? &ctrack->dp->desync_autottl6 : &ctrack->dp->desync_autottl;
if (AUTOTTL_ENABLED(*attl)) if (AUTOTTL_ENABLED(*attl))
{ {
ctrack->autottl = autottl_guess(ctrack->incoming_ttl, attl); uint8_t autottl = autottl_eval(hop_count, attl);
if (ctrack->autottl) if (autottl)
DLOG("autottl: guessed %u\n",ctrack->autottl); DLOG("%s autottl: guessed %u\n",attl_kind,autottl);
else else
DLOG("autottl: could not guess\n"); DLOG("%s autottl: could not guess\n",attl_kind);
return autottl;
} }
else else
ctrack->autottl = 0; return 0;
}
static void autottl_discover(t_ctrack *ctrack, const struct in_addr *a4, const struct in6_addr *a6, const char *iface)
{
if (ctrack && params.autottl_present && !ctrack->b_autottl_discovered)
{
ip_cache_item *ipc = ipcacheTouch(&params.ipcache,a4,a6,iface);
if (!ipc)
{
DLOG_ERR("ipcache: out of memory\n");
return;
}
if (ctrack->incoming_ttl)
{
uint8_t old_hops = ipc->hops;
ipc->hops = hop_count_guess(ctrack->incoming_ttl);
DLOG("incoming hops guessed %u\n", ipc->hops);
if (old_hops!=ipc->hops)
DLOG("updated autottl cache\n");
}
else if (ipc->hops)
DLOG("using cached hops %u\n", ipc->hops);
else
DLOG("hop count unknown\n");
if (ipc->hops)
{
ctrack->desync_autottl = autottl_guess(a6 ? &ctrack->dp->desync_autottl6 : &ctrack->dp->desync_autottl, ipc->hops, "desync");
ctrack->orig_autottl = autottl_guess(a6 ? &ctrack->dp->orig_autottl6 : &ctrack->dp->orig_autottl, ipc->hops, "orig");
ctrack->dup_autottl = autottl_guess(a6 ? &ctrack->dp->dup_autottl6 : &ctrack->dp->dup_autottl, ipc->hops, "dup");
}
ctrack->b_autottl_discovered = true;
}
}
static void autottl_rediscover(t_ctrack *ctrack, const struct in_addr *a4, const struct in6_addr *a6, const char *iface)
{
if (ctrack)
{
ctrack->b_autottl_discovered = false;
autottl_discover(ctrack,a4,a6,iface);
} }
} }
@ -838,7 +874,7 @@ uint8_t orig_mod(const struct desync_profile *dp, const t_ctrack *ctrack, struct
{ {
uint8_t ttl,ttl_orig; uint8_t ttl,ttl_orig;
ttl = dis->ip6 ? dp->orig_mod_ttl6 : dp->orig_mod_ttl; ttl = (ctrack && ctrack->orig_autottl) ? ctrack->orig_autottl : dis->ip6 ? dp->orig_mod_ttl6 : dp->orig_mod_ttl;
if (ttl && check_orig_mod_interval(dp,ctrack)) if (ttl && check_orig_mod_interval(dp,ctrack))
{ {
ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
@ -893,14 +929,13 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
bool sack,DF; bool sack,DF;
extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst); extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst);
ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6);
if (dp->dup_repeats && check_dup_interval(dp,ctrack)) if (dp->dup_repeats && check_dup_interval(dp,ctrack))
{ {
ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; ttl_fake = (ctrack && ctrack->dup_autottl) ? ctrack->dup_autottl : (dis->ip6 ? (dp->dup_ttl6 ? dp->dup_ttl6 : ttl_orig) : (dp->dup_ttl ? dp->dup_ttl : ttl_orig));
ttl_fake = dis->ip6 ? dp->dup_ttl6 : dp->dup_ttl;
if (!ttl_fake) ttl_fake = ttl_orig;
if (dp->dup_fooling_mode) if (dp->dup_fooling_mode)
{ {
@ -910,20 +945,19 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
sack = tcp_has_sack(dis->tcp); sack = tcp_has_sack(dis->tcp);
nmss = tcp_find_mss(dis->tcp); nmss = tcp_find_mss(dis->tcp);
ip_id = IP4_IP_ID_FIX(dis->ip); ip_id = IP4_IP_ID_FIX(dis->ip);
DF = ip_has_df(dis->ip);
len = sizeof(pkt); len = sizeof(pkt);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
flags_orig, sack, nmss, flags_orig, sack, nmss,
dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), ip_has_df(dis->ip),ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
dp->dup_fooling_mode,dp->dup_badseq_increment,dp->dup_badseq_ack_increment, dp->dup_fooling_mode,dp->dup_badseq_increment,dp->dup_badseq_ack_increment,
dis->data_payload, dis->len_payload, pkt, &len)) dis->data_payload, dis->len_payload, pkt, &len))
{ {
DLOG_ERR("dup: packet reconstruct failed\n"); DLOG_ERR("dup: packet reconstruct failed\n");
return false; return false;
} }
DLOG("sending %u dups with packet reconstruct\n", dp->dup_repeats); DLOG("sending %u dups with packet reconstruct. ttl %u => %u\n", dp->dup_repeats, ttl_orig, ttl_fake);
// send dups // send dups
for (k=0;k<dp->dup_repeats;k++) for (k=0;k<dp->dup_repeats;k++)
@ -941,7 +975,7 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
DLOG("NOT sending original because of dup_replace\n"); DLOG("NOT sending original because of dup_replace\n");
else else
{ {
DLOG("sending original\n", dp->dup_repeats); DLOG("sending original ttl %u\n", ttl_orig);
if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt))
return false; return false;
} }
@ -949,7 +983,7 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
} }
if (bForceSend) if (bForceSend)
{ {
DLOG("sending original\n", dp->dup_repeats); DLOG("sending original ttl %u\n", ttl_orig);
if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt))
return false; return false;
return true; return true;
@ -968,18 +1002,15 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
uint16_t ip_id; uint16_t ip_id;
struct sockaddr_storage src, dst; struct sockaddr_storage src, dst;
uint8_t ttl_orig,ttl_fake; uint8_t ttl_orig,ttl_fake;
bool DF;
extract_endpoints(dis->ip, dis->ip6, NULL, dis->udp, &src, &dst); extract_endpoints(dis->ip, dis->ip6, NULL, dis->udp, &src, &dst);
ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6); verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
if (dp->dup_repeats && check_dup_interval(dp,ctrack)) if (dp->dup_repeats && check_dup_interval(dp,ctrack))
{ {
ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; ttl_fake = (ctrack && ctrack->dup_autottl) ? ctrack->dup_autottl : (dis->ip6 ? (dp->dup_ttl6 ? dp->dup_ttl6 : ttl_orig) : (dp->dup_ttl ? dp->dup_ttl : ttl_orig));
ttl_fake = dis->ip6 ? dp->dup_ttl6 : dp->dup_ttl;
if (!ttl_fake) ttl_fake = ttl_orig;
DF = ip_has_df(dis->ip);
if (dp->dup_fooling_mode) if (dp->dup_fooling_mode)
{ {
@ -987,7 +1018,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
len = sizeof(pkt); len = sizeof(pkt);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
DF,ttl_fake, IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), ip_has_df(dis->ip),ttl_fake, IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
dp->dup_fooling_mode, NULL, 0, 0, dp->dup_fooling_mode, NULL, 0, 0,
dis->data_payload, dis->len_payload, pkt, &len)) dis->data_payload, dis->len_payload, pkt, &len))
{ {
@ -995,7 +1026,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
return false; return false;
} }
DLOG("sending %u dups with packet reconstruct\n", dp->dup_repeats); DLOG("sending %u dups with packet reconstruct. ttl %u => %u\n", dp->dup_repeats, ttl_orig, ttl_fake);
// send dups // send dups
for (k=0;k<dp->dup_repeats;k++) for (k=0;k<dp->dup_repeats;k++)
@ -1013,7 +1044,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
DLOG("NOT sending original because of dup_replace\n"); DLOG("NOT sending original because of dup_replace\n");
else else
{ {
DLOG("sending original\n", dp->dup_repeats); DLOG("sending original ttl %u\n", ttl_orig);
if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt))
return false; return false;
} }
@ -1021,7 +1052,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
} }
if (bForceSend) if (bForceSend)
{ {
DLOG("sending original\n", dp->dup_repeats); DLOG("sending original ttl %u\n", ttl_orig);
if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt))
return false; return false;
return true; return true;
@ -1030,7 +1061,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c
return false; return false;
} }
static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, struct dissect *dis) static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, struct dissect *dis)
{ {
uint8_t verdict=VERDICT_PASS; uint8_t verdict=VERDICT_PASS;
@ -1121,10 +1152,10 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
if (!ctrack->incoming_ttl) if (!ctrack->incoming_ttl)
{ {
DLOG("incoming TTL %u\n",ttl_orig);
ctrack->incoming_ttl = ttl_orig; ctrack->incoming_ttl = ttl_orig;
DLOG("incoming TTL %u\n",ttl_orig);
autottl_rediscover(ctrack,dis->ip ? &dis->ip->ip_src : NULL,dis->ip6 ? &dis->ip6->ip6_src : NULL , ifin);
} }
if (!ctrack->autottl) autottl_discover(ctrack,!!dis->ip6);
} }
// process reply packets for auto hostlist mode // process reply packets for auto hostlist mode
@ -1178,6 +1209,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
return verdict; // nothing to do. do not waste cpu return verdict; // nothing to do. do not waste cpu
} }
autottl_discover(ctrack,dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , ifout);
if (orig_mod(dp,ctrack,dis)) // ttl can change ! if (orig_mod(dp,ctrack,dis)) // ttl can change !
verdict = VERDICT_MODIFY; verdict = VERDICT_MODIFY;
@ -1207,7 +1240,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
} // !replay } // !replay
ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); ttl_fake = (ctrack_replay && ctrack_replay->desync_autottl) ? ctrack_replay->desync_autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig));
flags_orig = *((uint8_t*)dis->tcp+13); flags_orig = *((uint8_t*)dis->tcp+13);
scale_factor = tcp_find_scale_factor(dis->tcp); scale_factor = tcp_find_scale_factor(dis->tcp);
timestamps = tcp_find_timestamps(dis->tcp); timestamps = tcp_find_timestamps(dis->tcp);
@ -1368,7 +1401,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (!ReasmIsEmpty(&ctrack->reasm_orig)) if (!ReasmIsEmpty(&ctrack->reasm_orig))
{ {
verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6);
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
{ {
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed)); DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
} }
@ -1455,10 +1488,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (dp!=dp_prev) if (dp!=dp_prev)
{ {
DLOG("desync profile changed by revealed l7 protocol or hostname !\n"); DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
// rediscover autottl autottl_rediscover(ctrack_replay,dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , ifout);
autottl_discover(ctrack_replay,!!dis->ip6);
// re-evaluate start/cutoff limiters // re-evaluate start/cutoff limiters
if (!replay) if (replay)
{
if (orig_mod(dp,ctrack_replay,dis)) // ttl can change !
verdict = VERDICT_MODIFY;
}
else
{ {
maybe_cutoff(ctrack, IPPROTO_TCP); maybe_cutoff(ctrack, IPPROTO_TCP);
if (orig_mod(dp,ctrack,dis)) // ttl can change ! if (orig_mod(dp,ctrack,dis)) // ttl can change !
@ -1509,7 +1546,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("applying tampering to unknown protocol\n"); DLOG("applying tampering to unknown protocol\n");
} }
ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); ttl_fake = (ctrack_replay && ctrack_replay->desync_autottl) ? ctrack_replay->desync_autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig));
if ((l7proto == HTTP) && (dp->hostcase || dp->hostnospace || dp->domcase || dp->methodeol) && HttpFindHost(&phost,dis->data_payload,dis->len_payload)) if ((l7proto == HTTP) && (dp->hostcase || dp->hostnospace || dp->domcase || dp->methodeol) && HttpFindHost(&phost,dis->data_payload,dis->len_payload))
{ {
if (dp->hostcase) if (dp->hostcase)
@ -2207,7 +2244,7 @@ static bool quic_reasm_cancel(t_ctrack *ctrack, const char *reason)
} }
} }
static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, struct dissect *dis) static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, struct dissect *dis)
{ {
uint8_t verdict=VERDICT_PASS; uint8_t verdict=VERDICT_PASS;
@ -2294,12 +2331,14 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{ {
DLOG("incoming TTL %u\n",ttl_orig); DLOG("incoming TTL %u\n",ttl_orig);
ctrack->incoming_ttl = ttl_orig; ctrack->incoming_ttl = ttl_orig;
autottl_rediscover(ctrack,dis->ip ? &dis->ip->ip_src : NULL,dis->ip6 ? &dis->ip6->ip6_src : NULL , ifin);
} }
if (!ctrack->autottl) autottl_discover(ctrack,!!dis->ip6);
} }
return verdict; // nothing to do. do not waste cpu return verdict; // nothing to do. do not waste cpu
} }
autottl_discover(ctrack,dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , ifout);
if (orig_mod(dp,ctrack,dis)) // ttl can change ! if (orig_mod(dp,ctrack,dis)) // ttl can change !
verdict = VERDICT_MODIFY; verdict = VERDICT_MODIFY;
@ -2384,7 +2423,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (!ReasmIsEmpty(&ctrack->reasm_orig)) if (!ReasmIsEmpty(&ctrack->reasm_orig))
{ {
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6); verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
{ {
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed)); DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
} }
@ -2433,7 +2472,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
} }
} }
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6); verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
{ {
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed)); DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
} }
@ -2554,10 +2593,14 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (dp!=dp_prev) if (dp!=dp_prev)
{ {
DLOG("desync profile changed by revealed l7 protocol or hostname !\n"); DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
// rediscover autottl autottl_rediscover(ctrack_replay,dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , ifout);
autottl_discover(ctrack_replay,!!dis->ip6);
// re-evaluate start/cutoff limiters // re-evaluate start/cutoff limiters
if (!replay) if (replay)
{
if (orig_mod(dp,ctrack_replay,dis)) // ttl can change !
verdict = VERDICT_MODIFY;
}
else
{ {
maybe_cutoff(ctrack, IPPROTO_UDP); maybe_cutoff(ctrack, IPPROTO_UDP);
if (orig_mod(dp,ctrack,dis)) // ttl can change ! if (orig_mod(dp,ctrack,dis)) // ttl can change !
@ -2619,7 +2662,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
break; break;
} }
ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); ttl_fake = (ctrack_replay && ctrack_replay->desync_autottl) ? ctrack_replay->desync_autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig));
uint32_t fooling_orig = FOOL_NONE; uint32_t fooling_orig = FOOL_NONE;
@ -2832,7 +2875,7 @@ static void packet_debug(bool replay, const struct dissect *dis)
} }
static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, uint8_t *data_pkt, size_t *len_pkt)
{ {
struct dissect dis; struct dissect dis;
uint8_t verdict = VERDICT_PASS; uint8_t verdict = VERDICT_PASS;
@ -2846,14 +2889,14 @@ static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t
case IPPROTO_TCP: case IPPROTO_TCP:
if (dis.tcp) if (dis.tcp)
{ {
verdict = dpi_desync_tcp_packet_play(replay, reasm_offset, fwmark, ifout, &dis); verdict = dpi_desync_tcp_packet_play(replay, reasm_offset, fwmark, ifin, ifout, &dis);
verdict_tcp_csum_fix(verdict, dis.tcp, dis.transport_len, dis.ip, dis.ip6); verdict_tcp_csum_fix(verdict, dis.tcp, dis.transport_len, dis.ip, dis.ip6);
} }
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
if (dis.udp) if (dis.udp)
{ {
verdict = dpi_desync_udp_packet_play(replay, reasm_offset, fwmark, ifout, &dis); verdict = dpi_desync_udp_packet_play(replay, reasm_offset, fwmark, ifin, ifout, &dis);
verdict_udp_csum_fix(verdict, dis.udp, dis.transport_len, dis.ip, dis.ip6); verdict_udp_csum_fix(verdict, dis.udp, dis.transport_len, dis.ip, dis.ip6);
} }
break; break;
@ -2862,9 +2905,10 @@ static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t
} }
return verdict; return verdict;
} }
uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout, uint8_t *data_pkt, size_t *len_pkt)
{ {
return dpi_desync_packet_play(false, 0, fwmark, ifout, data_pkt, len_pkt); ipcachePurgeRateLimited(&params.ipcache, params.autottl_cache_lifetime);
return dpi_desync_packet_play(false, 0, fwmark, ifin, ifout, data_pkt, len_pkt);
} }
@ -2878,7 +2922,7 @@ static bool replay_queue(struct rawpacket_tailhead *q)
for (i=1,offset=0 ; (rp=rawpacket_dequeue(q)) ; offset+=rp->len_payload, rawpacket_free(rp), i++) for (i=1,offset=0 ; (rp=rawpacket_dequeue(q)) ; offset+=rp->len_payload, rawpacket_free(rp), i++)
{ {
DLOG("REPLAYING delayed packet #%u offset %zu\n",i,offset); DLOG("REPLAYING delayed packet #%u offset %zu\n",i,offset);
uint8_t verdict = dpi_desync_packet_play(true, offset, rp->fwmark, rp->ifout, rp->packet, &rp->len); uint8_t verdict = dpi_desync_packet_play(true, offset, rp->fwmark, rp->ifin, rp->ifout, rp->packet, &rp->len);
switch(verdict & VERDICT_MASK) switch(verdict & VERDICT_MASK)
{ {
case VERDICT_MODIFY: case VERDICT_MODIFY:

View File

@ -52,4 +52,4 @@ bool desync_valid_second_stage(enum dpi_desync_mode mode);
bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode); bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode);
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode); bool desync_valid_second_stage_udp(enum dpi_desync_mode mode);
uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt); uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout, uint8_t *data_pkt, size_t *len_pkt);

View File

@ -9,6 +9,8 @@
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#define UNARY_PLUS(v) (v>0 ? "+" : "")
// this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes. // this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes.
typedef union typedef union
{ {

View File

@ -99,7 +99,11 @@ static void onusr2(int sig)
printf("\nDESYNC PROFILE %d\n",dpl->dp.n); printf("\nDESYNC PROFILE %d\n",dpl->dp.n);
HostFailPoolDump(dpl->dp.hostlist_auto_fail_counters); HostFailPoolDump(dpl->dp.hostlist_auto_fail_counters);
} }
if (params.autottl_present)
{
printf("\nAUTOTTL IP CACHE\n");
ipcachePrint(&params.ipcache);
}
printf("\n"); printf("\n");
} }
@ -111,7 +115,7 @@ static void pre_desync(void)
} }
static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) static uint8_t processPacketData(uint32_t *mark, const char *ifin, const char *ifout, uint8_t *data_pkt, size_t *len_pkt)
{ {
#ifdef __linux__ #ifdef __linux__
if (*mark & params.desync_fwmark) if (*mark & params.desync_fwmark)
@ -120,7 +124,7 @@ static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *dat
return VERDICT_PASS; return VERDICT_PASS;
} }
#endif #endif
return dpi_desync_packet(*mark, ifout, data_pkt, len_pkt); return dpi_desync_packet(*mark, ifin, ifout, data_pkt, len_pkt);
} }
@ -154,8 +158,8 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da
size_t len; size_t len;
struct nfqnl_msg_packet_hdr *ph; struct nfqnl_msg_packet_hdr *ph;
uint8_t *data; uint8_t *data;
uint32_t ifidx; uint32_t ifidx_out, ifidx_in;
char ifout[IFNAMSIZ+1]; char ifout[IFNAMSIZ], ifin[IFNAMSIZ];
ph = nfq_get_msg_packet_hdr(nfa); ph = nfq_get_msg_packet_hdr(nfa);
id = ph ? ntohl(ph->packet_id) : 0; id = ph ? ntohl(ph->packet_id) : 0;
@ -163,27 +167,20 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da
uint32_t mark = nfq_get_nfmark(nfa); uint32_t mark = nfq_get_nfmark(nfa);
ilen = nfq_get_payload(nfa, &data); ilen = nfq_get_payload(nfa, &data);
ifidx_out = nfq_get_outdev(nfa);
*ifout=0; *ifout=0;
if (params.bind_fix4 || params.bind_fix6) if (ifidx_out) if_indextoname(ifidx_out,ifout);
{
char ifin[IFNAMSIZ+1];
uint32_t ifidx_in;
ifidx = nfq_get_outdev(nfa);
if (ifidx) if_indextoname(ifidx,ifout);
*ifin=0;
ifidx_in = nfq_get_indev(nfa); ifidx_in = nfq_get_indev(nfa);
*ifin=0;
if (ifidx_in) if_indextoname(ifidx_in,ifin); if (ifidx_in) if_indextoname(ifidx_in,ifin);
DLOG("packet: id=%d len=%d mark=%08X ifin=%s(%u) ifout=%s(%u)\n", id, ilen, mark, ifin, ifidx_in, ifout, ifidx); DLOG("packet: id=%d len=%d mark=%08X ifin=%s(%u) ifout=%s(%u)\n", id, ilen, mark, ifin, ifidx_in, ifout, ifidx_out);
}
else
// save some syscalls
DLOG("packet: id=%d len=%d mark=%08X\n", id, ilen, mark);
if (ilen >= 0) if (ilen >= 0)
{ {
len = ilen; len = ilen;
uint8_t verdict = processPacketData(&mark, ifout, data, &len); uint8_t verdict = processPacketData(&mark, ifin, ifout, data, &len);
switch(verdict & VERDICT_MASK) switch(verdict & VERDICT_MASK)
{ {
case VERDICT_MODIFY: case VERDICT_MODIFY:
@ -437,7 +434,7 @@ static int dvt_main(void)
ReloadCheck(); ReloadCheck();
DLOG("packet: id=%u len=%zu\n", id, len); DLOG("packet: id=%u len=%zu\n", id, len);
verdict = processPacketData(&mark, NULL, buf, &len); verdict = processPacketData(&mark, NULL, NULL, buf, &len);
switch (verdict & VERDICT_MASK) switch (verdict & VERDICT_MASK)
{ {
case VERDICT_PASS: case VERDICT_PASS:
@ -484,7 +481,7 @@ static int win_main(const char *windivert_filter)
uint8_t packet[16384]; uint8_t packet[16384];
uint32_t mark; uint32_t mark;
WINDIVERT_ADDRESS wa; WINDIVERT_ADDRESS wa;
char ifout[22]; char ifname[IFNAMSIZ];
pre_desync(); pre_desync();
@ -550,8 +547,8 @@ static int win_main(const char *windivert_filter)
ReloadCheck(); ReloadCheck();
*ifout=0; *ifname=0;
if (wa.Outbound) snprintf(ifout,sizeof(ifout),"%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx); snprintf(ifname,sizeof(ifname),"%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx);
DLOG("packet: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx); DLOG("packet: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx);
if (wa.Impostor) if (wa.Impostor)
{ {
@ -567,7 +564,7 @@ static int win_main(const char *windivert_filter)
{ {
mark=0; mark=0;
// pseudo interface id IfIdx.SubIfIdx // pseudo interface id IfIdx.SubIfIdx
verdict = processPacketData(&mark, ifout, packet, &len); verdict = processPacketData(&mark, ifname, ifname, packet, &len);
} }
switch (verdict & VERDICT_MASK) switch (verdict & VERDICT_MASK)
{ {
@ -690,11 +687,14 @@ static void load_file_or_exit(const char *filename, void *buf, size_t *size)
} }
} }
static bool parse_autottl(const char *s, autottl *t) static bool parse_autottl(const char *s, autottl *t, int8_t def_delta, uint8_t def_min, uint8_t def_max)
{ {
bool neg=true; bool neg=true;
unsigned int delta,min,max; unsigned int delta,min,max;
AUTOTTL_SET_DEFAULT(*t);
t->delta = def_delta;
t->min = def_min;
t->max = def_max;
if (s) if (s)
{ {
max = t->max; max = t->max;
@ -1416,6 +1416,7 @@ static void exithelp(void)
" --bind-fix6\t\t\t\t\t; apply outgoing interface selection fix for generated ipv6 packets\n" " --bind-fix6\t\t\t\t\t; apply outgoing interface selection fix for generated ipv6 packets\n"
#endif #endif
" --ctrack-timeouts=S:E:F[:U]\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n" " --ctrack-timeouts=S:E:F[:U]\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n"
" --autottl-cache-lifetime=<int>\t\t\t; time in seconds to keep cached hop count (default %u)\n"
#ifdef __CYGWIN__ #ifdef __CYGWIN__
"\nWINDIVERT FILTER:\n" "\nWINDIVERT FILTER:\n"
" --wf-iface=<int>[.<int>]\t\t\t; numeric network interface and subinterface indexes\n" " --wf-iface=<int>[.<int>]\t\t\t; numeric network interface and subinterface indexes\n"
@ -1456,12 +1457,16 @@ static void exithelp(void)
" --wssize-cutoff=[n|d|s]N\t\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" " --wssize-cutoff=[n|d|s]N\t\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --orig-ttl=<int>\t\t\t\t; set TTL for original packets\n" " --orig-ttl=<int>\t\t\t\t; set TTL for original packets\n"
" --orig-ttl6=<int>\t\t\t\t; set ipv6 hop limit for original packets. by default ttl value is used\n" " --orig-ttl6=<int>\t\t\t\t; set ipv6 hop limit for original packets. by default ttl value is used\n"
" --orig-autottl=[<delta>[:<min>[-<max>]]]\t; auto ttl mode for both ipv4 and ipv6. default: +%d:%u-%u\n"
" --orig-autottl6=[<delta>[:<min>[-<max>]]]\t; overrides --orig-autottl for ipv6 only\n"
" --orig-mod-start=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" " --orig-mod-start=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n"
" --orig-mod-cutoff=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" " --orig-mod-cutoff=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --dup=<int>\t\t\t\t\t; duplicate original packets. send N dups before original.\n" " --dup=<int>\t\t\t\t\t; duplicate original packets. send N dups before original.\n"
" --dup-replace=[0|1]\t\t\t\t; 1 or no argument means do not send original, only dups\n" " --dup-replace=[0|1]\t\t\t\t; 1 or no argument means do not send original, only dups\n"
" --dup-ttl=<int>\t\t\t\t; set TTL for dups\n" " --dup-ttl=<int>\t\t\t\t; set TTL for dups\n"
" --dup-ttl6=<int>\t\t\t\t; set ipv6 hop limit for dups. by default ttl value is used\n" " --dup-ttl6=<int>\t\t\t\t; set ipv6 hop limit for dups. by default ttl value is used\n"
" --dup-autottl=[<delta>[:<min>[-<max>]]]\t; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n"
" --dup-autottl6=[<delta>[:<min>[-<max>]]]\t; overrides --dup-autottl for ipv6 only\n"
" --dup-fooling=<mode>[,<mode>]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\n" " --dup-fooling=<mode>[,<mode>]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\n"
" --dup-badseq-increment=<int|0xHEX>\t\t; badseq fooling seq signed increment for dup. default %d\n" " --dup-badseq-increment=<int|0xHEX>\t\t; badseq fooling seq signed increment for dup. default %d\n"
" --dup-badack-increment=<int|0xHEX>\t\t; badseq fooling ackseq signed increment for dup. default %d\n" " --dup-badack-increment=<int|0xHEX>\t\t; badseq fooling ackseq signed increment for dup. default %d\n"
@ -1515,12 +1520,15 @@ static void exithelp(void)
" --dpi-desync-start=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" " --dpi-desync-start=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n"
" --dpi-desync-cutoff=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n", " --dpi-desync-cutoff=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n",
CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP, CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP,
AUTOTTL_CACHE_LIFETIME,
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT,
AUTOTTL_DEFAULT_ORIG_DELTA,AUTOTTL_DEFAULT_ORIG_MIN,AUTOTTL_DEFAULT_ORIG_MAX,
AUTOTTL_DEFAULT_DUP_DELTA,AUTOTTL_DEFAULT_DUP_MIN,AUTOTTL_DEFAULT_DUP_MAX,
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
#if defined(__linux__) || defined(SO_USER_COOKIE) #if defined(__linux__) || defined(SO_USER_COOKIE)
DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT, DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT,
#endif #endif
AUTOTTL_DEFAULT_DELTA,AUTOTTL_DEFAULT_MIN,AUTOTTL_DEFAULT_MAX, AUTOTTL_DEFAULT_DESYNC_DELTA,AUTOTTL_DEFAULT_DESYNC_MIN,AUTOTTL_DEFAULT_DESYNC_MAX,
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT,
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT,
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
@ -1610,6 +1618,7 @@ enum opt_indices {
IDX_WSSIZE, IDX_WSSIZE,
IDX_WSSIZE_CUTOFF, IDX_WSSIZE_CUTOFF,
IDX_CTRACK_TIMEOUTS, IDX_CTRACK_TIMEOUTS,
IDX_AUTOTTL_CACHE_LIFETIME,
IDX_HOSTCASE, IDX_HOSTCASE,
IDX_HOSTSPELL, IDX_HOSTSPELL,
IDX_HOSTNOSPACE, IDX_HOSTNOSPACE,
@ -1624,6 +1633,8 @@ enum opt_indices {
IDX_DUP, IDX_DUP,
IDX_DUP_TTL, IDX_DUP_TTL,
IDX_DUP_TTL6, IDX_DUP_TTL6,
IDX_DUP_AUTOTTL,
IDX_DUP_AUTOTTL6,
IDX_DUP_FOOLING, IDX_DUP_FOOLING,
IDX_DUP_BADSEQ_INCREMENT, IDX_DUP_BADSEQ_INCREMENT,
IDX_DUP_BADACK_INCREMENT, IDX_DUP_BADACK_INCREMENT,
@ -1632,6 +1643,8 @@ enum opt_indices {
IDX_DUP_CUTOFF, IDX_DUP_CUTOFF,
IDX_ORIG_TTL, IDX_ORIG_TTL,
IDX_ORIG_TTL6, IDX_ORIG_TTL6,
IDX_ORIG_AUTOTTL,
IDX_ORIG_AUTOTTL6,
IDX_ORIG_MOD_START, IDX_ORIG_MOD_START,
IDX_ORIG_MOD_CUTOFF, IDX_ORIG_MOD_CUTOFF,
IDX_DPI_DESYNC_TTL, IDX_DPI_DESYNC_TTL,
@ -1723,6 +1736,7 @@ static const struct option long_options[] = {
[IDX_WSSIZE] = {"wssize", required_argument, 0, 0}, [IDX_WSSIZE] = {"wssize", required_argument, 0, 0},
[IDX_WSSIZE_CUTOFF] = {"wssize-cutoff", required_argument, 0, 0}, [IDX_WSSIZE_CUTOFF] = {"wssize-cutoff", required_argument, 0, 0},
[IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_argument, 0, 0}, [IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_argument, 0, 0},
[IDX_AUTOTTL_CACHE_LIFETIME] = {"autottl-cache-lifetime", required_argument, 0, 0},
[IDX_HOSTCASE] = {"hostcase", no_argument, 0, 0}, [IDX_HOSTCASE] = {"hostcase", no_argument, 0, 0},
[IDX_HOSTSPELL] = {"hostspell", required_argument, 0, 0}, [IDX_HOSTSPELL] = {"hostspell", required_argument, 0, 0},
[IDX_HOSTNOSPACE] = {"hostnospace", no_argument, 0, 0}, [IDX_HOSTNOSPACE] = {"hostnospace", no_argument, 0, 0},
@ -1737,6 +1751,8 @@ static const struct option long_options[] = {
[IDX_DUP] = {"dup", required_argument, 0, 0}, [IDX_DUP] = {"dup", required_argument, 0, 0},
[IDX_DUP_TTL] = {"dup-ttl", required_argument, 0, 0}, [IDX_DUP_TTL] = {"dup-ttl", required_argument, 0, 0},
[IDX_DUP_TTL6] = {"dup-ttl6", required_argument, 0, 0}, [IDX_DUP_TTL6] = {"dup-ttl6", required_argument, 0, 0},
[IDX_DUP_AUTOTTL] = {"dup-autottl", optional_argument, 0, 0},
[IDX_DUP_AUTOTTL6] = {"dup-autottl6", optional_argument, 0, 0},
[IDX_DUP_FOOLING] = {"dup-fooling", required_argument, 0, 0}, [IDX_DUP_FOOLING] = {"dup-fooling", required_argument, 0, 0},
[IDX_DUP_BADSEQ_INCREMENT] = {"dup-badseq-increment", required_argument, 0, 0}, [IDX_DUP_BADSEQ_INCREMENT] = {"dup-badseq-increment", required_argument, 0, 0},
[IDX_DUP_BADACK_INCREMENT] = {"dup-badack-increment", required_argument, 0, 0}, [IDX_DUP_BADACK_INCREMENT] = {"dup-badack-increment", required_argument, 0, 0},
@ -1745,6 +1761,8 @@ static const struct option long_options[] = {
[IDX_DUP_CUTOFF] = {"dup-cutoff", required_argument, 0, 0}, [IDX_DUP_CUTOFF] = {"dup-cutoff", required_argument, 0, 0},
[IDX_ORIG_TTL] = {"orig-ttl", required_argument, 0, 0}, [IDX_ORIG_TTL] = {"orig-ttl", required_argument, 0, 0},
[IDX_ORIG_TTL6] = {"orig-ttl6", required_argument, 0, 0}, [IDX_ORIG_TTL6] = {"orig-ttl6", required_argument, 0, 0},
[IDX_ORIG_AUTOTTL] = {"orig-autottl", optional_argument, 0, 0},
[IDX_ORIG_AUTOTTL6] = {"orig-autottl6", optional_argument, 0, 0},
[IDX_ORIG_MOD_START] = {"orig-mod-start", required_argument, 0, 0}, [IDX_ORIG_MOD_START] = {"orig-mod-start", required_argument, 0, 0},
[IDX_ORIG_MOD_CUTOFF] = {"orig-mod-cutoff", required_argument, 0, 0}, [IDX_ORIG_MOD_CUTOFF] = {"orig-mod-cutoff", required_argument, 0, 0},
[IDX_DPI_DESYNC_TTL] = {"dpi-desync-ttl", required_argument, 0, 0}, [IDX_DPI_DESYNC_TTL] = {"dpi-desync-ttl", required_argument, 0, 0},
@ -1872,6 +1890,7 @@ int main(int argc, char **argv)
params.ctrack_t_est = CTRACK_T_EST; params.ctrack_t_est = CTRACK_T_EST;
params.ctrack_t_fin = CTRACK_T_FIN; params.ctrack_t_fin = CTRACK_T_FIN;
params.ctrack_t_udp = CTRACK_T_UDP; params.ctrack_t_udp = CTRACK_T_UDP;
params.autottl_cache_lifetime = AUTOTTL_CACHE_LIFETIME;
LIST_INIT(&params.hostlists); LIST_INIT(&params.hostlists);
LIST_INIT(&params.ipsets); LIST_INIT(&params.ipsets);
@ -2025,6 +2044,13 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case IDX_AUTOTTL_CACHE_LIFETIME:
if (sscanf(optarg, "%u", &params.autottl_cache_lifetime)!=1)
{
DLOG_ERR("invalid autottl-cache-lifetime value\n");
exit_clean(1);
}
break;
case IDX_HOSTCASE: case IDX_HOSTCASE:
dp->hostcase = true; dp->hostcase = true;
break; break;
@ -2130,6 +2156,22 @@ int main(int argc, char **argv)
case IDX_DUP_TTL6: case IDX_DUP_TTL6:
dp->dup_ttl6 = (uint8_t)atoi(optarg); dp->dup_ttl6 = (uint8_t)atoi(optarg);
break; break;
case IDX_DUP_AUTOTTL:
if (!parse_autottl(optarg, &dp->dup_autottl, AUTOTTL_DEFAULT_DUP_DELTA, AUTOTTL_DEFAULT_DUP_MIN, AUTOTTL_DEFAULT_DUP_MAX))
{
DLOG_ERR("dup-autottl value error\n");
exit_clean(1);
}
params.autottl_present=true;
break;
case IDX_DUP_AUTOTTL6:
if (!parse_autottl(optarg, &dp->dup_autottl6, AUTOTTL_DEFAULT_DUP_DELTA, AUTOTTL_DEFAULT_DUP_MIN, AUTOTTL_DEFAULT_DUP_MAX))
{
DLOG_ERR("dup-autottl6 value error\n");
exit_clean(1);
}
params.autottl_present=true;
break;
case IDX_DUP_REPLACE: case IDX_DUP_REPLACE:
dp->dup_replace = optarg ? !!atoi(optarg) : true; dp->dup_replace = optarg ? !!atoi(optarg) : true;
break; break;
@ -2175,6 +2217,22 @@ int main(int argc, char **argv)
case IDX_ORIG_TTL6: case IDX_ORIG_TTL6:
dp->orig_mod_ttl6 = (uint8_t)atoi(optarg); dp->orig_mod_ttl6 = (uint8_t)atoi(optarg);
break; break;
case IDX_ORIG_AUTOTTL:
if (!parse_autottl(optarg, &dp->orig_autottl, AUTOTTL_DEFAULT_ORIG_DELTA, AUTOTTL_DEFAULT_ORIG_MIN, AUTOTTL_DEFAULT_ORIG_MAX))
{
DLOG_ERR("orig-autottl value error\n");
exit_clean(1);
}
params.autottl_present=true;
break;
case IDX_ORIG_AUTOTTL6:
if (!parse_autottl(optarg, &dp->orig_autottl6, AUTOTTL_DEFAULT_ORIG_DELTA, AUTOTTL_DEFAULT_ORIG_MIN, AUTOTTL_DEFAULT_ORIG_MAX))
{
DLOG_ERR("orig-autottl6 value error\n");
exit_clean(1);
}
params.autottl_present=true;
break;
case IDX_ORIG_MOD_CUTOFF: case IDX_ORIG_MOD_CUTOFF:
if (!parse_cutoff(optarg, &dp->orig_mod_cutoff, &dp->orig_mod_cutoff_mode)) if (!parse_cutoff(optarg, &dp->orig_mod_cutoff, &dp->orig_mod_cutoff_mode))
{ {
@ -2197,18 +2255,20 @@ int main(int argc, char **argv)
dp->desync_ttl6 = (uint8_t)atoi(optarg); dp->desync_ttl6 = (uint8_t)atoi(optarg);
break; break;
case IDX_DPI_DESYNC_AUTOTTL: case IDX_DPI_DESYNC_AUTOTTL:
if (!parse_autottl(optarg, &dp->desync_autottl)) if (!parse_autottl(optarg, &dp->desync_autottl, AUTOTTL_DEFAULT_DESYNC_DELTA, AUTOTTL_DEFAULT_DESYNC_MIN, AUTOTTL_DEFAULT_DESYNC_MAX))
{ {
DLOG_ERR("dpi-desync-autottl value error\n"); DLOG_ERR("dpi-desync-autottl value error\n");
exit_clean(1); exit_clean(1);
} }
params.autottl_present=true;
break; break;
case IDX_DPI_DESYNC_AUTOTTL6: case IDX_DPI_DESYNC_AUTOTTL6:
if (!parse_autottl(optarg, &dp->desync_autottl6)) if (!parse_autottl(optarg, &dp->desync_autottl6, AUTOTTL_DEFAULT_DESYNC_DELTA, AUTOTTL_DEFAULT_DESYNC_MIN, AUTOTTL_DEFAULT_DESYNC_MAX))
{ {
DLOG_ERR("dpi-desync-autottl6 value error\n"); DLOG_ERR("dpi-desync-autottl6 value error\n");
exit_clean(1); exit_clean(1);
} }
params.autottl_present=true;
break; break;
case IDX_DPI_DESYNC_FOOLING: case IDX_DPI_DESYNC_FOOLING:
if (!parse_fooling(optarg,&dp->desync_fooling_mode)) if (!parse_fooling(optarg,&dp->desync_fooling_mode))
@ -2789,10 +2849,20 @@ int main(int argc, char **argv)
if (dp->dup_ttl6 == 0xFF) dp->dup_ttl6=dp->dup_ttl; if (dp->dup_ttl6 == 0xFF) dp->dup_ttl6=dp->dup_ttl;
if (dp->orig_mod_ttl6 == 0xFF) dp->orig_mod_ttl6=dp->orig_mod_ttl; if (dp->orig_mod_ttl6 == 0xFF) dp->orig_mod_ttl6=dp->orig_mod_ttl;
if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl; if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl;
if (!AUTOTTL_ENABLED(dp->orig_autottl6)) dp->orig_autottl6 = dp->orig_autottl;
if (!AUTOTTL_ENABLED(dp->dup_autottl6)) dp->dup_autottl6 = dp->dup_autottl;
if (AUTOTTL_ENABLED(dp->desync_autottl)) if (AUTOTTL_ENABLED(dp->desync_autottl))
DLOG("profile %d autottl ipv4 %d:%u-%u\n",dp->n,dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max); DLOG("profile %d desync autottl ipv4 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->desync_autottl.delta),dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max);
if (AUTOTTL_ENABLED(dp->desync_autottl6)) if (AUTOTTL_ENABLED(dp->desync_autottl6))
DLOG("profile %d autottl ipv6 %d:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max); DLOG("profile %d desync autottl ipv6 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->desync_autottl6.delta),dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max);
if (AUTOTTL_ENABLED(dp->orig_autottl))
DLOG("profile %d orig autottl ipv4 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->orig_autottl.delta),dp->orig_autottl.delta,dp->orig_autottl.min,dp->orig_autottl.max);
if (AUTOTTL_ENABLED(dp->orig_autottl6))
DLOG("profile %d orig autottl ipv6 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->orig_autottl6.delta),dp->orig_autottl6.delta,dp->orig_autottl6.min,dp->orig_autottl6.max);
if (AUTOTTL_ENABLED(dp->dup_autottl))
DLOG("profile %d dup autottl ipv4 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->dup_autottl.delta),dp->dup_autottl.delta,dp->dup_autottl.min,dp->dup_autottl.max);
if (AUTOTTL_ENABLED(dp->dup_autottl6))
DLOG("profile %d dup autottl ipv6 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->dup_autottl6.delta),dp->dup_autottl6.delta,dp->dup_autottl6.min,dp->dup_autottl6.max);
split_compat(dp); split_compat(dp);
if (!dp_fake_defaults(dp)) if (!dp_fake_defaults(dp))
{ {

View File

@ -1,5 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include "packet_queue.h" #include "packet_queue.h"
@ -25,7 +26,7 @@ void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
while((rp = rawpacket_dequeue(q))) rawpacket_free(rp); while((rp = rawpacket_dequeue(q))) rawpacket_free(rp);
} }
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,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,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload)
{ {
struct rawpacket *rp = malloc(sizeof(struct rawpacket)); struct rawpacket *rp = malloc(sizeof(struct rawpacket));
if (!rp) return NULL; if (!rp) return NULL;
@ -39,13 +40,14 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
rp->dst = *dst; rp->dst = *dst;
rp->fwmark = fwmark; rp->fwmark = fwmark;
if (ifout) if (ifin)
{ snprintf(rp->ifin,sizeof(rp->ifin),"%s",ifin);
strncpy(rp->ifout,ifout,sizeof(rp->ifout));
rp->ifout[sizeof(rp->ifout)-1]=0;
}
else else
rp->ifout[0]=0; *rp->ifin = 0;
if (ifout)
snprintf(rp->ifout,sizeof(rp->ifout),"%s",ifout);
else
*rp->ifout = 0;
memcpy(rp->packet,data,len); memcpy(rp->packet,data,len);
rp->len=len; rp->len=len;
rp->len_payload=len_payload; rp->len_payload=len_payload;

View File

@ -9,7 +9,7 @@
struct rawpacket struct rawpacket
{ {
struct sockaddr_storage dst; struct sockaddr_storage dst;
char ifout[IFNAMSIZ+1]; char ifin[IFNAMSIZ], ifout[IFNAMSIZ];
uint32_t fwmark; uint32_t fwmark;
size_t len, len_payload; size_t len, len_payload;
uint8_t *packet; uint8_t *packet;
@ -21,6 +21,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q);
void rawpacket_queue_destroy(struct rawpacket_tailhead *q); void rawpacket_queue_destroy(struct rawpacket_tailhead *q);
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q); bool rawpacket_queue_empty(const struct rawpacket_tailhead *q);
unsigned int rawpacket_queue_count(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,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,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload);
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q); struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q);
void rawpacket_free(struct rawpacket *rp); void rawpacket_free(struct rawpacket *rp);

View File

@ -36,6 +36,18 @@
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 #define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3 #define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
#define AUTOTTL_CACHE_LIFETIME 86400
#define AUTOTTL_DEFAULT_DESYNC_DELTA -1
#define AUTOTTL_DEFAULT_DESYNC_MIN 3
#define AUTOTTL_DEFAULT_DESYNC_MAX 20
#define AUTOTTL_DEFAULT_ORIG_DELTA +5
#define AUTOTTL_DEFAULT_ORIG_MIN 3
#define AUTOTTL_DEFAULT_ORIG_MAX 64
#define AUTOTTL_DEFAULT_DUP_DELTA -1
#define AUTOTTL_DEFAULT_DUP_MIN 3
#define AUTOTTL_DEFAULT_DUP_MAX 64
#define MAX_SPLITS 64 #define MAX_SPLITS 64
#define FAKE_TLS_MOD_SAVE_MASK 0x0F #define FAKE_TLS_MOD_SAVE_MASK 0x0F
@ -89,10 +101,12 @@ struct desync_profile
uint8_t dup_ttl, dup_ttl6; uint8_t dup_ttl, dup_ttl6;
uint32_t dup_fooling_mode; uint32_t dup_fooling_mode;
uint32_t dup_badseq_increment, dup_badseq_ack_increment; uint32_t dup_badseq_increment, dup_badseq_ack_increment;
autottl dup_autottl, dup_autottl6;
char orig_mod_start_mode, orig_mod_cutoff_mode; // n - packets, d - data packets, s - relative sequence char orig_mod_start_mode, orig_mod_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int orig_mod_start, orig_mod_cutoff; unsigned int orig_mod_start, orig_mod_cutoff;
uint8_t orig_mod_ttl, orig_mod_ttl6; uint8_t orig_mod_ttl, orig_mod_ttl6;
autottl orig_autottl, orig_autottl6;
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int desync_start, desync_cutoff; unsigned int desync_start, desync_cutoff;
@ -182,6 +196,10 @@ struct params_s
unsigned int ctrack_t_syn, ctrack_t_est, ctrack_t_fin, ctrack_t_udp; unsigned int ctrack_t_syn, ctrack_t_est, ctrack_t_fin, ctrack_t_udp;
t_conntrack conntrack; t_conntrack conntrack;
unsigned int autottl_cache_lifetime;
bool autottl_present;
ip_cache ipcache;
}; };
extern struct params_s params; extern struct params_s params;

View File

@ -579,3 +579,210 @@ bool blob_collection_empty(const struct blob_collection_head *head)
{ {
return !LIST_FIRST(head); return !LIST_FIRST(head);
} }
static void ipcache_item_touch(ip_cache_item *item)
{
time(&item->last);
}
static void ipcache_item_init(ip_cache_item *item)
{
ipcache_item_touch(item);
item->hops = 0;
}
static void ipcache4Destroy(ip_cache4 **ipcache)
{
ip_cache4 *elem, *tmp;
HASH_ITER(hh, *ipcache, elem, tmp)
{
HASH_DEL(*ipcache, elem);
free(elem);
}
}
static void ipcache4Key(ip4if *key, const struct in_addr *a, const char *iface)
{
memset(key,0,sizeof(*key)); // make sure everything is zero
key->addr = *a;
if (iface) snprintf(key->iface,sizeof(key->iface),"%s",iface);
}
static ip_cache4 *ipcache4Find(ip_cache4 *ipcache, const struct in_addr *a, const char *iface)
{
ip_cache4 *entry;
struct ip4if key;
ipcache4Key(&key,a,iface);
HASH_FIND(hh, ipcache, &key, sizeof(key), entry);
return entry;
}
static ip_cache4 *ipcache4Add(ip_cache4 **ipcache, const struct in_addr *a, const char *iface)
{
// avoid dups
ip_cache4 *entry = ipcache4Find(*ipcache,a,iface);
if (entry) return entry; // already included
entry = malloc(sizeof(ip_cache4));
if (!entry) return NULL;
ipcache4Key(&entry->key,a,iface);
oom = false;
HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry);
if (oom) { free(entry); return NULL; }
ipcache_item_init(&entry->data);
return entry;
}
static void ipcache4Print(ip_cache4 *ipcache)
{
char s_ip[16];
time_t now;
ip_cache4 *ipc, *tmp;
time(&now);
HASH_ITER(hh, ipcache , ipc, tmp)
{
*s_ip=0;
inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s iface=%s : hops %u now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, (unsigned long long)(now-ipc->data.last));
}
}
static void ipcache6Destroy(ip_cache6 **ipcache)
{
ip_cache6 *elem, *tmp;
HASH_ITER(hh, *ipcache, elem, tmp)
{
HASH_DEL(*ipcache, elem);
free(elem);
}
}
static void ipcache6Key(ip6if *key, const struct in6_addr *a, const char *iface)
{
memset(key,0,sizeof(*key)); // make sure everything is zero
key->addr = *a;
if (iface) snprintf(key->iface,sizeof(key->iface),"%s",iface);
}
static ip_cache6 *ipcache6Find(ip_cache6 *ipcache, const struct in6_addr *a, const char *iface)
{
ip_cache6 *entry;
ip6if key;
ipcache6Key(&key,a,iface);
HASH_FIND(hh, ipcache, &key, sizeof(key), entry);
return entry;
}
static ip_cache6 *ipcache6Add(ip_cache6 **ipcache, const struct in6_addr *a, const char *iface)
{
// avoid dups
ip_cache6 *entry = ipcache6Find(*ipcache,a,iface);
if (entry) return entry; // already included
entry = malloc(sizeof(ip_cache6));
if (!entry) return NULL;
ipcache6Key(&entry->key,a,iface);
oom = false;
HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry);
if (oom) { free(entry); return NULL; }
ipcache_item_init(&entry->data);
return entry;
}
static void ipcache6Print(ip_cache6 *ipcache)
{
char s_ip[40];
time_t now;
ip_cache6 *ipc, *tmp;
time(&now);
HASH_ITER(hh, ipcache , ipc, tmp)
{
*s_ip=0;
inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s iface=%s : hops %u now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, (unsigned long long)(now-ipc->data.last));
}
}
void ipcacheDestroy(ip_cache *ipcache)
{
ipcache4Destroy(&ipcache->ipcache4);
ipcache6Destroy(&ipcache->ipcache6);
}
void ipcachePrint(ip_cache *ipcache)
{
ipcache4Print(ipcache->ipcache4);
ipcache6Print(ipcache->ipcache6);
}
ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface)
{
ip_cache4 *ipcache4;
ip_cache6 *ipcache6;
if (a4)
{
if ((ipcache4 = ipcache4Add(&ipcache->ipcache4,a4,iface)))
{
ipcache_item_touch(&ipcache4->data);
return &ipcache4->data;
}
}
else if (a6)
{
if ((ipcache6 = ipcache6Add(&ipcache->ipcache6,a6,iface)))
{
ipcache_item_touch(&ipcache6->data);
return &ipcache6->data;
}
}
return NULL;
}
static void ipcache4_purge(ip_cache4 **ipcache, time_t lifetime)
{
ip_cache4 *elem, *tmp;
time_t now = time(NULL);
HASH_ITER(hh, *ipcache, elem, tmp)
{
if (now >= (elem->data.last + lifetime))
{
HASH_DEL(*ipcache, elem);
free(elem);
}
}
}
static void ipcache6_purge(ip_cache6 **ipcache, time_t lifetime)
{
ip_cache6 *elem, *tmp;
time_t now = time(NULL);
HASH_ITER(hh, *ipcache, elem, tmp)
{
if (now >= (elem->data.last + lifetime))
{
HASH_DEL(*ipcache, elem);
free(elem);
}
}
}
static void ipcache_purge(ip_cache *ipcache, time_t lifetime)
{
if (lifetime) // 0 = no expire
{
ipcache4_purge(&ipcache->ipcache4, lifetime);
ipcache6_purge(&ipcache->ipcache6, lifetime);
}
}
static time_t ipcache_purge_prev=0;
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime)
{
time_t now = time(NULL);
// do not purge too often to save resources
if (ipcache_purge_prev != now)
{
ipcache_purge(ipcache, lifetime);
ipcache_purge_prev = now;
}
}

View File

@ -3,6 +3,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <ctype.h> #include <ctype.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <net/if.h>
#include <time.h> #include <time.h>
#include "helpers.h" #include "helpers.h"
@ -161,3 +162,42 @@ struct blob_item *blob_collection_add(struct blob_collection_head *head);
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve); struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve);
void blob_collection_destroy(struct blob_collection_head *head); void blob_collection_destroy(struct blob_collection_head *head);
bool blob_collection_empty(const struct blob_collection_head *head); bool blob_collection_empty(const struct blob_collection_head *head);
typedef struct ip4if
{
char iface[IFNAMSIZ];
struct in_addr addr;
} ip4if;
typedef struct ip6if
{
char iface[IFNAMSIZ];
struct in6_addr addr;
} ip6if;
typedef struct ip_cache_item
{
time_t last;
uint8_t hops;
} ip_cache_item;
typedef struct ip_cache4
{
ip4if key;
ip_cache_item data;
UT_hash_handle hh; /* makes this structure hashable */
} ip_cache4;
typedef struct ip_cache6
{
ip6if key;
ip_cache_item data;
UT_hash_handle hh; /* makes this structure hashable */
} ip_cache6;
typedef struct ip_cache
{
ip_cache4 *ipcache4;
ip_cache6 *ipcache6;
} ip_cache;
ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface);
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime);
void ipcacheDestroy(ip_cache *ipcache);
void ipcachePrint(ip_cache *ipcache);