summaryrefslogtreecommitdiff
path: root/access/src/snat.cpp
blob: 140c4aa5057392aa5d534fe909a01c34c9880da6 (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
#include "mgw_utils.h"
#include "snat.h"
#include "ip_mgr.h"

struct snat_handle
{
    void *logger;
    struct ip_mgr_handle *_ip_mgr_handle;
    MESA_htable_handle ip2user_htable;  // should be thread-safe
    MESA_htable_handle snat_tx_htable;
    MESA_htable_handle snat_rx_htable;
    int access_id;
};

struct snat_tx_htable_value
{
    struct mgw_utils_sess sess;
    uint32_t mrl_ip;
};

struct field_stat_handle *g_fs_handle;


static void snat_tx_htable_data_free_cb(void *data)
{
    FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_tx, g_fs_handle->cloumn_element_num, FS_OP_ADD, -1);
    FREE(&data);
}

static void dnat_rx_htable_data_free_cb(void *data)
{
    FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_rx, g_fs_handle->cloumn_element_num, FS_OP_ADD, -1);
    FREE(&data);
}


struct snat_handle * snat_init(const char *profile, MESA_htable_handle ip2user_htable, struct ip_mgr_handle *_ip_mgr_handle, 
                                    struct field_stat_handle *fs_handle, void *logger)
{
    struct snat_handle *handle = ALLOC(struct snat_handle, 1);
    handle->logger = logger;
    handle->_ip_mgr_handle = _ip_mgr_handle;
    handle->ip2user_htable = ip2user_htable;
    handle->snat_tx_htable = mgw_utils_create_htable(profile, "snat_tx_htable", (void *)snat_tx_htable_data_free_cb, NULL, logger);
    handle->snat_rx_htable = mgw_utils_create_htable(profile, "dnat_rx_htable", (void *)dnat_rx_htable_data_free_cb, NULL, logger);
    char *section = (char *)"global";
    MESA_load_profile_int_def(profile, section, "access_id", &handle->access_id, 0);
    g_fs_handle = fs_handle;
    return handle;
}

void snat_destroy(struct snat_handle *handle)
{
    MESA_htable_destroy(handle->snat_tx_htable, NULL);
    MESA_htable_destroy(handle->snat_rx_htable, NULL);
    FREE(&handle);
}

static long snat_tx_htable_query_cb(void *data, const uchar *key, uint size, void *user_arg)
{
    struct snat_tx_htable_value *dup_value = (struct snat_tx_htable_value *)user_arg;
    if(data != NULL)
    {
        struct snat_tx_htable_value *_data = (struct snat_tx_htable_value *)data;
        dup_value->sess.proto = _data->sess.proto;
        dup_value->sess.sip = _data->sess.sip;
        dup_value->sess.sport = _data->sess.sport;
        dup_value->sess.dip = _data->sess.dip;
        dup_value->sess.dport = _data->sess.dport;
        dup_value->mrl_ip = _data->mrl_ip;
        return MGW_HTABLE_KEY_EXISTED;
    }
    else
    {
        return MGW_HTABLE_KEY_NOT_EXISTED;
    }
}

static long snat_rx_htable_query_cb(void *data, const uchar *key, uint size, void *user_arg)
{
    struct mgw_utils_sess *dup_value = (struct mgw_utils_sess *)user_arg;
    if(data != NULL)
    {
        struct mgw_utils_sess *_data = (struct mgw_utils_sess *)data;
        dup_value->proto = _data->proto;
        dup_value->sip = _data->sip;
        dup_value->sport = _data->sport;
        dup_value->dip = _data->dip;
        dup_value->dport = _data->dport;
        return MGW_HTABLE_KEY_EXISTED;
    }
    else
    {
        return MGW_HTABLE_KEY_NOT_EXISTED;
    }
}

static long ip2user_htable_query_cb(void *data, const uchar *key, uint size, void *user_arg)
{
    char *dup_value = (char *)user_arg;
    if(data != NULL)
    {
        char *_data = (char *)data;
        strncpy(dup_value, _data, MGW_SYMBOL_MAX);
        return MGW_HTABLE_KEY_EXISTED;
    }
    else
    {
        return MGW_HTABLE_KEY_NOT_EXISTED;
    }
}

static uint16_t get_candidate_port(int access_id, struct mgw_utils_sess *sess, uint32_t cand_ip)
{   
    u_int16_t random  = mgw_utils_get_random(64);
    uint16_t hash = ntohl(sess->dip) ^ ntohl(cand_ip) ^ ntohs(sess->dport) ^ (sess->proto);
    hash &= 0xff;
    uint16_t port = (access_id << 14) + (random << 8) + hash;
    return htons(port);
}

//get snat_tx_value, if succeed, has already added to snat_rx_htable
static struct snat_tx_htable_value * snat_tx_value_get(struct snat_handle *handle, const char *user_name, struct mgw_utils_sess *snat_tx_key)
{
    struct ip_mgr_handle *_ip_mgr_handle = handle->_ip_mgr_handle;
    int retry_times = 10;
    void *logger = handle->logger;
    for(int i = 0; i < retry_times; i++)
    {
        //get candidate ip
        uint32_t cand_ip;
        int rtn = ip_mgr_snat_cand_ip_get(_ip_mgr_handle, user_name, &cand_ip);
        if(rtn < 0)
        {
            MGW_LOG_ERROR(logger, "Failed at find snat candidate ip, user_name is %s", user_name);
            return NULL;
        }
        //query mrl_ip
        uint32_t mrl_ip;
        rtn = ip_mgr_mrl_ip_query(_ip_mgr_handle, cand_ip, &mrl_ip);
        if(rtn < 0)
        {
            char cand_ip_str[MGW_SYMBOL_MAX];
            mgw_utils_inet_ntoa(cand_ip, cand_ip_str);
            MGW_LOG_ERROR(logger, "mrl ip not found, snat candidate ip is %s", cand_ip_str);
            continue;
        }
        //get candidate port
        u_int16_t cand_port = get_candidate_port(handle->access_id, snat_tx_key, cand_ip);

        //try to add to snat_rx_htable
        struct mgw_utils_sess *snat_rx_key = ALLOC(struct mgw_utils_sess, 1);
        snat_rx_key->sip = snat_tx_key->dip;
        snat_rx_key->sport = snat_tx_key->dport;
        snat_rx_key->proto = snat_tx_key->proto;
        snat_rx_key->dip = cand_ip;
        snat_rx_key->dport = cand_port;
        struct mgw_utils_sess *snat_rx_value = ALLOC(struct mgw_utils_sess, 1);
        snat_rx_value->sip = snat_tx_key->dip;
        snat_rx_value->sport = snat_tx_key->dport;
        snat_rx_value->proto = snat_tx_key->proto;
        snat_rx_value->dip = snat_tx_key->sip;
        snat_rx_value->dport = snat_tx_key->sport;
        char snat_rx_key_str[MGW_SYMBOL_MAX];
        char snat_rx_value_str[MGW_SYMBOL_MAX];
        mgw_utils_sess_to_str(snat_rx_key, snat_rx_key_str);
        mgw_utils_sess_to_str(snat_rx_value, snat_rx_value_str);
        rtn = MESA_htable_add(handle->snat_rx_htable, (const unsigned char *)snat_rx_key, sizeof(struct mgw_utils_sess), (void *)snat_rx_value);
        FREE(&snat_rx_key);
        if(rtn < 0)
        {
            FREE(&snat_rx_value);
            if(rtn != MESA_HTABLE_RET_DUP_ITEM)
            {
                MGW_LOG_ERROR(logger, "MESA_htable: Failed at add, table is %s, key is %s, value is %s, rtn is %d", 
                            "snat_rx_htable", snat_rx_key_str, snat_rx_value_str, rtn);
            }
            continue;
        }
        else
        {
            MGW_LOG_INFO(logger, "MESA_htable: Succeed at add, table is %s, key is %s, value is %s", 
                            "snat_rx_htable", snat_rx_key_str, snat_rx_value_str);
            FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_rx, g_fs_handle->cloumn_element_num, FS_OP_ADD, 1);
            struct snat_tx_htable_value *snat_tx_value = ALLOC(struct snat_tx_htable_value, 1);
            snat_tx_value->sess.sip = cand_ip;
            snat_tx_value->sess.sport = cand_port;
            snat_tx_value->sess.proto = snat_tx_key->proto;
            snat_tx_value->sess.dip = snat_tx_key->dip;
            snat_tx_value->sess.dport = snat_tx_key->dport;
            snat_tx_value->mrl_ip = mrl_ip;
            return snat_tx_value;
        }
    }
    MGW_LOG_ERROR(logger, "snat candidate ip and port conflicts, retry times is %d", retry_times - 1);
    return NULL;
}

int snat_tx_convert(struct snat_handle *handle, char *buff, int len, uint32_t *mrl_ip)
{
    void *logger = handle->logger;
    //get session
    struct mgw_utils_sess *snat_tx_key = ALLOC(struct mgw_utils_sess, 1);
    int rtn = mgw_utils_pkt_sess_parse(buff, len, snat_tx_key);
    if(rtn == -1)
    {
        FREE(&snat_tx_key);
        MGW_LOG_ERROR(logger, "Failed at parse packet, len is %d", len);
        return MGW_DROP;
    }
    char snat_tx_key_str[MGW_SYMBOL_MAX];
    char snat_tx_value_str[MGW_SYMBOL_MAX];
    mgw_utils_sess_to_str(snat_tx_key, snat_tx_key_str);
    //query snat_tx_htable
    long cb_rtn = -1;
    struct snat_tx_htable_value snat_tx_dup_value;
    MESA_htable_search_cb(handle->snat_tx_htable, (const unsigned char *)(snat_tx_key), sizeof(struct mgw_utils_sess), snat_tx_htable_query_cb,
                                         (void *)(&snat_tx_dup_value), &cb_rtn);
    FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_tx, g_fs_handle->cloumn_query_num, FS_OP_ADD, 1);
    if(cb_rtn == MGW_HTABLE_KEY_EXISTED)
    {
        //replace
        FREE(&snat_tx_key);
        FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_tx, g_fs_handle->cloumn_cache_hit, FS_OP_ADD, 1);
        mgw_utils_pkt_sess_replace(buff, len, &(snat_tx_dup_value.sess));
        *mrl_ip = snat_tx_dup_value.mrl_ip;
        mgw_utils_sess_to_str(&(snat_tx_dup_value.sess), snat_tx_value_str);
        MGW_LOG_INFO(logger, "Succeed at snat_tx_convert: %s ---> %s", snat_tx_key_str, snat_tx_value_str);
        return MGW_FORWORD;
    }
    FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_tx, g_fs_handle->cloumn_cache_miss, FS_OP_ADD, 1);
    //query user_name. user_name not existed: bypass, user_name existed: drop or forward
    char dup_user_name[MGW_SYMBOL_MAX];
    cb_rtn = -1;
    uint32_t snat_tx_key_sip = snat_tx_key->sip;
    char snat_tx_key_sip_str[MGW_SYMBOL_MAX];
    mgw_utils_inet_ntoa(snat_tx_key_sip, snat_tx_key_sip_str);
    MESA_htable_search_cb(handle->ip2user_htable, (const unsigned char *)(&snat_tx_key_sip), sizeof(uint32_t), 
                ip2user_htable_query_cb, (void *)(dup_user_name), &cb_rtn);
    FS_operate(g_fs_handle->handle, g_fs_handle->line_ip2user, g_fs_handle->cloumn_query_num, FS_OP_ADD, 1);
    if(cb_rtn == MGW_HTABLE_KEY_NOT_EXISTED)
    {
        mgw_utils_inet_ntoa(snat_tx_key_sip, snat_tx_key_sip_str);
        MGW_LOG_INFO(logger, "MESA_htable: key not existed, table is %s, ip is %s", "ip2user_htable", snat_tx_key_sip_str);
        FS_operate(g_fs_handle->handle, g_fs_handle->line_ip2user, g_fs_handle->cloumn_cache_miss, FS_OP_ADD, 1);
        FREE(&snat_tx_key);
        return MGW_BYPASS;
    }
    MGW_LOG_INFO(logger, "MESA_htable: key existed, table is %s, ip is %s, user is %s", "ip2user_htable", snat_tx_key_sip_str, dup_user_name);
    FS_operate(g_fs_handle->handle, g_fs_handle->line_ip2user, g_fs_handle->cloumn_cache_hit, FS_OP_ADD, 1);
    //get snat_tx_value
    struct snat_tx_htable_value *snat_tx_value = NULL;
    snat_tx_value = snat_tx_value_get(handle, dup_user_name, snat_tx_key);
    if(snat_tx_value == NULL)
    {
        FREE(&snat_tx_key);
        MGW_LOG_ERROR(logger, "Failed at snat_tx_convert: session is %s", snat_tx_key_str);
        return MGW_DROP;
    }
    //add to snat_tx_htable
    rtn = MESA_htable_add(handle->snat_tx_htable, (const unsigned char *)snat_tx_key, sizeof(struct mgw_utils_sess), (void *)snat_tx_value);
    FREE(&snat_tx_key);
    mgw_utils_sess_to_str(&(snat_tx_value->sess), snat_tx_value_str);
    if(rtn < 0)
    {
        if(rtn != MESA_HTABLE_RET_DUP_ITEM)
        {
            MGW_LOG_ERROR(logger, "MESA_htable: Failed at add, table is %s, key is %s, value is %s, rtn is %d", 
                        "snat_tx_htable", snat_tx_key_str, snat_tx_value_str, rtn);
        }
        //snat_tx_table and snat_rx_table are Transaction
        struct mgw_utils_sess *snat_rx_key = ALLOC(struct mgw_utils_sess, 1);
        snat_rx_key->sip = snat_tx_value->sess.dip;
        snat_rx_key->sport = snat_tx_value->sess.dport;
        snat_rx_key->proto = snat_tx_value->sess.proto;
        snat_rx_key->dip = snat_tx_value->sess.sip;
        snat_rx_key->dport = snat_tx_value->sess.sport;
        char snat_rx_key_str[MGW_SYMBOL_MAX];
        mgw_utils_sess_to_str(snat_rx_key, snat_rx_key_str);
        rtn = MESA_htable_del(handle->snat_rx_htable, (const unsigned char *)snat_rx_key, sizeof(struct mgw_utils_sess), NULL);
        FREE(&snat_tx_value);
        FREE(&snat_rx_key);
        if(rtn < 0)
        {
            MGW_LOG_ERROR(logger, "MESA_htable: Failed at del, table is %s, key is %s, rtn is %s", "snat_rx_htable", snat_rx_key_str, rtn);
        }
        else
        {
            MGW_LOG_INFO(logger, "MESA_htable: Succeed at del, table is %s, key is %s", "snat_rx_htable", snat_rx_key_str);
        }
        return MGW_DROP;
    }
    else
    {
        MGW_LOG_INFO(logger, "MESA_htable: Succeed at add, table is %s, key is %s, value is %s", 
                    "snat_tx_htable", snat_tx_key_str, snat_tx_value_str);
        FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_tx, g_fs_handle->cloumn_element_num, FS_OP_ADD, 1);
        //replace 
        mgw_utils_pkt_sess_replace(buff, len, &(snat_tx_value->sess));
        *mrl_ip = snat_tx_value->mrl_ip;
        MGW_LOG_INFO(logger, "Succeed at snat_tx_convert: %s ---> %s", snat_tx_key_str, snat_tx_value_str);
        return MGW_FORWORD;
    }
}

int snat_rx_convert(struct snat_handle *handle, char *buff, int len)
{   
    void *logger = handle->logger;
    //get session
    struct mgw_utils_sess *snat_rx_key = ALLOC(struct mgw_utils_sess, 1);
    int rtn = mgw_utils_pkt_sess_parse(buff, len, snat_rx_key);
    if(rtn == -1)
    {
        FREE(&snat_rx_key);
        MGW_LOG_ERROR(logger, "Failed at parse packet, len is %d", len);
        return MGW_DROP;
    }
    char snat_rx_key_str[MGW_SYMBOL_MAX];
    char snat_rx_value_str[MGW_SYMBOL_MAX];
    mgw_utils_sess_to_str(snat_rx_key, snat_rx_key_str);
    //query snat_rx_htable
    long cb_rtn = -1;
    struct mgw_utils_sess snat_rx_dup_value;
    MESA_htable_search_cb(handle->snat_rx_htable, (const unsigned char *)(snat_rx_key), sizeof(struct mgw_utils_sess), snat_rx_htable_query_cb,
                                         (void *)(&snat_rx_dup_value), &cb_rtn);
    FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_rx, g_fs_handle->cloumn_query_num, FS_OP_ADD, 1);
    if(cb_rtn == MGW_HTABLE_KEY_EXISTED)
    {
        //replace
        FREE(&snat_rx_key);
        FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_rx, g_fs_handle->cloumn_cache_hit, FS_OP_ADD, 1);
        mgw_utils_pkt_sess_replace(buff, len, &snat_rx_dup_value);
        mgw_utils_sess_to_str(&snat_rx_dup_value, snat_rx_value_str);
        MGW_LOG_INFO(logger, "Succeed at snat_rx_convert: %s ---> %s", snat_rx_key_str, snat_rx_value_str);
        return MGW_FORWORD;
    }
    FREE(&snat_rx_key);
    FS_operate(g_fs_handle->handle, g_fs_handle->line_snat_rx, g_fs_handle->cloumn_cache_miss, FS_OP_ADD, 1);
    return MGW_BYPASS;
}