summaryrefslogtreecommitdiff
path: root/decoders/ftp/ftp_decoder_hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'decoders/ftp/ftp_decoder_hash.c')
-rw-r--r--decoders/ftp/ftp_decoder_hash.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/decoders/ftp/ftp_decoder_hash.c b/decoders/ftp/ftp_decoder_hash.c
new file mode 100644
index 0000000..3a03368
--- /dev/null
+++ b/decoders/ftp/ftp_decoder_hash.c
@@ -0,0 +1,138 @@
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ftp_decoder_inner.h"
+#include "ftp_decoder_hash.h"
+#include "ftp_decoder_util.h"
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include "uthash/uthash.h"
+#include "uthash/utlist.h"
+
+ static __thread struct ftp_datalink_htable *__thread_local_ftp_datalink_htable = NULL;
+ static __thread struct ftp_datalink_htable *__thread_local_ftp_datalink_htable_fifo_head = NULL;
+ static __thread char __ftp_hash_string_buf[FTP_HASH_STRING_BUF_SIZE];
+ static __thread int ftp_local_thread_idx;
+ static __thread struct ftp_decoder *ftp_local_env;
+
+ static void ftp_del_hash_item(struct ftp_datalink_htable *item)
+ {
+ ftp_decoder_stat_incrby(ftp_local_thread_idx, ftp_local_env, FTPD_STAT_DATA_LINK_HTABLE_ITEMS, -1);
+ HASH_DEL(__thread_local_ftp_datalink_htable, item);
+ DL_DELETE(__thread_local_ftp_datalink_htable_fifo_head, item);
+ ftp_decoder_do_exdata_free(item->ftp_ext, ftp_local_env);
+ free(item); // only free hash item, but not free ftp_ext
+ }
+
+ static void ftp_hash_cleanup_timeout(void)
+ {
+ struct ftp_datalink_htable *to_del, *tmp;
+ time_t now = time(NULL);
+ DL_FOREACH_SAFE(__thread_local_ftp_datalink_htable_fifo_head, to_del, tmp)
+ {
+ if (now - to_del->insert_htable_time > FTP_HASH_ITEM_TIMEOUT)
+ {
+ ftp_del_hash_item(to_del);
+ }
+ }
+ }
+
+ int ftp_hash_add(const ftp_hash_key_t *key, u_int32_t key_len, struct ftp_datalink_htable *new_item)
+ {
+ ftp_hash_cleanup_timeout();
+ struct ftp_datalink_htable *in_hash_item = NULL;
+ HASH_FIND(hh, __thread_local_ftp_datalink_htable, key, key_len, in_hash_item);
+ if (in_hash_item != NULL)
+ {
+ return -1; // duplicate
+ }
+ HASH_ADD(hh, __thread_local_ftp_datalink_htable, hkey, key_len, new_item);
+ DL_APPEND(__thread_local_ftp_datalink_htable_fifo_head, new_item);
+ return 0;
+ }
+
+ void ftp_hash_del(const ftp_hash_key_t *key)
+ {
+ struct ftp_datalink_htable *tmp = NULL;
+ HASH_FIND(hh, __thread_local_ftp_datalink_htable, key, sizeof(ftp_hash_key_t), tmp);
+ if (tmp)
+ {
+ ftp_del_hash_item(tmp);
+ }
+ }
+
+ void ftp_make_hkey_v4(ftp_hash_key_t *keyv4, uint32_t sip_net, uint32_t dip_net, uint16_t dip_port_net)
+ {
+ memset(keyv4, 0, sizeof(ftp_hash_key_t));
+ keyv4->af_inet = AF_INET;
+ keyv4->saddr4 = sip_net;
+ keyv4->daddr4 = dip_net;
+ keyv4->sport = 0;
+ keyv4->dport = dip_port_net;
+ }
+
+ void ftp_make_hkey_v6(ftp_hash_key_t *keyv6, const struct in6_addr *sip, const struct in6_addr *dip, uint16_t dip_port_net)
+ {
+ memset(keyv6, 0, sizeof(ftp_hash_key_t));
+ keyv6->af_inet = AF_INET6;
+ memcpy(&keyv6->saddr6, sip, sizeof(struct in6_addr));
+ memcpy(&keyv6->daddr6, dip, sizeof(struct in6_addr));
+ keyv6->sport = 0;
+ keyv6->dport = dip_port_net;
+ }
+
+ struct ftp_datalink_htable *ftp_hash_search(const ftp_hash_key_t *key)
+ {
+ ftp_hash_cleanup_timeout();
+ struct ftp_datalink_htable *tmp = NULL;
+ HASH_FIND(hh, __thread_local_ftp_datalink_htable, key, sizeof(ftp_hash_key_t), tmp);
+ return tmp;
+ }
+
+ const char *ftp_hash_key_to_str(const ftp_hash_key_t *hkey)
+ {
+ char sip_str[INET6_ADDRSTRLEN], dip_str[INET6_ADDRSTRLEN];
+ unsigned short sport_host, dport_host;
+ if (AF_INET == hkey->af_inet)
+ {
+ inet_ntop(AF_INET, &hkey->saddr4, sip_str, INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &hkey->daddr4, dip_str, INET_ADDRSTRLEN);
+ sport_host = ntohs(hkey->sport);
+ dport_host = ntohs(hkey->dport);
+ }
+ else
+ {
+ inet_ntop(AF_INET6, &hkey->saddr6, sip_str, INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, &hkey->daddr6, dip_str, INET6_ADDRSTRLEN);
+ sport_host = ntohs(hkey->sport);
+ dport_host = ntohs(hkey->dport);
+ }
+ snprintf(__ftp_hash_string_buf, sizeof(__ftp_hash_string_buf), "%s:%u -> %s:%u", sip_str, sport_host, dip_str, dport_host);
+ return __ftp_hash_string_buf;
+ }
+
+ struct module *ftp_on_thread_init(UNUSED struct module_manager *mod_mgr, UNUSED int thread_id, struct module *mod)
+ {
+ ftp_local_thread_idx = thread_id;
+ __thread_local_ftp_datalink_htable = NULL;
+ ftp_local_env = (struct ftp_decoder *)module_get_ctx(mod);
+ return mod;
+ }
+
+ void ftp_on_thread_exit(UNUSED struct module_manager *mod_mgr, UNUSED int thread_id, UNUSED struct module *mod)
+ {
+ struct ftp_datalink_htable *item, *tmp;
+ HASH_ITER(hh, __thread_local_ftp_datalink_htable, item, tmp)
+ {
+ ftp_del_hash_item(item);
+ }
+ HASH_CLEAR(hh, __thread_local_ftp_datalink_htable);
+ }
+
+#ifdef __cplusplus
+}
+#endif