diff options
Diffstat (limited to 'src/access/flowood_access.c')
| -rw-r--r-- | src/access/flowood_access.c | 1656 |
1 files changed, 1656 insertions, 0 deletions
diff --git a/src/access/flowood_access.c b/src/access/flowood_access.c new file mode 100644 index 0000000..6af4866 --- /dev/null +++ b/src/access/flowood_access.c @@ -0,0 +1,1656 @@ +#include "flowood.h" +#include "flowood_fun.h" +#include "flwd_net.h" +#include "MESA_htable.h" +#include "MESA_list_queue.h" +#include "MESA_handle_logger.h" +#include "MESA_list_count.h" +#include "ltsm.h" +#include <assert.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> +#include <string.h> +#include <assert.h> +#include <arpa/inet.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> + +/* + IP����ϵͳ��������, ��������ն˵�����, ���ݲ���ѡ���ض�IP��, ��NATת��, + ����ת������, + �Զ������̷�ʽ����. +*/ + +static int flwd_access_fetch_usable_ipport_by_single_ip( + flwd_active_ip_t *flwd_active_ip, flwd_active_ip_port_args_t *usable_active_ipport_args) +{ + int ret; + int try_times; + MESA_list_count_t *usable_sport_queue_head, *sport_list_node; + unsigned short sport; + long buf_len; + flwd_tuple5_t seek_nat_key; + unsigned int compat_io_hash; + char ip_str[64]; + int usable_sport_num; + + if(IPPROTO_TCP == usable_active_ipport_args->protocol){ + usable_sport_queue_head = &flwd_active_ip->usable_tcp_sport_list_head; + }else{ + usable_sport_queue_head = &flwd_active_ip->usable_udp_sport_list_head; + } + + usable_sport_num = MESA_list_count_get_count(usable_sport_queue_head); + if(usable_sport_num <= 0){ + /* ��ǰIP���ö˿���ȫ�������� */ + flwd_log(20, "ip_pool: %s, all usable sport is in used!\n", + flwd_ipt_ntop_r(&flwd_active_ip->active_ip_net_order, ip_str, 64)); + return ITERATE_CB_RET_CONTINUE_FLAG; + } + + flwd_tuple5_dup_to_stack(usable_active_ipport_args->tid, &seek_nat_key, usable_active_ipport_args->nat_key); + + flwd_tuple5_adjust_dir(&seek_nat_key); + + if(FLWD_IP_ADDR_TYPE_V4 == flwd_active_ip->active_ip_net_order.addr_type){ + seek_nat_key.ippair_v4.sip_net_order = flwd_active_ip->active_ip_net_order.addr_ipv4; + }else{ + memcpy(&seek_nat_key.ippair_v6->sip_net_order, + &flwd_active_ip->active_ip_net_order.addr_ipv6, + sizeof(struct in6_addr)); + } + + /* + TODO, + �˴�ѡ����ԴIP, ��Ҫѡ����ʵ�Դ�˿�, ʹ�ظ��������ܷ�������ǰ���͵��߳�, + ����ʹ��ring_queue, ��Ҫ��ͣ�ı������Կ��ö˿�, ֱ��hashֵ���Ϸ�������. + */ + sport_list_node = usable_sport_queue_head->nextele; + + for(try_times = 0; + (try_times < usable_sport_num) && (sport_list_node != usable_sport_queue_head); + try_times++, sport_list_node = sport_list_node->nextele){ + /* �������ж˿�, �鿴�ĸ����ɵ���Ԫ��HASH���ɷ��ϵ�ǰ�߳�id */ + memcpy(&seek_nat_key.sport_net_order, &sport_list_node->quiddity, sizeof(short)); + compat_io_hash = compat_marsio_tuple4_hash(&seek_nat_key); + if((compat_io_hash % flwd_cfg_val.tot_thread_count) == usable_active_ipport_args->tid){ + MESA_list_count_del(usable_sport_queue_head, sport_list_node); /* �ӿ��ö˿��������Ƴ� */ + free(sport_list_node); /* �˿��Ѿ���ȡ��, ������������ṹ */ + goto bingo; + } + } + + /* ��Ȼ�п��ö˿�, ���ǵ�ǰIPû�ҵ��ʺϵ�ǰ�߳�, �Թ�����ʵ�HASHֵ����Ѷ˿�, ����������һ��IP */ + flwd_log(20, "ip_pool: %s,has %d usable sport, but unfortunately no match hash value sport for current thread!\n", + usable_sport_num, + flwd_ipt_ntop_r(&flwd_active_ip->active_ip_net_order, ip_str, 64), usable_sport_num); + return ITERATE_CB_RET_CONTINUE_FLAG ; + +bingo: + usable_active_ipport_args->act_sip_net_order = flwd_active_ip->active_ip_net_order; + usable_active_ipport_args->act_sport_net_order = seek_nat_key.sport_net_order; + + memcpy(&usable_active_ipport_args->gdev_args, &flwd_active_ip->gdev_args, sizeof(flwd_gdev_associated_args_t)); + + return ITERATE_CB_RET_BREAK_FLAG | ITERATE_CB_RET_REVERSE_FLAG; +} + +/* + NOTE: + Ϊ��ͬʱ��Ӧstatic_pool��dynamic_pool, ����һ������, + ��ͬ����static_poolΪһ��flwd_active_ip_t�ṹ������, ��Ҫ�ڴ˺�����ѭ������. +*/ +static int flwd_access_fetch_usable_ipport_by_ip_list_cb( + const uchar * key, uint size, void * data, void *user) +{ + int ret; + flwd_active_ip_t *flwd_active_ip_list_head = (flwd_active_ip_t *)data; + flwd_active_ip_t *tmp_node; + flwd_active_ip_port_args_t *usable_active_ipport_args = (flwd_active_ip_port_args_t *)user; + + tmp_node = flwd_active_ip_list_head; + do{ + ret = flwd_access_fetch_usable_ipport_by_single_ip(tmp_node, usable_active_ipport_args); + if(ITERATE_CB_RET_BREAK_FLAG == ret){ + break; + } + + tmp_node = (flwd_active_ip_t *)tmp_node->active_ip_list_node.nextele->quiddity; + }while(flwd_active_ip_list_head != tmp_node); + + return ret|ITERATE_CB_RET_REVERSE_FLAG /* ��item˳��, ÿ�����Ӹ�����ַ���ﲻͬ��IP */; +} + +/* + ����: ��ʵ�ͻ��˵���Ԫ��; + ���: ���õ�Դ��ԾIP; + + ����ֵ: + 1 : ���в�������, �����ҵ����ŵ�ǰ���ԵĿ���Դip; + 0 : ����; + -1 : �����˲���, ��û�п���IP; + + service_defined��ʽ: + "IR_STRATEGY:123" +*/ +static int flwd_access_snat_search_policy(int tid, + flwd_tuple5_t *tuple5, flwd_active_ip_port_args_t *usable_active_ipport_net_order) +{ + unsigned int usable_active_ip = 0; + int ret; + int found_usable_policy_ip = -1; + +#if FLWD_NO_ACTIVE_IP_DISCOVER + return 0; /* ��ʱ����, ���� */ +#else + unsigned int policy_id; + MESA_list_t *list_node; + flwd_active_ip_t *ip_static_pool_list_head, *list_node_item; + flwd_ip_region_type_t ip_pool_retion; + unsigned char static_ip_group_key[64]; + int static_ip_group_key_len = 64; + + policy_id = flwd_access_maat_scan_rule(tid, tuple5); + if(0 == policy_id){ + return 0; + } + + flwd_log(10, "tuple4 %s hit policy id:%u\n", flwd_tuple5_ntop(tid, tuple5), policy_id); + + /* ���õ�IPΪ��ǰĿ��IP�ķ��� */ + if(FLWD_IP_REGION_INLAND == usable_active_ipport_net_order->dip_region_type){ + ip_pool_retion = FLWD_IP_REGION_OUTLAND; + }else{ + ip_pool_retion = FLWD_IP_REGION_INLAND; + } + + flwd_policy_group_id_key_gen(policy_id, static_ip_group_key, &static_ip_group_key_len); + + ip_static_pool_list_head = flwd_ip_pool_search(FLWD_ACT_IP_STATIC, + flwd_thread_val[tid].flwd_ip_pool_static_htable[tuple5->addr_type][ip_pool_retion], + static_ip_group_key, + static_ip_group_key_len); + if(NULL == ip_static_pool_list_head){ + flwd_log(30, "tuple4 %s hit policy id:%u, but no valid ip in static ip_pool!\n", + flwd_tuple5_ntop(tid, tuple5), policy_id); + return 0; + } + + list_node = &ip_static_pool_list_head->active_ip_list_node; + do{ + list_node_item = (flwd_active_ip_t *)list_node->quiddity; + /* ����htable_cb����, �˴���key, size�ɲ��� */ + ret = flwd_access_fetch_usable_ipport_by_single_ip(list_node_item, usable_active_ipport_net_order); + if(ITERATE_CB_RET_BREAK_FLAG == ret){ + found_usable_policy_ip = 1; + break; + } + list_node = list_node->nextele; + }while(list_node != &ip_static_pool_list_head->active_ip_list_node); + +#endif + + return found_usable_policy_ip; +} + + +/* + �ӵ�ַ����, ���ѡ��һ�����û�ԾIP. + + TODO: + �����ͬ�ͻ���, ʹ���˲�ͬ����, ��ͬһ��ԴIP���ڲ�ͬ�ľ�̬��ַ����, + ������1.2.3.4��Ϊ����IP, �˿ڷ�Χ�ǰ�access_gateway�������ֵ�, + ����ͬһ��access_gateway, ������һ���Ķ˿�, ��ͻ��ô��? + ��ô�����ͻ����??!! + + �����ý��汣֤, һ��IP��ַֻ������һ����̬��ַ��. +*/ +static int flwd_access_snat_fetch_usable_ip_from_pool( + MESA_htable_handle table, pthread_rwlock_t *flwd_ip_pool_rwlock, int tid, + flwd_tuple5_t *nat_key, flwd_active_ip_port_args_t *usable_active_ipport_args) +{ + + pthread_rwlock_wrlock(flwd_ip_pool_rwlock); + + /* ����htable�İ�ʱ�����ȱ�������, ��ѡ���µ�IP, ����dip�ĵ���, ѡ���෴��Դ��Ծip */ + MESA_htable_iterate_bytime(table, + ITERATE_TYPE_NEWEST_FIRST, + flwd_access_fetch_usable_ipport_by_ip_list_cb, + usable_active_ipport_args); + + if((0 == usable_active_ipport_args->act_sip_net_order.addr_ipv4) + || (0 == memcmp(&usable_active_ipport_args->act_sip_net_order.addr_ipv6, + &flwd_global_val.zero_ipv6_addr, sizeof(struct in6_addr)))){ + pthread_rwlock_unlock(flwd_ip_pool_rwlock); + return -1; + } + + pthread_rwlock_unlock(flwd_ip_pool_rwlock); + return 0; +} + +#if FLWD_SUPPORT_DNAT +static void * flwd_search_access_dnat_lb_policy(int tid, + flwd_tuple4v4_t *nat_key, flwd_actual_ip_port_t *actual_ipport_net_order) +{ + /* ����dip, dport�ҵ���ʵ��������dip, dport, �滻�������ݰ�, Ȼ��洢��nat-htable */ + return 0; +} +#endif + + + +/* TODO: + ��ֹ������, �ǶԳ�·������, ����S2C�����������C2S������ͬһ̨ת������, + + Ҫ�����ӱ���ɢ��ȫ����ת������, + + ��Ԫ��, dip+dport+sip, ��Ԫ����̫����, + + sport����һ������ָ���㷨, ɨ����Ԫ������ж�sport. +*/ +static int flwd_link_table_broadcast(int tid, flwd_nat_info_t *nat_info) +{ + /* TODO: + ��ֹ������, �ǶԳ�·������, ����S2C�����������C2S������ͬһ̨ת������, + + Ҫ�����ӱ���ɢ��ȫ����ת������. + */ + return 0; +} + + +/* ��ָ����Ϣ�洢��Դ�˿ڵ��ض��ֶ�, ��������IR�İ�����ʵ�ͻ��˵İ� */ +static void flwd_pkt_signature_hide_to_sport( + unsigned short pkt_signature, flwd_nat_info_t *nat_info) +{ + unsigned short sport_host_order; + + pkt_signature &= (FLWD_UDP_SPORT_HASH_MASK >> 8); + + if(0 == nat_info->outer_nat_tuple5.dir_reverse){ + sport_host_order = ntohs(nat_info->outer_nat_tuple5.sport_net_order); + sport_host_order &= (~FLWD_UDP_SPORT_HASH_MASK); /* �����hash�ֶ� */ + sport_host_order |= (pkt_signature << 8); /* hash�ֶ�������sport�� */ + nat_info->outer_nat_tuple5.sport_net_order = htons(sport_host_order); + }else{ + sport_host_order = ntohs(nat_info->outer_nat_tuple5.dport_net_order); + sport_host_order &= (~FLWD_UDP_SPORT_HASH_MASK); /* �����hash�ֶ� */ + sport_host_order |= (pkt_signature << 8); /* hash�ֶ�������sport�� */ + nat_info->outer_nat_tuple5.dport_net_order = htons(sport_host_order); + } + + return; +} + + +/* + ѡ��Դ�˿���Ҫ��֤����ȥ���߳�id, ��Ӧ�������֮��, ���ܱ�����������ͬһ���߳�, + ������Ҫ���Զ��, �ҵ�һ�����ʵ�sport, ���ɷ��������ķ����㷨. + + ��Ϊdip, dport�Dz��ܱ��, sipҲ�����ѡ�����ܱ�, ֻ����Դ�˿�����һЩtrick, + ���Ҷ����ͬ��������֮��, �������صIJ�ͬ�߳�֮���Ѿ�Ԥ�ȷ����˶˿ڷ�Χ, + ����һ����ԾIP��˵, �˿������������trick�ķ�Χ��С, ����ȷ�Ⱥܵ�! + + ��ȡһ���²���: + 1,TCPЭ��, ʹ��SYN-ISNת������, ͨ��32bit��ISN����hash, ��Ϊָ��; + 2,DNSЭ��, ʹ��DNS-TRANSIDת������, ͨ��16bit��TRANSID��Ϊָ��, ��ͻ�ʱ�TCP_ISN���һЩ; + 3,����UDPЭ��, ѡ�����Ԫ��ʹ��maat_redisȫ����ɢ, ����Э����ܴ�����ʱ������װ���ʧ! +*/ +static int flwd_acc_user_generate_pkt_signature( + int tid, flwd_nat_info_t *nat_info, flwd_raw_pkt_t *raw_pkt) +{ + const flwd_ipv4_hdr_t *flwd_iphdr = (flwd_ipv4_hdr_t *)raw_pkt->inner_ip_layer_hdr; + const flwd_udp_hdr_t *flwd_udphdr; + const flwd_tcp_hdr_t *flwd_tcphdr; + int canot_convert_pro; + unsigned int hash_val; + unsigned short pkt_signature; + + if(FLWD_NAT_TYPE_SNAT != nat_info->nat_type){ + return 0; + } + + if(IPPROTO_TCP == flwd_iphdr->ip_p){ + flwd_tcphdr = (flwd_tcp_hdr_t *)((char *)flwd_iphdr + flwd_iphdr->ip_hl * 4); + assert(TH_SYN == flwd_tcphdr->th_flags); + canot_convert_pro = 0; + /* �˴�Ҫʹ��nat֮�����Ԫ��, ָ����Ϣ��Ҫ����ת������ʶ������internet�����ݰ� */ + hash_val = flwd_tuple5_hash(&nat_info->outer_nat_tuple5, 1); + /* + TODO: + ����TCPЭ��, ʹ�ö˿�HASH�����ʽ��ͻ�ʽϸ�, ������ISN�ķ�ʽ, + */ +#if 0 + nat_info->signature_param = (long long)hash_val - (long long)ntohl(flwd_tcphdr->th_seq); +#else + pkt_signature = hash_val % (FLWD_UDP_SPORT_HASH_MASK >> 8); +#endif + + }else if(IPPROTO_UDP == flwd_iphdr->ip_p){ + /* + TODO, + ����UDPЭ��, ���ö˿�HASH����, ��ͻ��Ҳ�ϸ�, ������redisȫ����ɢ��Ԫ�鹦��, + IP���ú���ʵ�ͻ��˷���ͬһ��������, ���Ҷ˿ڻ����ɳ�ͻ�ļ��ʼ�С. + */ + hash_val = flwd_tuple5_hash(&nat_info->outer_nat_tuple5, 1); + pkt_signature = hash_val % (FLWD_UDP_SPORT_HASH_MASK >> 8); + canot_convert_pro = 0; + }else{ + canot_convert_pro = 1; + } + + if(1 == canot_convert_pro){ + /* TODO: ��ͨUDPЭ�鿿redisʵʱ��ɢ��Ԫ��, ʶ��Ӧ��� */ + //flwd_link_table_broadcast(tid, nat_info); + }else{ + flwd_pkt_signature_hide_to_sport(pkt_signature, nat_info); + } + + return 0; +} + +static flwd_terminal_proto_t flwd_access_proto_identify(flwd_raw_pkt_t *raw_pkt) +{ + flwd_terminal_proto_t flwd_pro = FLWD_TERMINAL_IP_LAYER; + + /* + TODO: + ʶ��L2TP, PPTP���뷽ʽ�����ݰ�. + + ���߿�������ʽ�ս�VPN, תΪ��IP��, ��ͬ��IP�������. + */ + + return flwd_pro; +} + + + +/* �������شӿͻ��˷����հ�, ����ײ�ԭʼ���ݰ���ں��� */ +static int flwd_acc_user_pkt_input(flwd_device_handle_t *device_handle, + int tid, flwd_raw_pkt_t *raw_pkt) +{ + int ret; + + raw_pkt->terminal_proto = flwd_access_proto_identify(raw_pkt); + switch(raw_pkt->terminal_proto){ + case FLWD_TERMINAL_IP_LAYER: + flwd_access_kernal_pkt_input(device_handle, tid, raw_pkt); + break; + + case FLWD_TERMINAL_IP_L2TP: + /* TODO */ + assert(0); + break; + + case FLWD_TERMINAL_IP_PPTP: + /* TODO */ + assert(0); + break; + + default: + assert(0); + } + + return 0; +} + +/* + NAT��ַת��, + ����nat_info��, ����������Ԫ��, �滻���ݰ��е�IP�Ͷ˿�, + �����¼���У���. +*/ +static int flwd_nat_set_new_addr_v4(flwd_topology_t topo_mode, + flwd_nat_type_t nat_type, const flwd_nat_info_t *nat_info, flwd_ipv4_hdr_t *flwd_ip4hdr) +{ + flwd_tcp_hdr_t *flwd_tcp_hdr; + flwd_udp_hdr_t *flwd_udp_hdr; + const flwd_tuple5_t *after_nat_addr; + struct ltsm_result ltsm_res; + unsigned int *tobe_modify_ip; + unsigned short *tobe_modify_port; + unsigned char tcp_flags = 0; + + if(TOPO_ACC_LINK_USER == topo_mode){ + /* C2I����, ��outer�ĵ�ַ, �滻��ǰ����Դip��Դ�˿� */ + after_nat_addr = &nat_info->outer_nat_tuple5; + tobe_modify_ip = &flwd_ip4hdr->ip_src.s_addr; + if(IPPROTO_TCP == flwd_ip4hdr->ip_p){ + flwd_tcp_hdr = (flwd_tcp_hdr_t *)((char *)flwd_ip4hdr + flwd_ip4hdr->ip_hl * 4); + tcp_flags = flwd_tcp_hdr->th_flags; + tobe_modify_port = &flwd_tcp_hdr->th_sport; + }else{ + flwd_udp_hdr = (flwd_udp_hdr_t *)((char *)flwd_ip4hdr + flwd_ip4hdr->ip_hl * 4); + tobe_modify_port = &flwd_udp_hdr->uh_sport; + } + }else{ + /* I2C����, ��inner�ĵ�ַ, �滻��ǰ����Ŀ��ip��Ŀ��˿� */ + after_nat_addr = &nat_info->inner_nat_tuple5; + tobe_modify_ip = &flwd_ip4hdr->ip_dst.s_addr; + if(IPPROTO_TCP == flwd_ip4hdr->ip_p){ + flwd_tcp_hdr = (flwd_tcp_hdr_t *)((char *)flwd_ip4hdr + flwd_ip4hdr->ip_hl * 4); + tcp_flags = flwd_tcp_hdr->th_flags; + tobe_modify_port = &flwd_tcp_hdr->th_dport; + }else{ + flwd_udp_hdr = (flwd_udp_hdr_t *)((char *)flwd_ip4hdr + flwd_ip4hdr->ip_hl * 4); + tobe_modify_port = &flwd_udp_hdr->uh_dport; + } + } + + /* Ϊ��hashֻ����һ��, key�ĵ�ַ�洢���Ǹ���sip>dip�Ľ������, Ҫ���ݴ洢��key�ĵ�ַ����, ѡ��������ԭʼ��ַ */ + if(0 == after_nat_addr->dir_reverse){ + *tobe_modify_ip = after_nat_addr->ippair_v4.sip_net_order; + *tobe_modify_port = after_nat_addr->sport_net_order; + }else{ + *tobe_modify_ip = after_nat_addr->ippair_v4.dip_net_order; + *tobe_modify_port = after_nat_addr->dport_net_order; + } + + if(IPPROTO_TCP == flwd_ip4hdr->ip_p){ + flwd_sendpacket_do_checksum((char *)flwd_ip4hdr, + IPPROTO_TCP, + ntohs(flwd_ip4hdr->ip_len) - flwd_ip4hdr->ip_hl * 4); /* �Ӵ����ͷ����ʼ����ĩβ�ij��� */ + }else{ + flwd_sendpacket_do_checksum((char *)flwd_ip4hdr, + IPPROTO_UDP, + ntohs(flwd_ip4hdr->ip_len) - flwd_ip4hdr->ip_hl * 4); /* �Ӵ����ͷ����ʼ����ĩβ�ij��� */ + } + + flwd_sendpacket_do_checksum((char *)flwd_ip4hdr, + IPPROTO_IP, + sizeof(flwd_ipv4_hdr_t)); + +#if FLWD_USE_LTSM_FOR_QUICK_CLOSE + unsigned char dir; + if(tcp_flags != 0){ + if(FLWD_NAT_TYPE_SNAT == nat_info->nat_type){ + if(TOPO_ACC_LINK_USER == topo_mode){ + dir = LTSM_DIR_C2S; /* SNATģʽ, ��user���յ��Ŀ϶���client�˵İ� */ + }else{ + dir = LTSM_DIR_S2C; + } + }else{ + if(TOPO_ACC_LINK_USER == topo_mode){ + dir = LTSM_DIR_S2C; + }else{ + dir = LTSM_DIR_C2S; + } + } + + ltsm_res = ltsm_get_current_state(nat_info->ltsm_stat_handle, tcp_flags, dir); + } +#endif + + return (int)ltsm_res.fstate; +} + + +static int flwd_nat_set_new_addr_v6(flwd_topology_t topo_mode, + flwd_nat_type_t nat_type, const flwd_nat_info_t *nat_info,flwd_ipv6_hdr_t *flwd_ip6hdr) +{ + /* TODO, IPv6 NAT */ + return -1; +} + + +/* + ����֮ǰ�Ѿ��洢��ת����, ��natת�� + Ŀǰ���õIJ�����ֱ����ԭʼ����IP��ַ�Ͷ˿�, �������, ����ÿ�ζ�malloc/memcpy/free����. +*/ +static int flwd_do_nat(flwd_device_handle_t *device_handle, + flwd_nat_info_t *nat_info, flwd_raw_pkt_t *raw_pkt) +{ + int ret; + + if(FLWD_IP_ADDR_TYPE_V4 == nat_info->outer_nat_tuple5.addr_type){ + ret = flwd_nat_set_new_addr_v4(device_handle->io_para.topo_mode, + nat_info->nat_type, nat_info, + (flwd_ipv4_hdr_t *)raw_pkt->inner_ip_layer_hdr); + }else{ + ret = flwd_nat_set_new_addr_v6(device_handle->io_para.topo_mode, + nat_info->nat_type, nat_info, + (flwd_ipv6_hdr_t *)raw_pkt->inner_ip_layer_hdr); + } + + return ret; +} + +static void *flwd_nat_table_search(void) +{ + /* + ת���������к�, �ὫSNAT��DNAT���ʹ洢��vxlan��ij���ֶΣ� + + ����SNAT, C2S����Ĵ洢NAT�����Ԫ��, ��S2C����Ļ�����, �ٴβ���htable��ͬ��key�� �ָ�֮ǰ��ʵ�ͻ���IP��PORT����; + + ����DNAT, ��һ��SYN��ɨ��IP���ò��Ա�, �ҵ�һ�����õ�RIP��RPORT, Ȼ��Ҳ�洢��htable, + ����������������İ�, ֱ�Ӻ�SNAT�ɸ���һ��htable, ����һ�μ��ɡ� + */ + return 0; +} + + +static void * flwd_acc_to_fwd_pre_output(flwd_device_handle_t *rcv_device_handle, + flwd_device_handle_t *send_device_handle, int tid, flwd_nat_info_t *nat_info, + flwd_raw_pkt_t *raw_pkt, unsigned int out_opt) +{ + flwd_vxlan_hdr_t *outer_vxlan_hdr; + unsigned char *local_acc_gateway_mac = NULL ; + int ret; + flwd_ip_t ip_union; + char ip_str[64]; + flwd_eth_hdr_t *inner_eth_hdr; + + char *unsend_raw_data_ptr = rcv_device_handle->low_level_mbuff_mtod(raw_pkt->low_level_mbuff); + int unsend_raw_data_len = rcv_device_handle->low_level_mbuff_get_pkt_len(raw_pkt->low_level_mbuff); + void *send_mbuff = send_device_handle->low_level_mbuff_malloc(send_device_handle, tid, unsend_raw_data_len+FLWD_VXLAN_OUTER_PACKET_LEN); + char *send_buf_data_ptr; + + /* �����վ���Ļ�����copy�������;���Ļ�����, �����߲���ģʽ���ܲ�һ��, + ����accessʹ��Э��ջģʽ, ��forwardʹ��marsioģʽ, + mbuff����ֱ�Ӹ���, ������һ��malloc/memcpy/free�Ĺ���. + */ + send_device_handle->low_level_mbuff_data_append(send_mbuff, unsend_raw_data_ptr, unsend_raw_data_len); + + /* ָ����ǰ�ƶ�, Ԥ��vxlan���ռ� */ + send_buf_data_ptr = (char *)send_device_handle->low_level_mbuff_data_forward(send_mbuff, FLWD_VXLAN_OUTER_PACKET_LEN); + + /* ����ײ�vxlan��Ϣ, ���迼�Ƿ������, ��Ϊ�����ڲ���Ԫ��hash����, vxlan����ַ����·��Ѱַ���� */ + +#if FLWD_NO_ACTIVE_ARP_QUERY + local_acc_gateway_mac = send_device_handle->io_para.local_mac_addr; + unsigned char remote_fwd_gateway_mac[6] = {0x0c, 0xc4,0x7a,0x14,0x6f,0x5a}; /* 10.0.6.203 */ + flwd_sendpacket_build_ethernet(ETH_P_IP, local_acc_gateway_mac, remote_fwd_gateway_mac, send_buf_data_ptr); +#else + if(send_device_handle->io_para.cap_mode != CAP_MODEL_SOCKET){ /* ��socketģʽ����Ҫ����vxlan����ethernet�� */ + local_acc_gateway_mac = send_device_handle->io_para.local_mac_addr; + + ip_union.addr_type = FLWD_IP_ADDR_TYPE_V4; + ip_union.addr_ipv4 = nat_info->flwd_route_info.next_gateway_ip_net; + + if(memcmp(nat_info->flwd_route_info.next_gateway_mac, flwd_global_val.zero_mac_addr, 6) == 0){ + /* �˴�������MAC���浽nat_info, ����ÿ�ζ���arp�� */ + ret = flwd_arp_table_query(nat_info->tid, &ip_union, send_device_handle, nat_info->flwd_route_info.next_gateway_mac); + if(ret < 0){ + send_device_handle->low_level_mbuff_free(send_device_handle, tid, send_mbuff); + flwd_log(30, "arp query %s, but not found!\n", flwd_ipt_ntop_r(&ip_union, ip_str, 64)); + return NULL; + } + } + + /* ���ݻ�ԾIP�IJ���ʱ��gdevIP, ��ѯGDEV��MAC, ����ethernet header */ + unsigned char *remote_fwd_gateway_mac = nat_info->flwd_route_info.next_gateway_mac; + flwd_sendpacket_build_ethernet(ETH_P_IP, local_acc_gateway_mac, remote_fwd_gateway_mac, send_buf_data_ptr); + } + +#endif + + /* NOTE, ��ʹ��socketģʽ, ����Ҫ����ײ�vxlanԭʼ��, ��DIP, PORT���ܶ���һ��, ����Щֵ���Ƿ�װ�����ݰ���, ��dl_io_send�Ӱ���ȡ */ +#if FLWD_NO_GDEV_ENV + flwd_sendpacket_build_ipv4(unsend_raw_data_len + sizeof(flwd_udp_hdr_t) + sizeof(flwd_vxlan_hdr_t), /* �ڲ�ԭʼ�� + UDP��ͷ + vxlanͷ */ + 0, + 0x1234, + 0, + 64, + IPPROTO_UDP, + send_device_handle->io_para.device_ip_net_order, + nat_info->flwd_route_info.next_gateway_ip_net, + NULL, + 0, + (char *)send_buf_data_ptr + sizeof(flwd_eth_hdr_t)); +#else + flwd_sendpacket_build_ipv4(unsend_raw_data_len + sizeof(flwd_udp_hdr_t) + sizeof(flwd_vxlan_hdr_t), /* �ڲ�ԭʼ�� + UDP��ͷ + vxlanͷ */ + 0, + 0x1234, + 0, + 64, + IPPROTO_UDP, + 0x0100007F, /* ����socket */ + 0x0100007F, /* ����socket */ + NULL, + 0, + (char *)send_buf_data_ptr + sizeof(flwd_eth_hdr_t)); +#endif + + flwd_sendpacket_build_udp(unsend_raw_data_len + sizeof(flwd_vxlan_hdr_t), + htons(50000 + tid), /* TODO, �˴���sport�����ڲ��sport, �ڲ�sport��ȫ��ʶ��ij���������ص�, vxlan��sport�������� */ + htons(60000 + tid), + NULL, + 0, + send_buf_data_ptr + sizeof(flwd_eth_hdr_t) + sizeof(flwd_ipv4_hdr_t)); + + if(CAP_MODEL_SOCKET != send_device_handle->io_para.cap_mode){ /* socketģʽ�ײ���Э��ջ��װ, У�����Э��ջʵ�� */ + flwd_sendpacket_do_checksum((char *)send_buf_data_ptr + sizeof(flwd_eth_hdr_t), + IPPROTO_IP, + sizeof(flwd_ipv4_hdr_t)); + } + + outer_vxlan_hdr = (flwd_vxlan_hdr_t *)(send_buf_data_ptr + sizeof(flwd_eth_hdr_t) + sizeof(flwd_ipv4_hdr_t) + sizeof(flwd_udp_hdr_t)); + memset(outer_vxlan_hdr, 0, sizeof(flwd_vxlan_hdr_t)); + outer_vxlan_hdr->link_id = nat_info->flwd_route_info.gdev_args.link_id; + outer_vxlan_hdr->link_layer_type = 0; /* 0:ethernet; */ + outer_vxlan_hdr->dir = nat_info->flwd_route_info.gdev_args.this_ip_as_sip_route_dir; + if(FLWD_OUTOPT_FIRST_PKT == (out_opt & FLWD_OUTOPT_FIRST_PKT)){ + outer_vxlan_hdr->first_pkt_per_stream = 1; + } + + inner_eth_hdr = (flwd_eth_hdr_t *)(send_buf_data_ptr + sizeof(flwd_eth_hdr_t) + sizeof(flwd_ipv4_hdr_t) + sizeof(flwd_udp_hdr_t) + sizeof(flwd_vxlan_hdr_t)); + memcpy(inner_eth_hdr->h_source, nat_info->flwd_route_info.gdev_args.inner_raw_smac, 6); + memcpy(inner_eth_hdr->h_dest , nat_info->flwd_route_info.gdev_args.inner_raw_dmac, 6); + + if(FLWD_IP_ADDR_TYPE_V4 == nat_info->inner_nat_tuple5.addr_type){ + inner_eth_hdr->h_proto = htons(ETH_P_IP); + }else{ + inner_eth_hdr->h_proto = htons(ETH_P_IPV6); + } + + return send_mbuff; +} + +static void * flwd_acc_to_user_pre_output(flwd_device_handle_t *rcv_device_handle, + flwd_device_handle_t *send_device_handle, int tid, flwd_nat_info_t *nat_info, + flwd_raw_pkt_t *raw_pkt, unsigned int out_opt) +{ + flwd_vxlan_hdr_t *outer_vxlan_dr; + + const char *unsend_raw_data_ptr = raw_pkt->inner_pkt_data; /* ��ָ����flwd_acc_fwd_pkt_input()����, �Ѿ�ָ�����ڲ�ethernetͷ�� */ + int unsend_raw_data_len = raw_pkt->inner_pkt_len; + void *send_mbuff = send_device_handle->low_level_mbuff_malloc(send_device_handle, tid, unsend_raw_data_len + FLWD_VXLAN_OUTER_PACKET_LEN); + char *send_buf_data_ptr; + + /* �����վ���Ļ�����copy�������;���Ļ�����, �����߲���ģʽ���ܲ�һ��, ����ֱ�Ӹ���, ������һ��malloc/memcpy/free�Ĺ��� */ + send_buf_data_ptr = send_device_handle->low_level_mbuff_data_append(send_mbuff, unsend_raw_data_ptr, unsend_raw_data_len); + +#if FLWD_NO_ACTIVE_ARP_QUERY + /* û��ARP��̬��ѯ�Ĺ���ʱ, �ֹ����²����ն˵�mac */ + unsigned char *local_acc_gateway_mac = send_device_handle->io_para.local_mac_addr; + unsigned char *remote_user_mac = nat_info->flwd_route_info.inner_terminal_mac; + + flwd_sendpacket_build_ethernet(ETH_P_IP, local_acc_gateway_mac, remote_user_mac, send_buf_data_ptr); +#else + /* û��ARP��̬��ѯ�Ĺ���ʱ, �ֹ����²����ն˵�mac */ + unsigned char *local_acc_gateway_mac = send_device_handle->io_para.local_mac_addr; + unsigned char *remote_user_mac = nat_info->flwd_route_info.inner_terminal_mac; + + flwd_sendpacket_build_ethernet(ETH_P_IP, local_acc_gateway_mac, remote_user_mac, send_buf_data_ptr); +#endif + + return send_mbuff; +} + + +/* + TODO: + ��ϵͳ����������������ʵ��L2TP, PPTP��������, + ��Iptables ��ppp�������һ������ָ��(�ض���)��һ��tap�豸, + ����, tap�豸�Ķ�ȡ��(��������), ���ܿ��������ڲ���ip��, + �յ�ip�����acc-userһ���Ĵ�������. + + ����: + acc-userֻ��һ��io_handle, Ŀǰ��pcap, marsio, socket, ��tap, + ������pcap��tap�ľ�����Բ�һ��, + + �����ʽ: + 1, һ��Flowood_IO���(�ĸ�����, acc-user, acc-fwd, fwd-acc, fwd-gdev), �ɶ�Ӧ�������IO���, + ��acc-user�����IO�����������������IO���, ��������ͬ�Ľ��뷽ʽ: pcap, l2tp_tap, pptp_tap, + �����������Ľ����ij�; + + 2, ����Ǹ���һ������, ������������Ƕ��, ��ʵ�ʴ�һ����������; + ��acc-user, acc-fwd����һ���������ӵ�������, + Flowood���������, ��ʵ��������һ��, ��ʱӦ�ÿ���ͬ��IP��������, + ��һ���������IP��ַ, �����ݰ���dip�����ĸ���acc-user�İ�, �ĸ���acc-fwd�İ�. + +*/ + +static int flwd_access_output(flwd_device_handle_t *rcv_device_handle, int tid, + flwd_nat_info_t *nat_info, flwd_raw_pkt_t *raw_pkt, unsigned int out_opt) +{ + int ret; + flwd_device_handle_t *send_device_handle; + void *send_mbuff ; + const char *send_actual_ptr; + char debug_outer_tuple4[128]; + + /* + TODO, + + ACC��USERת������ʱ, �������ͨIPЭ��ջ, ����ͨ��low_level_io_send()ֱ�ӽ�������ȥ, + ���п��ܻ���PPTP����, ��ʱ�����ݰ������ڲ����һ����, ���PPP��װ��Ҫ��VPN�������, + ��Ҫע�����������, ������ͨ���ײ�IO�ӿ�ֱ�ӷ��ͳ�����. + + Ӧ�������ֵײ������ӿ�, ���pcap, marsio, socket��ϵͳ��ʽ, + ���ӿ�, ��һ������������IP, ��������������, + ������L2TP, PPTP������, ��ԭʼ�������յ�PPP�İ���, ���ջ�������ڲ�IP��, + + �������������һ�Զ�Ĺ�ϵ, ��ʹ����һ���ӿ�, Ҳ���������һ������, + flowood������������ͨ��, ����ֱ�Ӷ�������. + */ + + if(TOPO_ACC_LINK_USER == rcv_device_handle->io_para.topo_mode){ + send_device_handle = &flwd_global_val.global_io_handle[TOPO_ACC_LINK_FWD]; + send_mbuff = flwd_acc_to_fwd_pre_output(rcv_device_handle, send_device_handle, tid, nat_info, raw_pkt, out_opt); + if(NULL == send_mbuff){ + return -1; + } + ret = send_device_handle->low_level_send(send_device_handle, tid, send_mbuff); + if(ret < 0){ + send_actual_ptr = (char *)rcv_device_handle->low_level_mbuff_mtod(send_mbuff); + flwd_log(30, "ACC: send pkt to forward gateway error! inner_tuple4 is:%s, outer_tuple4 is:%s\n", + flwd_debug_print_tuple4_detail(send_actual_ptr+FLWD_VXLAN_OUTER_PACKET_LEN+sizeof(flwd_eth_hdr_t), tid), + flwd_debug_print_tuple4_detail_r(send_actual_ptr + sizeof(flwd_eth_hdr_t), debug_outer_tuple4, 128)); + }else{ + if(flwd_cfg_val.flwd_log_level <= 10){ + send_actual_ptr = (char *)rcv_device_handle->low_level_mbuff_mtod(send_mbuff); + flwd_log(10, "ACC: send pkt to forward gateway succ, inner_tuple4 is:%s, outer_tuple4 is:%s\n", + flwd_debug_print_tuple4_detail(send_actual_ptr+FLWD_VXLAN_OUTER_PACKET_LEN+sizeof(flwd_eth_hdr_t), tid), + flwd_debug_print_tuple4_detail_r(send_actual_ptr + sizeof(flwd_eth_hdr_t), debug_outer_tuple4, 128)); + } + } + + }else{ + send_device_handle = &flwd_global_val.global_io_handle[TOPO_ACC_LINK_USER]; + send_mbuff = flwd_acc_to_user_pre_output(rcv_device_handle, send_device_handle, tid, nat_info, raw_pkt, out_opt); + ret = send_device_handle->low_level_send(send_device_handle, tid, send_mbuff); + if(ret < 0){ + send_actual_ptr = (char *)rcv_device_handle->low_level_mbuff_mtod(send_mbuff); + flwd_log(30, "ACC: send pkt to user client error! tuple4 is:%s\n", + flwd_debug_print_tuple4_detail(send_actual_ptr+sizeof(flwd_eth_hdr_t), tid)); + }else{ + if(flwd_cfg_val.flwd_log_level <= 10){ + send_actual_ptr = (char *)rcv_device_handle->low_level_mbuff_mtod(send_mbuff); + flwd_log(10, "ACC: send pkt to user client succ! tuple4 is:%s\n", + flwd_debug_print_tuple4_detail(send_actual_ptr+sizeof(flwd_eth_hdr_t), tid)); + + } + } + } + + send_device_handle->low_level_mbuff_free_after_send(send_device_handle, tid, send_mbuff); + + return ret; +} + + +/* + ���ӽ�����, �ͷ�ռ�û�ԾIP��Դ�˿�. +*/ +static void flwd_sport_recycle(flwd_nat_info_t *nat_info) +{ + /* ����nat����, snat����outer->tuple5��sip, ����ʵ����ԴIP; + dnatû�ж��������Դ, ֻ�ǼĽ�virtual_dip:virtual_dport�ij���real_dip:real_dport. + */ + MESA_list_count_t *usable_sport_queue_head; + MESA_list_count_t *recycle_node; + unsigned char *ip_key; + unsigned int ip_key_size; + MESA_htable_handle act_ip_htable; + int tid = nat_info->tid; + const flwd_tuple5_t *recycle_tuple5; + unsigned short recycle_sport; + char ip_str[64]; + + if(FLWD_NAT_TYPE_DNAT == nat_info->nat_type){ + return; /* nothing to do */ + } + + if(FLWD_NAT_TYPE_SNAT == nat_info->nat_type){ + recycle_tuple5 = &nat_info->outer_nat_tuple5; + } + + if(flwd_likely(FLWD_IP_ADDR_TYPE_V4 == nat_info->inner_nat_tuple5.addr_type)){ + if(FLWD_ACT_IP_DYNAMIC == nat_info->act_ip_origin){ + act_ip_htable = flwd_thread_val[tid].flwd_ip_pool_dynamic_htable[FLWD_IP_ADDR_TYPE_V4][nat_info->act_ip_region]; + }else{ + act_ip_htable = flwd_thread_val[tid].flwd_ip_pool_static_htable[FLWD_IP_ADDR_TYPE_V4][nat_info->act_ip_region]; + } + + if(recycle_tuple5->dir_reverse){ + ip_key = (unsigned char *)&recycle_tuple5->ippair_v4.dip_net_order; + recycle_sport = recycle_tuple5->dport_net_order; + }else{ + ip_key = (unsigned char *)&recycle_tuple5->ippair_v4.sip_net_order; + recycle_sport = recycle_tuple5->sport_net_order; + } + ip_key_size = sizeof(int); + }else{ /* IPv6 */ + if(FLWD_ACT_IP_DYNAMIC == nat_info->act_ip_origin){ + act_ip_htable = flwd_thread_val[tid].flwd_ip_pool_dynamic_htable[FLWD_IP_ADDR_TYPE_V6][nat_info->act_ip_region]; + }else{ + act_ip_htable = flwd_thread_val[tid].flwd_ip_pool_static_htable[FLWD_IP_ADDR_TYPE_V6][nat_info->act_ip_region]; + } + + if(recycle_tuple5->dir_reverse){ + ip_key = (unsigned char *)&recycle_tuple5->ippair_v6->dip_net_order; + recycle_sport = recycle_tuple5->dport_net_order; + }else{ + ip_key = (unsigned char *)&recycle_tuple5->ippair_v6->sip_net_order; + recycle_sport = recycle_tuple5->sport_net_order; + } + ip_key_size = sizeof(struct in6_addr); + } + + if(sizeof(int) == ip_key_size){ + inet_ntop(AF_INET, ip_key, ip_str, 64); + }else{ + inet_ntop(AF_INET6, ip_key, ip_str, 64); + } + + pthread_rwlock_wrlock(&flwd_thread_val[tid].flwd_ip_pool_static_rwlock); + + flwd_active_ip_t *flwd_active_ip = (flwd_active_ip_t *)flwd_ip_pool_search(nat_info->act_ip_origin, act_ip_htable, ip_key, ip_key_size); + if(NULL == flwd_active_ip){ + /* NOTE: �������ڼ�˻�ԾIP�Ѿ���ʱ��maat_callback�Ƴ�, Ҳ�Ͳ��ػ��ն˿�, ֱ�ӷ��ؼ��� */ + flwd_log(20, "ACC:sport %u recycle, but active ip:%s is not exist!\n", recycle_sport, ip_str); + goto done; + } + + if(IPPROTO_TCP == nat_info->inner_nat_tuple5.protocol){ /* TCP, UDP������ */ + usable_sport_queue_head = &flwd_active_ip->usable_tcp_sport_list_head; + }else{ + usable_sport_queue_head = &flwd_active_ip->usable_udp_sport_list_head; + } + + /* NOTE: ȡ���ö˿�ʱ�ֳ�free��MESA_list_count_t�����ṹ, �˴�Ҳ���ֳ�malloc */ + recycle_node = (MESA_list_count_t *)malloc(sizeof(MESA_list_count_t)); + memcpy(&recycle_node->quiddity, &recycle_sport, sizeof(short)); + /* �˴�ʹ��MESA_list_count_add_tail, ����head->pre, ���ʹ�� */ + MESA_list_count_add_tail(usable_sport_queue_head, recycle_node); + +done: + pthread_rwlock_unlock(&flwd_thread_val[tid].flwd_ip_pool_static_rwlock); + + flwd_log(10, "ACC:sport recycle, active_ip:%s, port:%u\n", ip_str, recycle_sport); + + return; +} + + +static void flwd_access_nat_htable_data_free(void *data) +{ + flwd_nat_info_t *nat_info = (flwd_nat_info_t *)data; + + if(--nat_info->reference > 0){ + /* ����key����ͬһ��nat_info, ɾ��ʱ����double free, ����reference���� */ + return; + } + + flwd_sport_recycle(nat_info); + + if(FLWD_IP_ADDR_TYPE_V6 == nat_info->inner_nat_tuple5.addr_type ){ + flwd_free(nat_info->tid, nat_info->inner_nat_tuple5.ippair_v6); + } + + if(FLWD_IP_ADDR_TYPE_V6 == nat_info->outer_nat_tuple5.addr_type ){ + flwd_free(nat_info->tid, nat_info->outer_nat_tuple5.ippair_v6); + } + +#if FLWD_USE_LTSM_FOR_QUICK_CLOSE + ltsm_destroy_handle(nat_info->ltsm_stat_handle); +#endif + + flwd_free(nat_info->tid, data); +} + +static int flwd_access_nat_htable_data_expire_notify( + void *data, int eliminate_type) +{ + char str_tmp[256]; + flwd_nat_info_t *nat_info = (flwd_nat_info_t *)data; + + if(1 == nat_info->reference){ /* ��Ϊͬʱ������key����, ֻ���һ�μ�¼��־, �����д����һ������־ */ + flwd_log(10, "pre-nat-tuple4 %s expire!\n", + flwd_tuple5_ntop_r(&nat_info->inner_nat_tuple5, str_tmp, 256)); + } + + return 1; +} + + + +/* + natת����������, ��һ�δ���nat_infoʱ������, + �洢·��ת�������Ϣ, ����ÿ��ת��ʱ����ѯһ��. +*/ +static int flwd_save_session_route_info(flwd_nat_info_t *nat_info, + flwd_raw_pkt_t *raw_pkt, flwd_active_ip_port_args_t *usable_active_ipport_args) +{ + const flwd_eth_hdr_t *ehdr = (flwd_eth_hdr_t *)raw_pkt->outer_pkt_data; + int ret; + + if(FLWD_NAT_TYPE_SNAT == nat_info->nat_type){ + /* user�ն˵�MAC���ò�ѯ, ֱ��ʹ�õ�ǰ������mac�洢�������� */ + memcpy(nat_info->flwd_route_info.inner_terminal_mac, ehdr->h_source, ETH_ALEN); + /* + TODO: + ��εõ���һ��ת�����ص�IP, ��ת������IP? + ������ͬһ���ֵ�������豸������ͨ��, ��ѡһ���Ϳ���, + ��������ɵ�����, + �����֪��GDEV�ķ����㷨�����. + */ +#if 0 + nat_info->flwd_route_info.next_gateway_ip_net = flwd_search_fwd_ip_by_gdev_ip(usable_active_ipport_args->gdev_args.gdev_ip_net_order); +#else + /* TODO, ��̨����, ��д��, ʹ�ñ��ػػ� */ + inet_pton(AF_INET, "127.0.0.1", &nat_info->flwd_route_info.next_gateway_ip_net); +#endif + + memcpy(&nat_info->flwd_route_info.gdev_args, + &usable_active_ipport_args->gdev_args, + sizeof(flwd_gdev_associated_args_t)); + }else{ + /* TODO, DNAT */ + abort(); + } + + return 0; +} + + +/* + NOTE: + + HASH����ʱ, + ��ΪSNAT->C2S����, SNAT->S2C����, DNAT->C2S����, DNAT->S2C����, + ��������ĵ�ַ��ͬ, + ����, ����һ�����ӵ��ڲ���ַ���ⲿ��ַ��˵, Ҫ��������key, ָ��ͬһ��nat_info. + + hash����ʱ, ����ͬһ��nat_info, ʹ��������ͬ��key����. + + ����: + 192.168.10.100:12345->8.8.8.8:53����һ��DNS��ѯ, + ��NAT���غ�����: + 202.43.148.189:34567->8.8.8.8:53, + + Ҫ������������ͬ����Ԫ��ֱ���Ϊkey, �����ҵ�ͬһ��htable���data, ��nat_info. +*/ +static int flwd_new_nat_session_sotre(int tid, flwd_nat_info_t *nat_info) +{ + int ret; + char inner_str[256], outer_str[256]; + + ret = MESA_htable_add(flwd_thread_val[tid].nat_info_table, + (unsigned char *)&nat_info->inner_nat_tuple5, + sizeof(flwd_tuple5_t), + nat_info); + if(ret < 0){ + flwd_log(30, "save nat session error, %s!\n", + flwd_tuple5_ntop_r(&nat_info->inner_nat_tuple5, inner_str, 256)); + nat_info->reference = 1; + flwd_access_nat_htable_data_free(nat_info); + return -1; + } + nat_info->reference++; + + ret = MESA_htable_add(flwd_thread_val[tid].nat_info_table, + (unsigned char *)&nat_info->outer_nat_tuple5, + sizeof(flwd_tuple5_t), + nat_info); + if(ret < 0){ + nat_info->reference = 1; + flwd_log(30, "save nat session error, %s!\n", + flwd_tuple5_ntop_r(&nat_info->outer_nat_tuple5, outer_str, 256)); + /* NOTE: ����ʧ��, �˴�Ҫʹ��inner��key, ��Ϊouter����ʧ�� */ + MESA_htable_del(flwd_thread_val[tid].nat_info_table, + (unsigned char *)&nat_info->inner_nat_tuple5, + sizeof(flwd_tuple5_t), + NULL); + return -1; + } + nat_info->reference++; + + return 0; +} + + +static inline flwd_nat_info_t *flwd_create_new_nat_info_v4(int tid, + flwd_nat_type_t nat_type, flwd_tuple5_t *inner_nat_key, + flwd_active_ip_port_args_t *usable_active_ipport_args, flwd_raw_pkt_t *raw_pkt) +{ + flwd_nat_info_t *nat_info = (flwd_nat_info_t *)flwd_calloc(tid, 1, sizeof(flwd_nat_info_t)); + flwd_tuple5_t *opposite_tuple5; + int differ; + unsigned int outer_actual_dip_net_order; /* �ͻ���ȥ����ʵ��Ŀ��IP, inner��outer��һ����, ����key�Ĵ洢λ��, ��sip,dip�Ĵ�С��ϵ���ܲ�һ�� */ + unsigned int outer_actual_dport_net_order; /* �ͻ���ȥ����ʵ��Ŀ��˿�, inner��outer��һ����, ����key�Ĵ洢λ��, ��sip,dip�Ĵ�С��ϵ���ܲ�һ�� */ + + nat_info->tid = tid; /* ��Ҫ����htable�ص������ڲ���tid�������� */ + nat_info->nat_type = nat_type; + + if(FLWD_NAT_TYPE_SNAT == nat_type){ + /************************** ���� inner tuple5 **************************/ + memcpy(&nat_info->inner_nat_tuple5, inner_nat_key, sizeof(flwd_tuple5_t)); /* snat��inner tuple5ֱ��copy */ + + + /*************************** ����outer tuple5 **************************/ + opposite_tuple5 = &nat_info->outer_nat_tuple5; + + if(inner_nat_key->dir_reverse){ + outer_actual_dip_net_order = inner_nat_key->ippair_v4.sip_net_order; + outer_actual_dport_net_order = inner_nat_key->sport_net_order; + }else{ + outer_actual_dip_net_order = inner_nat_key->ippair_v4.dip_net_order; + outer_actual_dport_net_order = inner_nat_key->dport_net_order; + } + + /* NOTE: �������������Ƚϴ�С, һ��Ҫֱ�ӱȽ�, ������ c = a - b; if(c < 0)�ķ�ʽ!!! */ + if(usable_active_ipport_args->act_sip_net_order.addr_ipv4 > outer_actual_dip_net_order){ + /* �ⲿ��ַ����ʵԴIP�Ǹ�ѡ��Ļ�ԾIP, ��ʵĿ��IP���ǵ�ǰinner_key��Ŀ��ip */ + opposite_tuple5->ippair_v4.sip_net_order = usable_active_ipport_args->act_sip_net_order.addr_ipv4; + opposite_tuple5->ippair_v4.dip_net_order = outer_actual_dip_net_order; + opposite_tuple5->sport_net_order = usable_active_ipport_args->act_sport_net_order; + opposite_tuple5->dport_net_order = outer_actual_dport_net_order; + + opposite_tuple5->dir_reverse = 0; /* �洢��key����ʵ��Ԫ���ַ��һ���� */ + }else if(usable_active_ipport_args->act_sip_net_order.addr_ipv4 < outer_actual_dip_net_order){ + opposite_tuple5->ippair_v4.sip_net_order = outer_actual_dip_net_order; + opposite_tuple5->ippair_v4.dip_net_order = usable_active_ipport_args->act_sip_net_order.addr_ipv4; + opposite_tuple5->sport_net_order = outer_actual_dport_net_order; + opposite_tuple5->dport_net_order = usable_active_ipport_args->act_sport_net_order; + + opposite_tuple5->dir_reverse = 1; /* �洢��key����ʵ��Ԫ���ַ���෴�� */ + }else{ + /* inner��outer��IP��ַ��ͬ, ��������IP����ϵͳ���Dz����ܵ�!!! */ + abort(); + } + + opposite_tuple5->addr_type = inner_nat_key->addr_type; /* TODO, Ԥ��6to4��ַת������?? */ + opposite_tuple5->protocol = inner_nat_key->protocol; + + /* TODO, ����ѡ��Ļ�ԾIP, �������, ȷ��Ӧ�ô��ĸ�FWD���� */ + ////nat_info->next_hop_ip_net_order = flwd_search_fwd_ip_by_gdev_ip(usable_active_ipport_args->related_gdev_ip_net_order); + }else{ +#if FLWD_SUPPORT_DNAT + /* TODO, + DNATֻ����滻dip, dport����, ���ÿ�����ô��ѡ�˿�, �˿ڸ�������, + ��Ϊ����һ���������, ��ʵԴIP,Դport�Ѿ�������������Э��ջ��֤��ͻ��. + */ + assert(0); +#endif + } + + flwd_save_session_route_info(nat_info, raw_pkt, usable_active_ipport_args); + + return nat_info; +} + + +static inline flwd_nat_info_t *flwd_create_new_nat_info_v6(int tid, + flwd_nat_type_t nat_type, flwd_tuple5_t *inner_tuple5_v6, + flwd_active_ip_port_args_t *usable_active_ipport_args, flwd_raw_pkt_t *raw_pkt) +{ + flwd_nat_info_t *nat_info = (flwd_nat_info_t *)flwd_calloc(tid, 1, sizeof(flwd_nat_info_t)); + flwd_tuple5_t *opposite_tuple5; + int differ; + struct in6_addr outer_actual_dip_net_order; /* �ͻ���ȥ����ʵ��Ŀ��IP, inner��outer��һ����, ����key�Ĵ洢λ��, ��sip,dip�Ĵ�С��ϵ���ܲ�һ�� */ + unsigned int outer_actual_dport_net_order; /* �ͻ���ȥ����ʵ��Ŀ��˿�, inner��outer��һ����, ����key�Ĵ洢λ��, ��sip,dip�Ĵ�С��ϵ���ܲ�һ�� */ + + nat_info->tid = tid; /* ��Ҫ����htable�ص������ڲ���tid�������� */ + nat_info->nat_type = nat_type; + + nat_info->inner_nat_tuple5.ippair_v6 = (flwd_ippair_v6_t *)flwd_malloc(tid, sizeof(flwd_ippair_v6_t)); + nat_info->outer_nat_tuple5.ippair_v6 = (flwd_ippair_v6_t *)flwd_malloc(tid, sizeof(flwd_ippair_v6_t)); + + if(FLWD_NAT_TYPE_SNAT == nat_type){ + /********* ���� inner tuple5 ******/ + memcpy(&nat_info->inner_nat_tuple5, inner_tuple5_v6, sizeof(flwd_tuple5_t)); /* snat��inner tuple5ֱ��copy */ + memcpy(nat_info->inner_nat_tuple5.ippair_v6, inner_tuple5_v6->ippair_v6, sizeof(flwd_ippair_v6_t)); + + opposite_tuple5 = &nat_info->outer_nat_tuple5; + /********* ����outer tuple5 ******/ + + if(inner_tuple5_v6->dir_reverse){ + outer_actual_dip_net_order = inner_tuple5_v6->ippair_v6->sip_net_order; + outer_actual_dport_net_order = inner_tuple5_v6->sport_net_order; + }else{ + outer_actual_dip_net_order = inner_tuple5_v6->ippair_v6->dip_net_order; + outer_actual_dport_net_order = inner_tuple5_v6->dport_net_order; + } + + differ = memcmp(&usable_active_ipport_args->act_sip_net_order.addr_ipv6, &outer_actual_dip_net_order, sizeof(struct in6_addr)) ; + if(differ > 0){ /* �ⲿ��ַ����ʵԴIP�Ǹ�ѡ��Ļ�ԾIP, ��ʵĿ��IP���ǵ�ǰinner_key��Ŀ��ip */ + memcpy(&opposite_tuple5->ippair_v6->sip_net_order, &usable_active_ipport_args->act_sip_net_order.addr_ipv6, sizeof(struct in6_addr)); + memcpy(&opposite_tuple5->ippair_v6->dip_net_order, &outer_actual_dip_net_order, sizeof(struct in6_addr)); + opposite_tuple5->sport_net_order = usable_active_ipport_args->act_sport_net_order; + opposite_tuple5->dport_net_order = outer_actual_dport_net_order; + + opposite_tuple5->dir_reverse = 0; /* �洢��key����ʵ��Ԫ���ַ��һ���� */ + }else if(differ < 0){ + memcpy(&opposite_tuple5->ippair_v6->sip_net_order, &outer_actual_dip_net_order, sizeof(struct in6_addr)); + memcpy(&opposite_tuple5->ippair_v6->dip_net_order, &usable_active_ipport_args->act_sip_net_order.addr_ipv6, sizeof(struct in6_addr)); + opposite_tuple5->sport_net_order = outer_actual_dport_net_order; + opposite_tuple5->dport_net_order = usable_active_ipport_args->act_sport_net_order; + + opposite_tuple5->dir_reverse = 1; /* �洢��key����ʵ��Ԫ���ַ���෴�� */ + }else{ + /* inner��outer��IP��ַ��ͬ, ��������flowoodϵͳ���Dz����ܵ�!!! */ + abort(); + } + + opposite_tuple5->addr_type = inner_tuple5_v6->addr_type; /* TODO, Ԥ��6to4��ַת������, �ⲿ��ַ�����Ǹ��ݲ��Եõ�, ��һ���ǹ̶���ipv4תipv4 */ + opposite_tuple5->protocol = inner_tuple5_v6->protocol; + + ////nat_info->next_hop_ip_net_order = flwd_search_fwd_ip_by_gdev_ip(usable_active_ipport_args->related_gdev_ip_net_order); /* TODO, ����ѡ��Ļ�ԾIP, �������, ȷ��Ӧ�ô��ĸ�FWD���� */ + + }else{ +#if FLWD_SUPPORT_DNAT + assert(0); +#endif + } + + flwd_save_session_route_info(nat_info, raw_pkt, usable_active_ipport_args); + + return nat_info; +} + + + +static flwd_nat_info_t *flwd_create_new_nat_info(int tid, + flwd_nat_type_t nat_type, flwd_tuple5_t *inner_nat_key, + flwd_active_ip_port_args_t *usable_active_ipport_args, flwd_raw_pkt_t *raw_pkt) +{ + flwd_nat_info_t *nat_info; + + if(flwd_likely(FLWD_IP_ADDR_TYPE_V4 == inner_nat_key->addr_type)){ + nat_info = flwd_create_new_nat_info_v4(tid, nat_type, inner_nat_key, + usable_active_ipport_args, raw_pkt); + }else{ + nat_info = flwd_create_new_nat_info_v6(tid, nat_type, inner_nat_key, + usable_active_ipport_args, raw_pkt); + } + + if(FLWD_IP_REGION_INLAND == usable_active_ipport_args->dip_region_type){ + nat_info->act_ip_region = FLWD_IP_REGION_OUTLAND; + }else{ + nat_info->act_ip_region = FLWD_IP_REGION_INLAND; + } + + nat_info->nat_type = nat_type; + +#if FLWD_USE_LTSM_FOR_QUICK_CLOSE + nat_info->ltsm_stat_handle = ltsm_create_handle(); +#endif + return nat_info; +} + + + +static flwd_nat_info_t * flwd_new_nat_session(flwd_device_handle_t *device_handle, + int tid, flwd_tuple5_t *nat_key, flwd_raw_pkt_t *raw_pkt) +{ + int ret; + flwd_nat_info_t *nat_info = NULL; + flwd_active_ip_port_args_t usable_active_ipport_args; + flwd_actual_ip_port_t actual_ipport_net_order; + + memset(&usable_active_ipport_args, 0, sizeof(flwd_active_ip_port_args_t)); + + usable_active_ipport_args.dip_region_type = flwd_dstip_location(nat_key); /* �鿴Ŀ��IP��������λ�� */ + usable_active_ipport_args.tid = tid; + usable_active_ipport_args.nat_key = nat_key; + usable_active_ipport_args.protocol = nat_key->protocol; + + if(TOPO_ACC_LINK_USER == device_handle->io_para.topo_mode){ + /* ACC_LINK�ӿ�, NATת����������, �϶���SNAT���װ�, �Ȳ���NAT���ò��� */ + ret = flwd_access_snat_search_policy(tid, nat_key, &usable_active_ipport_args); + if(0 == ret){ + /* ����, ��dynamic-ip-pool�������ѡһ��IP */ + ret = flwd_access_snat_fetch_usable_ip_from_pool(flwd_thread_val[tid].flwd_ip_pool_dynamic_htable[nat_key->addr_type][(int)usable_active_ipport_args.dip_region_type ^ 1], + &flwd_thread_val[tid].flwd_ip_pool_dynamic_rwlock, + tid, nat_key, &usable_active_ipport_args); + if(ret < 0){ + flwd_log(RLOG_LV_INFO, "tuple4 %s not hit any policy, but no according usable active ip in %s dynamic pool !\n", + flwd_tuple5_ntop(tid, nat_key), + flwd_ip_region_ntop((int)usable_active_ipport_args.dip_region_type ^ 1)); + + if(flwd_cfg_val.use_static_pool_ip_if_no_dynamic != 0){ + ret = flwd_access_snat_fetch_usable_ip_from_pool(flwd_thread_val[tid].flwd_ip_pool_static_htable[nat_key->addr_type][(int)usable_active_ipport_args.dip_region_type ^ 1], + &flwd_thread_val[tid].flwd_ip_pool_static_rwlock, + tid, nat_key, &usable_active_ipport_args); + if(ret < 0){ + flwd_log(RLOG_LV_FATAL, "tuple4 %s not hit any policy, but no according usable ip in all %s static and dynamic pool!\n", + flwd_tuple5_ntop(tid, nat_key), + flwd_ip_region_ntop((int)usable_active_ipport_args.dip_region_type ^ 1)); + return NULL; + } + }else{ + flwd_log(RLOG_LV_FATAL, "tuple4 %s not hit any policy, but no according usable active ip in %s dynamic pool, unfortunately 'use_static_pool_ip_if_no_dynamic' is disable!\n", + flwd_tuple5_ntop(tid, nat_key), + flwd_ip_region_ntop((int)usable_active_ipport_args.dip_region_type ^ 1)); + return NULL; + } + } + }else if(-1 == ret){ + if(flwd_cfg_val.use_dynamic_pool_ip_if_no_static != 0){ + ret = flwd_access_snat_fetch_usable_ip_from_pool(flwd_thread_val[tid].flwd_ip_pool_static_htable[nat_key->addr_type][(int)usable_active_ipport_args.dip_region_type ^ 1], + &flwd_thread_val[tid].flwd_ip_pool_static_rwlock, + tid, nat_key, &usable_active_ipport_args); + if(ret < 0){ + flwd_log(RLOG_LV_FATAL, "tuple4 %s hit policy, but no according usable ip in all %s static and dynamic pool!\n", + flwd_tuple5_ntop(tid, nat_key), + flwd_ip_region_ntop((int)usable_active_ipport_args.dip_region_type ^ 1)); + return NULL; + } + }else{ + flwd_log(RLOG_LV_FATAL, "tuple4 %s hit policy, but no according usable ip in %s static pool, unfortunately 'use_dynamic_pool_ip_if_no_static' is disable!\n", + flwd_tuple5_ntop(tid, nat_key), + flwd_ip_region_ntop((int)usable_active_ipport_args.dip_region_type ^ 1)); + return NULL; + } + } + + nat_info = flwd_create_new_nat_info(tid, FLWD_NAT_TYPE_SNAT, nat_key, + &usable_active_ipport_args, raw_pkt); + + flwd_log(RLOG_LV_DEBUG, "---before signature, tuple4:%s", + flwd_tuple5_ntop(tid, &nat_info->outer_nat_tuple5)); + flwd_acc_user_generate_pkt_signature(tid, nat_info, raw_pkt); + flwd_log(RLOG_LV_DEBUG, "---after signature, tuple4:%s", + flwd_tuple5_ntop(tid, &nat_info->outer_nat_tuple5)); + + }else if(TOPO_ACC_LINK_FWD == device_handle->io_para.topo_mode){ + /* FWD���������װ�, ˵����DNAT��һ����, ���ݸ��ؾ�����Բ���������ʵ������IP�Ͷ˿� */ +#if FLWD_SUPPORT_DNAT + flwd_search_access_dnat_lb_policy(tid, nat_key, &actual_ipport_net_order); + + nat_info = flwd_create_new_nat_info(tid, FLWD_NAT_TYPE_DNAT, nat_key, + &usable_active_ipport_args, raw_pkt); +#endif + } + + if(NULL == nat_info){ +#if FLWD_SUPPORT_DNAT + assert(0); +#endif + return NULL; + } + + if(flwd_new_nat_session_sotre(tid, nat_info) < 0){ + return NULL; + } + + char inner_tuple5_str[256]; + char outer_tuple5_str[256]; + + flwd_log(10, "ACC: create new nat session, inner_tuple4:%s, outer_tuple4:%s\n", + flwd_tuple5_ntop_r(&nat_info->inner_nat_tuple5, inner_tuple5_str, 256), + flwd_tuple5_ntop_r(&nat_info->outer_nat_tuple5, outer_tuple5_str, 256)); + + return nat_info; +} + +/* + access����user�հ�, ���nat��������, Ҫ��֤�Ϸ����װ�, + ������TCP->SYN, ������UDP��. + + return value: + 0 : valid; + -1: invalid; +*/ +static int flwd_acc_user_first_pkt_verify(const char *raw_eth_data) +{ + const flwd_eth_hdr_t *flwd_ethhdr = (flwd_eth_hdr_t *)raw_eth_data; + const flwd_ipv4_hdr_t *flwd_ip4hdr; + const flwd_ipv6_hdr_t *flwd_ip6hdr; + unsigned short eth_type = ntohs(flwd_ethhdr->h_proto); + const flwd_tcp_hdr_t *flwd_tcphdr; + int ret = 0; + + if(ETH_P_IP == eth_type){ + flwd_ip4hdr = (flwd_ipv4_hdr_t *)((char *)flwd_ethhdr + sizeof(flwd_eth_hdr_t)); + if(IPPROTO_TCP == flwd_ip4hdr->ip_p){ + flwd_tcphdr = (flwd_tcp_hdr_t *)((char *)flwd_ip4hdr + flwd_ip4hdr->ip_hl * 4); + if(TH_SYN == flwd_tcphdr->th_flags){ + ret = 0; + }else{ + ret = -1; + } + }else if(IPPROTO_UDP == flwd_ip4hdr->ip_p){ + ret = 0; + } + }else if(ETH_P_IPV6 == eth_type){ + flwd_ip6hdr = (flwd_ipv6_hdr_t *)((char *)flwd_ethhdr + sizeof(flwd_eth_hdr_t)); + if(IPPROTO_TCP == flwd_ip6hdr->ip6_nxt_hdr){ + flwd_tcphdr = (flwd_tcp_hdr_t *)((char *)flwd_ip6hdr + sizeof(flwd_ipv6_hdr_t)); + if(TH_SYN == flwd_tcphdr->th_flags){ + ret = 0; + }else{ + ret = -1; + } + }else if(IPPROTO_UDP == flwd_ip4hdr->ip_p){ + ret = 0; + } + }else{ + assert(0); + } + + return ret; +} + +/* + access���ش�fwd�����հ�, ���nat��������, Ҫ��֤�Ϸ����װ�, + ������IP���ò���DNAT�е�ip,port; + ͬʱ��������TCP->SYN, ������UDP��. + + �����SNAT, �϶�Ӧ�����ҵ�nat����֮ǰ�洢��Ԫ��. + + return value: + 0 : valid; + -1: invalid; +*/ +static int flwd_acc_fwd_first_pkt_verify(char *inner_mac_hdr) +{ + const flwd_eth_hdr_t *flwd_ethhdr = (flwd_eth_hdr_t *)inner_mac_hdr; + const flwd_ipv4_hdr_t *flwd_ip4hdr; + const flwd_ipv6_hdr_t *flwd_ip6hdr; + unsigned short eth_type = ntohs(flwd_ethhdr->h_proto); + const flwd_tcp_hdr_t *flwd_tcphdr; + int ret = 0; + + if(ETH_P_IP == eth_type){ + flwd_ip4hdr = (flwd_ipv4_hdr_t *)((char *)flwd_ethhdr + sizeof(flwd_eth_hdr_t)); + if(IPPROTO_TCP == flwd_ip4hdr->ip_p){ + flwd_tcphdr = (flwd_tcp_hdr_t *)((char *)flwd_ip4hdr + flwd_ip4hdr->ip_hl * 4); + if(TH_SYN == flwd_tcphdr->th_flags){ /* ����DNAT��˵ */ + ret = 0; + }if((TH_SYN|TH_ACK) == flwd_tcphdr->th_flags){ /* ����SNAT��˵ */ + ret = 0; + }else{ + ret = -1; + } + }else if(IPPROTO_UDP == flwd_ip4hdr->ip_p){ + ret = 0; + } + }else if(ETH_P_IPV6 == eth_type){ + flwd_ip6hdr = (flwd_ipv6_hdr_t *)((char *)flwd_ethhdr + sizeof(flwd_eth_hdr_t)); + if(IPPROTO_TCP == flwd_ip6hdr->ip6_nxt_hdr){ /* TODO, IPv6���п��ܰ�������ͷ��, ��ʵ��Ӧ����ôֱ��ȡnext_hdr */ + flwd_tcphdr = (flwd_tcp_hdr_t *)((char *)flwd_ip6hdr + sizeof(flwd_ipv6_hdr_t)); + if(TH_SYN == flwd_tcphdr->th_flags){ /* ����DNAT��˵ */ + ret = 0; + }if((TH_SYN|TH_ACK) == flwd_tcphdr->th_flags){ /* ����SNAT��˵ */ + ret = 0; + }else{ + ret = -1; + } + }else if(IPPROTO_UDP == flwd_ip4hdr->ip_p){ + ret = 0; + } + }else{ + assert(0); + } + + return ret; +} + +/* �ͻ��˽��뷽��IP��, ���߰�ȥ������(��L2TP, PPTP������װ)����ʵ�ͻ����ڲ����ݰ���ں��� */ +int flwd_access_kernal_pkt_input(flwd_device_handle_t *device_handle, + int tid, flwd_raw_pkt_t *raw_pkt) +{ + void *ip_strategy; + flwd_nat_info_t *nat_info; + char nat_key_buf[sizeof(flwd_tuple4v6_t)]; /* v4, v6����, ʹ��v6�ռ����� */ + flwd_tuple5_t nat_key; + unsigned char dir_reverse; + int ret; + int ltsm_stat; + unsigned int out_opt = 0; + + ret = flwd_build_tuple4_key(tid, &nat_key, raw_pkt); + if(ret < 0){ + return -1; + } + + nat_info = (flwd_nat_info_t *)MESA_htable_search(flwd_thread_val[tid].nat_info_table, + (const uchar *)&nat_key, sizeof(flwd_tuple5_t)); + if(NULL == nat_info){ + if((TOPO_ACC_LINK_USER == device_handle->io_para.topo_mode) + && (flwd_acc_user_first_pkt_verify(raw_pkt->outer_pkt_data) < 0)){ + return -1; + }else if((TOPO_ACC_LINK_FWD == device_handle->io_para.topo_mode) + && (flwd_acc_fwd_first_pkt_verify(raw_pkt->inner_pkt_data) < 0)){ + return -1; + } + + nat_info = flwd_new_nat_session(device_handle, tid, &nat_key, raw_pkt); + if(NULL == nat_info){ + if(TOPO_ACC_LINK_FWD == device_handle->io_para.topo_mode){ + flwd_log(30, "recv pkt from gdev, but not found nat_info:%s!", + flwd_tuple5_ntop(tid, &nat_key)); + } + return -1; + } + out_opt |= FLWD_OUTOPT_FIRST_PKT; + } + + ltsm_stat = flwd_do_nat(device_handle, nat_info, raw_pkt); + + flwd_access_output(device_handle, tid, nat_info, raw_pkt, out_opt); + +#if FLWD_USE_LTSM_FOR_QUICK_CLOSE + if(FTSM_CLOSED == ltsm_stat){ + flwd_log(10, "tuple4 %s state is CLOSED, quick destroy nat_info!\n", + flwd_tuple5_ntop(tid, &nat_key)); + MESA_htable_del(flwd_thread_val[tid].nat_info_table, + (const uchar *)&nat_key, sizeof(flwd_tuple5_t), NULL); + } +#endif + + return 0; +} + +static void *flwd_access_nat_table_create(void) +{ + int opt_int; + MESA_htable_handle htable; + + htable = MESA_htable_born(); + assert(htable != NULL); + + opt_int = 0; /* ÿ���̶߳���, ����ģʽ */ + MESA_htable_set_opt(htable, MHO_THREAD_SAFE, &opt_int, sizeof(int)); + + opt_int = 1024 * 256; + MESA_htable_set_opt(htable, MHO_HASH_SLOT_SIZE, &opt_int, sizeof(int)); + + MESA_htable_set_opt(htable, MHO_HASH_MAX_ELEMENT_NUM, &flwd_cfg_val.nat_htable_max_num, sizeof(int)); + + /* TODO, Ŀǰ���ó�ʱ��̭, ����TCPӦ��������״̬��, TCP������������̭, �����ͷ��ڴ� */ + MESA_htable_set_opt(htable, MHO_EXPIRE_TIME, &flwd_cfg_val.nat_htable_timeout, sizeof(int)); + + opt_int = HASH_ELIMINATE_ALGO_LRU; + MESA_htable_set_opt(htable, MHO_ELIMIMINATE_TYPE, &opt_int, sizeof(int)); + + MESA_htable_set_opt(htable, MHO_CBFUN_KEY_COMPARE, (void *)&flwd_nat_htable_key_cmp, sizeof(void *)); + + MESA_htable_set_opt(htable, MHO_CBFUN_KEY_TO_INDEX, (void *)&flwd_nat_htable_key2index, sizeof(void *)); + + MESA_htable_set_opt(htable, MHO_CBFUN_COMPLEX_KEY_DUP, (void *)flwd_nat_htable_key_dup, sizeof(void *)); + + MESA_htable_set_opt(htable, MHO_CBFUN_COMPLEX_KEY_FREE, (void *)flwd_nat_htable_key_free, sizeof(void *)); + + MESA_htable_set_opt(htable, MHO_CBFUN_DATA_FREE, (void *)&flwd_access_nat_htable_data_free, sizeof(void *)); + + MESA_htable_set_opt(htable, MHO_CBFUN_DATA_EXPIRE_NOTIFY, (void *)&flwd_access_nat_htable_data_expire_notify, sizeof(void *)); + + opt_int = 1; + MESA_htable_set_opt(htable, MHO_AUTO_UPDATE_TIME, &opt_int, sizeof(int)); + + opt_int = 0; + MESA_htable_set_opt(htable, MHO_SCREEN_PRINT_CTRL, &opt_int, sizeof(int)); + + opt_int = 100; + MESA_htable_set_opt(htable, MHO_HASH_LIST_COLLIDE_THRESHOLD, &opt_int, sizeof(int)); + + char *err_log = (char *)"./flwd_hash_collide.log"; + MESA_htable_set_opt(htable, MHO_HASH_LOG_FILE, (void *)err_log, strlen(err_log)); + + int ret = MESA_htable_mature(htable); + assert(ret >= 0); + + return htable; +} + + +/* + �������ش�ת�����ط����հ�, ����vxlan��. +*/ +static int flwd_acc_fwd_pkt_input(flwd_device_handle_t *rcv_device_handle, + int tid, flwd_raw_pkt_t *raw_pkt) +{ + int ret; + + raw_pkt->inner_ip_layer_hdr = (const char *)raw_pkt->outer_pkt_data + FLWD_VXLAN_OUTER_PACKET_LEN + sizeof(flwd_eth_hdr_t); /* �����������vxlanͷ�����ڲ�ethernetͷ�� */ + raw_pkt->inner_pkt_data = (char *)raw_pkt->outer_pkt_data + FLWD_VXLAN_OUTER_PACKET_LEN; /* ָ���ڲ�ethernet��ʼ��ַ */ + raw_pkt->inner_pkt_len = raw_pkt->outer_pkt_len - FLWD_VXLAN_OUTER_PACKET_LEN; + ret = flwd_access_kernal_pkt_input(rcv_device_handle, tid, raw_pkt); + + return ret; +} + +int flwd_acc_pkt_input(flwd_device_handle_t *device_handle, int tid, flwd_raw_pkt_t *raw_pkt) +{ + int ret; + + flwd_thread_val[tid].pkt_stat.eth_pkt_num++; + flwd_thread_val[tid].pkt_stat.eth_pkt_byte += raw_pkt->outer_pkt_len; + + if(TOPO_ACC_LINK_FWD == device_handle->io_para.topo_mode){ + ret = flwd_rubbish_pkt_identify(device_handle, raw_pkt, 1); + }else{ + ret = flwd_rubbish_pkt_identify(device_handle, raw_pkt, 0); + } + if(ret != 0){ + return 0; + } + + ret = flwd_protocol_stack_process(device_handle, tid, raw_pkt); + if(ret != 0){ + return 0; + } + + switch((int)device_handle->io_para.topo_mode){ + case TOPO_ACC_LINK_USER: + flwd_log(10, "ACC: recv pkt from user client, tuple4:%s\n", + flwd_debug_print_tuple4_detail((char *)raw_pkt->outer_pkt_data + sizeof(flwd_eth_hdr_t), tid)); + flwd_acc_user_pkt_input(device_handle, tid, raw_pkt); + break; + + case TOPO_ACC_LINK_FWD: + { + char inner_tuple4[128]; + char outer_tuple4[128]; + flwd_log(10, "ACC: recv pkt from forward gateway, inner_tuple4:%s, outer_tuple4:%s\n", + flwd_debug_print_tuple4_detail_r((char *)raw_pkt->outer_pkt_data + FLWD_VXLAN_OUTER_PACKET_LEN + sizeof(flwd_eth_hdr_t), inner_tuple4, 128), + flwd_debug_print_tuple4_detail_r((char *)raw_pkt->outer_pkt_data + sizeof(flwd_eth_hdr_t), outer_tuple4, 128)); + + flwd_acc_fwd_pkt_input(device_handle, tid, raw_pkt); + } + break; + } + + return 0; +} + + +void *flwd_packet_io_work_thread(void *arg) +{ + int ret1, ret2, ret3; + int tseq = *((int *)arg); + flwd_raw_pkt_t raw_pkt; + unsigned long long last_idle_call_in_ms = 0; + flwd_device_handle_t *dev_handle; + int tot_work_times = 0; /* �ܽ��հ�, idle���� */ + int success_work_times_in_recent_100 = 0; /* ���100�γɹ��Ĵ��� */ + + while(1){ + dev_handle = &flwd_global_val.global_io_handle[TOPO_ACC_LINK_USER]; + ret1 = dev_handle->low_level_pkt_recv(dev_handle, tseq, &raw_pkt.low_level_mbuff); + if(ret1 >= 0){ + raw_pkt.outer_pkt_data = dev_handle->low_level_mbuff_mtod(raw_pkt.low_level_mbuff); + raw_pkt.outer_pkt_len = dev_handle->low_level_mbuff_get_pkt_len(raw_pkt.low_level_mbuff); + flwd_pre_process_pkt_input(dev_handle, &raw_pkt); + flwd_acc_pkt_input(dev_handle, tseq, &raw_pkt); + dev_handle->low_level_pkt_free(dev_handle, tseq, raw_pkt.low_level_mbuff); + } + + dev_handle = &flwd_global_val.global_io_handle[TOPO_ACC_LINK_FWD]; + ret2 = dev_handle->low_level_pkt_recv(dev_handle, tseq, &raw_pkt.low_level_mbuff); + if(ret2 >= 0){ + raw_pkt.outer_pkt_data = dev_handle->low_level_mbuff_mtod(raw_pkt.low_level_mbuff); + raw_pkt.outer_pkt_len = dev_handle->low_level_mbuff_get_pkt_len(raw_pkt.low_level_mbuff); + flwd_pre_process_pkt_input(dev_handle, &raw_pkt); + flwd_acc_pkt_input(dev_handle, tseq, &raw_pkt); + dev_handle->low_level_pkt_free(dev_handle, tseq, raw_pkt.low_level_mbuff); + } + + tot_work_times++; + + if((ret1 < 0) && (ret2 < 0)){ + ret3 = flwd_idle_call(tseq); + if(0 == ret3){ + /* ����������������, idle_call()Ҳ���¿���, ����һ�� */ + flwd_adapt_sleep(success_work_times_in_recent_100); + }else{ + success_work_times_in_recent_100++; + } + }else{ + success_work_times_in_recent_100++; + } + + if(tot_work_times >= 100){ + /////printf("%d/100\n", success_work_times_in_recent_100); + tot_work_times = 0; + success_work_times_in_recent_100 = 0; + } + } + + return NULL; +} + +/* �������س�ʼ������� */ +int flwd_gateway_init(void) +{ + int i, ret; + char str_tmp[256]; + +#if FLWD_NO_ACTIVE_IP_DISCOVER + printf("\033[1;31;40m[Warning] TEST NO IP DISCOVER is enable!\033[0m\n" ); + sleep(2); +#endif + + MESA_load_profile_int_def(FLWD_CONFIG_FILE, "main", "nat_htable_max_num", &flwd_cfg_val.nat_htable_max_num, 50000); + MESA_load_profile_int_def(FLWD_CONFIG_FILE, "main", "nat_htable_timeout", &flwd_cfg_val.nat_htable_timeout, 30); + + for(i = 0; i < flwd_cfg_val.tot_thread_count; i++){ + flwd_thread_val[i].nat_info_table = flwd_access_nat_table_create(); + } + + + /* TODO, PPTP, L2TP server ��ʼ�� */ + + /* TODO, IP��ַ��ȫ��, ip-hot-pool �ṹ��ʼ�� */ + + /* IP���ò��Խṹ��ʼ��, HASH��, ����SNAT, keyΪdip+dport, ����DNAT, keyΪRIP+RPORT */ + + ret = flwd_packet_io_init(TOPO_ACC_LINK_USER, TOPO_ACC_LINK_FWD); + if(ret < 0){ + return -1; + } + + ret = flwd_access_active_ip_init(); + if(ret < 0){ + return -1; + } + + ret = flwd_network_conn_init(); + if(ret < 0){ + return -1; + } + + /* NOTE: maat��÷���������, ��Ϊ��callback, ��ʼ����ر���������, ����������ݽṹ��û��ʼ�����, ����flwd_access_active_ip_init(), callback�����! */ + ret = flwd_access_maat_init(); + if(ret < 0){ + return -1; + } + + return 0; +} + |
