summaryrefslogtreecommitdiff
path: root/decoders/ftp/ftp_decoder_hash.c
blob: 3a033683e76e24992468cef4a5afefb064de10dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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