diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-09-04 09:27:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-09-04 09:27:04 +0000 |
commit | 81fa0bc63909a67cdd6d321617a2e5648a6a94a2 (patch) | |
tree | 2b0a2eae7aed22e3c6f707283d7617d8c02b3fbe /src/tcpstate.c | |
parent | Adding upstream version 2.1.3. (diff) | |
download | dnscap-81fa0bc63909a67cdd6d321617a2e5648a6a94a2.tar.xz dnscap-81fa0bc63909a67cdd6d321617a2e5648a6a94a2.zip |
Adding upstream version 2.2.0.upstream/2.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tcpstate.c')
-rw-r--r-- | src/tcpstate.c | 84 |
1 files changed, 78 insertions, 6 deletions
diff --git a/src/tcpstate.c b/src/tcpstate.c index 5bc3840..b11c701 100644 --- a/src/tcpstate.c +++ b/src/tcpstate.c @@ -38,11 +38,18 @@ #include "iaddr.h" #include "log.h" #include "tcpreasm.h" +#include "hashtbl.h" + +#ifndef s6_addr32 +#define s6_addr32 __u6_addr.__u6_addr32 +#endif #define MAX_TCP_IDLE_TIME 600 #define MAX_TCP_IDLE_COUNT 4096 #define TCP_GC_TIME 60 +static hashtbl* _hash = 0; + tcpstate_ptr tcpstate_find(iaddr from, iaddr to, unsigned sport, unsigned dport, time_t t) { static time_t next_gc = 0; @@ -59,12 +66,15 @@ tcpstate_ptr tcpstate_find(iaddr from, iaddr to, unsigned sport, unsigned dport, } #endif - for (tcpstate = HEAD(tcpstates); - tcpstate != NULL; - tcpstate = NEXT(tcpstate, link)) { - if (ia_equal(tcpstate->saddr, from) && ia_equal(tcpstate->daddr, to) && tcpstate->sport == sport && tcpstate->dport == dport) - break; - } + tcpstate_key key = { + .saddr = &from, + .daddr = &to, + .sport = sport, + .dport = dport + }; + + tcpstate = hash_find(&key, _hash); + if (tcpstate != NULL) { tcpstate->last_use = t; if (tcpstate != HEAD(tcpstates)) { @@ -77,10 +87,47 @@ tcpstate_ptr tcpstate_find(iaddr from, iaddr to, unsigned sport, unsigned dport, return tcpstate; } +unsigned int tcpstate_hash(const tcpstate_key* key) +{ + uint32_t h = 0; + + switch (key->saddr->af) { + case AF_INET: + h = hashword(&key->saddr->u.a4.s_addr, 1, h); + break; + case AF_INET6: + h = hashword(key->saddr->u.a6.s6_addr32, 4, h); + break; + } + + switch (key->daddr->af) { + case AF_INET: + h = hashword(&key->daddr->u.a4.s_addr, 1, h); + break; + case AF_INET6: + h = hashword(key->daddr->u.a6.s6_addr32, 4, h); + break; + } + + uint32_t p = (key->sport << 16) | (key->dport & 0xffff); + return hashword(&p, 1, h); +} + +int tcpstate_cmp(const tcpstate_key* a, const tcpstate_key* b) +{ + if (ia_equalp(a->saddr, b->saddr) && ia_equalp(a->daddr, b->daddr) && a->sport == b->sport && a->dport == b->dport) + return 0; + return 1; +} + tcpstate_ptr _curr_tcpstate = 0; tcpstate_ptr tcpstate_new(iaddr from, iaddr to, unsigned sport, unsigned dport) { + if (!_hash) { + _hash = hash_create(65535, (hashkey_func)tcpstate_hash, (hashkeycmp_func)tcpstate_cmp, 0); + assert(_hash); + } tcpstate_ptr tcpstate = calloc(1, sizeof *tcpstate); if (tcpstate == NULL) { /* Out of memory; recycle the least recently used */ @@ -95,6 +142,7 @@ tcpstate_ptr tcpstate_new(iaddr from, iaddr to, unsigned sport, unsigned dport) if (_curr_tcpstate == tcpstate) { _curr_tcpstate = 0; } + hash_remove(&tcpstate->key, _hash); memset(tcpstate, 0, sizeof(*tcpstate)); } else { tcpstate_count++; @@ -105,6 +153,13 @@ tcpstate_ptr tcpstate_new(iaddr from, iaddr to, unsigned sport, unsigned dport) tcpstate->dport = dport; INIT_LINK(tcpstate, link); PREPEND(tcpstates, tcpstate, link); + + tcpstate->key.saddr = &tcpstate->saddr; + tcpstate->key.daddr = &tcpstate->daddr; + tcpstate->key.sport = sport; + tcpstate->key.dport = dport; + hash_add(&tcpstate->key, tcpstate, _hash); + return tcpstate; } @@ -124,6 +179,7 @@ void tcpstate_discard(tcpstate_ptr tcpstate, const char* msg) if (tcpstate->reasm) { tcpreasm_free(tcpstate->reasm); } + hash_remove(&tcpstate->key, _hash); free(tcpstate); if (_curr_tcpstate == tcpstate) { _curr_tcpstate = 0; @@ -149,3 +205,19 @@ void tcpstate_reset(tcpstate_ptr tcpstate, const char* msg) } } } + +void tcpstate_free(tcpstate_ptr tcpstate) +{ + if (tcpstate) { + UNLINK(tcpstates, tcpstate, link); + if (tcpstate->reasm) { + tcpreasm_free(tcpstate->reasm); + } + hash_remove(&tcpstate->key, _hash); + free(tcpstate); + if (_curr_tcpstate == tcpstate) { + _curr_tcpstate = 0; + } + tcpstate_count--; + } +}
\ No newline at end of file |