diff options
-rw-r--r-- | scripts/exp/no_tcp_syn_ack.pcap | bin | 0 -> 264 bytes | |||
-rw-r--r-- | scripts/exp/tcp_2_pkts.pcap | bin | 0 -> 184 bytes | |||
-rw-r--r-- | scripts/exp/tcp_low_ipg.pcap | bin | 0 -> 264 bytes | |||
-rwxr-xr-x | src/bp_gtest.cpp | 72 | ||||
-rwxr-xr-x | src/bp_sim.cpp | 284 | ||||
-rwxr-xr-x | src/bp_sim.h | 114 | ||||
-rwxr-xr-x | src/common/Network/Packet/TcpHeader.h | 5 | ||||
-rw-r--r-- | src/latency.cpp | 17 | ||||
-rw-r--r-- | src/latency.h | 34 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 5 | ||||
-rwxr-xr-x | src/nat_check.cpp | 78 | ||||
-rwxr-xr-x | src/nat_check.h | 21 |
12 files changed, 438 insertions, 192 deletions
diff --git a/scripts/exp/no_tcp_syn_ack.pcap b/scripts/exp/no_tcp_syn_ack.pcap Binary files differnew file mode 100644 index 00000000..0cdcf91b --- /dev/null +++ b/scripts/exp/no_tcp_syn_ack.pcap diff --git a/scripts/exp/tcp_2_pkts.pcap b/scripts/exp/tcp_2_pkts.pcap Binary files differnew file mode 100644 index 00000000..37c4f46b --- /dev/null +++ b/scripts/exp/tcp_2_pkts.pcap diff --git a/scripts/exp/tcp_low_ipg.pcap b/scripts/exp/tcp_low_ipg.pcap Binary files differnew file mode 100644 index 00000000..78fb987e --- /dev/null +++ b/scripts/exp/tcp_low_ipg.pcap diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp index 79ea2458..3c6b2e40 100755 --- a/src/bp_gtest.cpp +++ b/src/bp_gtest.cpp @@ -2416,7 +2416,7 @@ public: assert(ipv4->getTimeToLive()==255); /* ip option packet */ printf(" rx got ip option packet ! \n"); - mg->handle_packet_ipv4(option,ipv4); + mg->handle_packet_ipv4(option, ipv4, true); delay(10); // delay for queue flush mg->handle_aging(); // flush the RxRing } @@ -2481,8 +2481,10 @@ protected: m_flow_info.Delete(); } public: - CCapFileFlowInfo m_flow_info; + void load_cap_file_errors_helper(std::string cap_file, enum CCapFileFlowInfo::load_cap_file_err expect); +public: + CCapFileFlowInfo m_flow_info; }; TEST_F(file_flow_info, f1) { @@ -2612,30 +2614,58 @@ TEST_F(file_flow_info, http_add_ipv6_option) { po->preview.set_ipv6_mode_enable(false); } +void file_flow_info::load_cap_file_errors_helper(std::string cap_file, enum CCapFileFlowInfo::load_cap_file_err expect) { + enum CCapFileFlowInfo::load_cap_file_err err; + + err = m_flow_info.load_cap_file(cap_file, 1, 0); + if (err == 0) err = m_flow_info.is_valid_template_load_time(); + if (err != expect) { + printf("Error in testing file %s. Expected error to be %d, but it is %d\n", cap_file.c_str(), expect, err); + } + assert (err == expect); +} + // Test error conditions when loading cap file TEST_F(file_flow_info, load_cap_file_errors) { - enum CCapFileFlowInfo::load_cap_file_err err; - CParserOption * po =&CGlobalInfo::m_options; - po->m_learn_mode = CParserOption::LEARN_MODE_TCP_ACK; + CParserOption *po = &CGlobalInfo::m_options; - // file does not exist - err = m_flow_info.load_cap_file("/tmp/not_exist",1,0); - assert (err == CCapFileFlowInfo::kFileNotExist); + po->m_learn_mode = CParserOption::LEARN_MODE_DISABLED; + load_cap_file_errors_helper("/tmp/not_exist", CCapFileFlowInfo::kFileNotExist); // file format not supported - err = m_flow_info.load_cap_file("cap2/dns.yaml",1,0); - assert (err == CCapFileFlowInfo::kFileNotExist); - // udp in tcp learn mode - err = m_flow_info.load_cap_file("./cap2/dns.pcap",1,0); - assert (err == CCapFileFlowInfo::kNoTCPFromServer); - // First TCP packet without syn - err = m_flow_info.load_cap_file("./exp/tcp_no_syn.pcap",1,0); - assert (err == CCapFileFlowInfo::kNoSyn); - // TCP flags offset is too big - err = m_flow_info.load_cap_file("./exp/many_ip_options.pcap",1,0); - assert (err == CCapFileFlowInfo::kTCPOffsetTooBig); + load_cap_file_errors_helper("cap2/dns.yaml", CCapFileFlowInfo::kFileNotExist); + load_cap_file_errors_helper("cap2/dns.pcap", CCapFileFlowInfo::kOK); + load_cap_file_errors_helper("./exp/tcp_no_syn.pcap", CCapFileFlowInfo::kOK); + load_cap_file_errors_helper("./exp/many_ip_options.pcap", CCapFileFlowInfo::kOK); // Non IP packet - err = m_flow_info.load_cap_file("./exp/bad_not_ip.pcap",1,0); - assert (err == CCapFileFlowInfo::kPktProcessFail); + load_cap_file_errors_helper("./exp/bad_not_ip.pcap", CCapFileFlowInfo::kPktProcessFail); + load_cap_file_errors_helper("./exp/tcp_2_pkts.pcap", CCapFileFlowInfo::kOK); + // more than 1 flow in cap file + load_cap_file_errors_helper("./exp/syn_attack.pcap", CCapFileFlowInfo::kCapFileErr); + + po->m_learn_mode = CParserOption::LEARN_MODE_IP_OPTION; + load_cap_file_errors_helper("cap2/dns.pcap", CCapFileFlowInfo::kOK); + load_cap_file_errors_helper("./exp/tcp_no_syn.pcap", CCapFileFlowInfo::kOK); + load_cap_file_errors_helper("./exp/many_ip_options.pcap", CCapFileFlowInfo::kIPOptionNotAllowed); + load_cap_file_errors_helper("./exp/tcp_2_pkts.pcap", CCapFileFlowInfo::kOK); + + po->m_learn_mode = CParserOption::LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND; + // udp in tcp learn mode + load_cap_file_errors_helper("cap2/dns.pcap", CCapFileFlowInfo::kNoTCPFromServer); + // no SYN in first packet + load_cap_file_errors_helper("./exp/tcp_no_syn.pcap", CCapFileFlowInfo::kNoSyn); + // TCP flags offset is too big. We don't allow IP option, so can comment this. + // open this if we do allow IP options in the future + // load_cap_file_errors_helper("./exp/many_ip_options.pcap", CCapFileFlowInfo::kTCPOffsetTooBig); + load_cap_file_errors_helper("./exp/tcp_2_pkts.pcap", CCapFileFlowInfo::kOK); + load_cap_file_errors_helper("./exp/no_tcp_syn_ack.pcap", CCapFileFlowInfo::kOK); + + po->m_learn_mode = CParserOption::LEARN_MODE_TCP_ACK; + // too short. only two packets + load_cap_file_errors_helper("./exp/tcp_2_pkts.pcap", CCapFileFlowInfo::kTCPLearnModeBadFlow); + // no SYN+ACK + load_cap_file_errors_helper("./exp/no_tcp_syn_ack.pcap", CCapFileFlowInfo::kNoTCPSynAck); + // IPG between TCP handshake packets too low + load_cap_file_errors_helper("./exp/tcp_low_ipg.pcap", CCapFileFlowInfo::kTCPIpgTooLow); } ////////////////////////////////////////////////////////////// diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index b93c0461..f46f2824 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -1938,42 +1938,114 @@ typedef CTmpFlowInfo * flow_tmp_t; typedef std::map<uint16_t, flow_tmp_t> flow_tmp_map_t; typedef flow_tmp_map_t::iterator flow_tmp_map_iter_t; - - -bool CCapFileFlowInfo::is_valid_template_load_time(std::string & err){ - err=""; +enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::is_valid_template_load_time(){ int i; for (i=0; i<Size(); i++) { CFlowPktInfo * lp= GetPacket((uint32_t)i); CPacketIndication * lpd=&lp->m_pkt_indication; if ( lpd->getEtherOffset() !=0 ){ - err=" supported template Ether offset start is 0 \n"; - return (false); - } - if ( lpd->getIpOffset() !=14 ){ - err=" supported template ip offset is 14 \n"; - return (false); + fprintf(stderr, "Error: Bad CAP file. Ether offset start is not 0 in packet %d \n", i+1); + return kPktNotSupp; } - if ( lpd->is_ipv6() ){ - if ( lpd->getTcpOffset() != (14+40) ){ - err=" supported template tcp/udp offset is 54, no ipv6 option header is supported \n"; - return (false); + + if ( CGlobalInfo::is_learn_mode() ) { + // We change TCP ports. Need them to be in first 64 byte mbuf. + // Since we also add IP option, and rx-check feature might add another IP option, better not allow + // OP options in this mode. If needed this limitation can be refined a bit. + if ( lpd->getTcpOffset() - lpd->getIpOffset() != 20 ) { + fprintf(stderr, "Error: Bad CAP file. In learn (NAT) mode, no IP options allowed \n"); + return kIPOptionNotAllowed; } - }else{ - if ( lpd->getTcpOffset() != (14+20) ){ - err=" supported template tcp/udp offset is 34, no ipv4 option is allowed in this version \n"; - return (false); + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP)) { + if (lpd->getIpProto() != IPPROTO_TCP && !lpd->m_desc.IsInitSide()) { + fprintf(stderr, "Error: In the chosen learn mode, all packets from server to client in CAP file should be TCP.\n"); + fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n"); + return kNoTCPFromServer; + } } } } if ( CGlobalInfo::is_learn_mode() ) { - if ( GetPacket(0)->m_pkt_indication.m_desc.IsPluginEnable() ) { - err="plugins are not supported with --learn mode \n"; - return(false); + CPacketIndication &pkt_0_indication = GetPacket(0)->m_pkt_indication; + + if ( pkt_0_indication.m_desc.IsPluginEnable() ) { + fprintf(stderr, "Error: plugins are not supported with --learn mode \n"); + return kPlugInWithLearn; + } + + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP)) { + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { + if (Size() < 3) { + fprintf(stderr + , "Error: In the chosen learn mode, need at least the 3 TCP handshake packets.\n"); + fprintf(stderr + , " Please give different CAP file, or try different --learn-mode\n"); + return kTCPLearnModeBadFlow; + } + } + CPacketIndication &pkt_1_indication = GetPacket(1)->m_pkt_indication; + + + // verify first packet is TCP SYN from client + TCPHeader *tcp = (TCPHeader *)(pkt_0_indication.getBasePtr() + pkt_0_indication.getTcpOffset()); + if ( (! pkt_0_indication.m_desc.IsInitSide()) || (! tcp->getSynFlag()) ) { + fprintf(stderr, "Error: In the chosen learn mode, first TCP packet should be SYN from client side.\n"); + fprintf(stderr, " In cap file, first packet side direction is %s. TCP header is:\n" + , pkt_0_indication.m_desc.IsInitSide() ? "outside":"inside"); + tcp->dump(stderr); + fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n"); + return kNoSyn; + } + + // We want at least the TCP flags to be inside first mbuf + if (pkt_0_indication.getTcpOffset() + 14 > FIRST_PKT_SIZE) { + fprintf(stderr + , "Error: In the chosen learn mode, TCP flags offset should be less than %d, but it is %d.\n" + , FIRST_PKT_SIZE, pkt_0_indication.getTcpOffset() + 14); + fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n"); + return kTCPOffsetTooBig; + } + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { + // To support TCP seq randomization from server to client, we need second packet in flow to be the server SYN+ACK + bool error = false; + if (pkt_1_indication.getIpProto() != IPPROTO_TCP) { + error = true; + } else { + TCPHeader *tcp = (TCPHeader *)(pkt_1_indication.getBasePtr() + pkt_1_indication.getTcpOffset()); + if ( (! tcp->getSynFlag()) || (! tcp->getAckFlag()) || ( pkt_1_indication.m_desc.IsInitSide())) { + error = true; + } + } + if (error) { + fprintf(stderr, "Error: In the chosen learn mode, second packet should be SYN+ACK from server.\n"); + fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n"); + return kNoTCPSynAck; + } + + CPacketIndication &pkt_2_indication = GetPacket(2)->m_pkt_indication; + if ( (! pkt_2_indication.m_desc.IsInitSide()) ) { + fprintf(stderr + , "Error: Wrong third packet. In the chosen learn mode, need at least the 3 TCP handshake packets.\n"); + fprintf(stderr + , " Please give different CAP file, or try different --learn-mode\n"); + return kTCPLearnModeBadFlow; + } + if ((pkt_0_indication.m_cap_ipg < LEARN_MODE_MIN_IPG / 1000) || (pkt_1_indication.m_cap_ipg < LEARN_MODE_MIN_IPG / 1000)) { + fprintf(stderr + , "Error: Bad cap file timings. In the chosen learn mode"); + fprintf(stderr, "IPG between TCP handshake packets should be at least %d msec.\n", LEARN_MODE_MIN_IPG); + fprintf(stderr, " Current delay is %f between second and first, %f between third and second" + , pkt_0_indication.m_cap_ipg, pkt_1_indication.m_cap_ipg); + fprintf(stderr + , " Please give different CAP file, try different --learn-mode, or edit ipg parameters in template file\n"); + return kTCPIpgTooLow; + } + } } } - return(true); + + return(kOK); } @@ -2061,6 +2133,13 @@ void CCapFileFlowInfo::update_info(){ if ( lp->m_pkt_indication.m_desc.IsBiDirectionalFlow() ){ lp->mask_as_learn(); } + + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { + // In this mode, we need to see the SYN+ACK as well. + lp = GetPacket(1); + assert(lp); + lp->m_pkt_indication.setTTL(TTL_RESERVE_DUPLICATE); + } } if ( ft.empty() ) @@ -2100,7 +2179,6 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st m_total_errors=0; CFlow * first_flow=0; bool first_flow_fif_is_swap=false; - bool time_was_set=false; double last_time=0.0; CCapPktRaw raw_packet; @@ -2175,35 +2253,10 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st m_total_errors++; } } - - if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { - // in this mode, first TCP packet must be SYN from client. - if (pkt_indication.getIpProto() == IPPROTO_TCP) { - TCPHeader *tcp = (TCPHeader *)(pkt_indication.getBasePtr() + pkt_indication.getTcpOffset()); - if ( (! pkt_indication.m_desc.IsInitSide()) || (! tcp->getSynFlag()) ) { - fprintf(stderr, "Error: In the chosen learn mode, first TCP packet should be SYN from client side.\n"); - fprintf(stderr, " In cap file, first packet side direction is %s. TCP header is:\n", pkt_indication.m_desc.IsInitSide() ? "outside":"inside"); - tcp->dump(stderr); - fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n"); - - return kNoSyn; - } - // We want at least the TCP flags to be inside first mbuf - if (pkt_indication.getTcpOffset() + 14 > FIRST_PKT_SIZE) { - fprintf(stderr, "Error: In the chosen learn mode, first TCP packet TCP flags offset should be less than %d, but it is %d.\n" - , FIRST_PKT_SIZE, pkt_indication.getTcpOffset() + 14); - fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n"); - return kTCPOffsetTooBig; - } - } - } - }else{ /* no FIF */ - pkt_indication.m_desc.SetFlowId(lpflow->flow_id); if ( multi_flow_enable ==false ){ - if (lpflow == first_flow) { // add to bool init_side= @@ -2225,16 +2278,6 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st } } - - if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { - // This test must be down here, after initializing init side indication - if (pkt_indication.getIpProto() != IPPROTO_TCP && !pkt_indication.m_desc.IsInitSide()) { - fprintf(stderr, "Error: In the chosen learn mode, all packets from server to client in CAP file should be TCP.\n"); - fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n"); - return kNoTCPFromServer; - } - } - }else{ fprintf(stderr, "ERROR packet %d is not supported, should be Ethernet/IP(0x0800)/(TCP|UDP) format try to convert it using Wireshark !\n",cnt); return kPktNotSupp; @@ -2245,7 +2288,6 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st } } - /* set the last */ CFlowPktInfo * last_pkt =GetPacket((uint32_t)(Size()-1)); last_pkt->m_pkt_indication.m_desc.SetIsLastPkt(true); @@ -2261,6 +2303,7 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st + printf("%d: IPG:%f", i, lp_prev->m_pkt_indication.m_cap_ipg); //??? remove if ( lp->m_pkt_indication.m_desc.IsInitSide() != lp_prev->m_pkt_indication.m_desc.IsInitSide()) { lp_prev->m_pkt_indication.m_desc.SetRtt(true); @@ -3122,11 +3165,8 @@ bool CFlowGeneratorRec::Create(CFlowYamlInfo * info, int res=m_flow_info.load_cap_file(info->m_name.c_str(),_id,m_info->m_plugin_id); if ( res==0 ) { fixup_ipg_if_needed(); - std::string err; - /* verify that template are valid */ - bool is_valid=m_flow_info.is_valid_template_load_time(err); - if (!is_valid) { - printf("\n ERROR template file is not valid '%s' \n",err.c_str()); + + if (m_flow_info.is_valid_template_load_time() != 0) { return (false); } m_flow_info.update_info(); @@ -3700,11 +3740,11 @@ inline int CNodeGenerator::teardown(CFlowGenListPerThread * thread, } return (0); } - + template<int SCH_MODE> -inline int CNodeGenerator::flush_file_realtime(dsec_t max_time, +inline int CNodeGenerator::flush_file_realtime(dsec_t max_time, dsec_t d_time, bool always, CFlowGenListPerThread * thread, @@ -3723,9 +3763,9 @@ inline int CNodeGenerator::flush_file_realtime(dsec_t max_time, sch_state_t state = scINIT; node = m_p_queue.top(); - n_time = node->m_time + offset; + n_time = node->m_time + offset; cur_time = now_sec(); - + while (state!=scTERMINATE) { switch (state) { @@ -3751,7 +3791,7 @@ inline int CNodeGenerator::flush_file_realtime(dsec_t max_time, break; } node = m_p_queue.top(); - n_time = node->m_time + offset; + n_time = node->m_time + offset; if ((n_time-cur_time)>EAT_WINDOW_DTIME) { state=scINIT; @@ -3761,7 +3801,7 @@ inline int CNodeGenerator::flush_file_realtime(dsec_t max_time, break; case scWAIT: - do_sleep(cur_time,thread,n_time); // estimate loop + do_sleep(cur_time,thread,n_time); // estimate loop state=scWORK; break; default: @@ -3772,7 +3812,7 @@ inline int CNodeGenerator::flush_file_realtime(dsec_t max_time, return (teardown(thread,always,old_offset,offset)); } -FORCE_NO_INLINE int CNodeGenerator::flush_file_sim(dsec_t max_time, +FORCE_NO_INLINE int CNodeGenerator::flush_file_sim(dsec_t max_time, dsec_t d_time, bool always, CFlowGenListPerThread * thread, @@ -3799,7 +3839,7 @@ FORCE_NO_INLINE int CNodeGenerator::flush_file_sim(dsec_t max_time, return (teardown(thread,always,old_offset,0)); } -int CNodeGenerator::flush_file(dsec_t max_time, +int CNodeGenerator::flush_file(dsec_t max_time, dsec_t d_time, bool always, CFlowGenListPerThread * thread, @@ -3820,7 +3860,7 @@ int CNodeGenerator::flush_file(dsec_t max_time, void CNodeGenerator::handle_flow_pkt(CGenNode *node, CFlowGenListPerThread *thread) { - /*repeat and NAT is not supported */ + /*repeat and NAT is not supported together */ if ( node->is_nat_first_state() ) { node->set_nat_wait_state(); flush_one_node_to_file(node); @@ -3831,7 +3871,7 @@ void CNodeGenerator::handle_flow_pkt(CGenNode *node, CFlowGenListPerThread *thre if ( node->is_nat_wait_state() ) { if (node->is_responder_pkt()) { m_p_queue.pop(); - /* time out, need to free the flow and remove the association , we didn't get convertion yet*/ + /* time out, need to free the flow and remove the association , we didn't get conversion yet*/ thread->terminate_nat_flows(node); return; @@ -3842,7 +3882,22 @@ void CNodeGenerator::handle_flow_pkt(CGenNode *node, CFlowGenListPerThread *thre #endif } } else { - assert(0); + if ( node->is_nat_wait_ack_state() ) { + if (node->is_initiator_pkt()) { + m_p_queue.pop(); + /* time out, need to free the flow and remove the association , we didn't get conversion yet*/ + thread->terminate_nat_flows(node); + return; + + } else { + flush_one_node_to_file(node); +#ifdef _DEBUG + update_stats(node); +#endif + } + } else { + assert(0); + } } } m_p_queue.pop(); @@ -4146,38 +4201,72 @@ void CFlowGenListPerThread::handle_latency_pkt_msg(CGenNodeLatencyPktInfo * msg) m_node_gen.m_v_if->send_one_pkt((pkt_dir_t)msg->m_dir,msg->m_pkt); } - void CFlowGenListPerThread::handle_nat_msg(CGenNodeNatInfo * msg){ int i; + bool first = true, second = true; + for (i=0; i<msg->m_cnt; i++) { + first = true; + second = true; CNatFlowInfo * nat_msg=&msg->m_data[i]; CGenNode * node=m_flow_id_to_node_lookup.lookup(nat_msg->m_fid); if (!node) { - /* this should be move to a notification module */ - #ifdef NAT_TRACE_ + /* this should be moved to a notification module */ +#ifdef NAT_TRACE_ printf(" ERORR not valid flow_id %d probably flow was aged \n",nat_msg->m_fid); - #endif +#endif m_stats.m_nat_lookup_no_flow_id++; continue; } - #ifdef NAT_TRACE_ - printf(" %.03f RX :set node %p:%x %x:%x:%x \n",now_sec() ,node,nat_msg->m_fid,nat_msg->m_external_ip,nat_msg->m_external_ip_server,nat_msg->m_external_port); - #endif - node->set_nat_ipv4_addr(nat_msg->m_external_ip); - node->set_nat_ipv4_port(nat_msg->m_external_port); - node->set_nat_ipv4_addr_server(nat_msg->m_external_ip_server); - - assert(node->is_nat_wait_state()); - if ( CGlobalInfo::is_learn_verify_mode() ){ - if (!node->is_external_is_eq_to_internal_ip() ){ - m_stats.m_nat_flow_learn_error++; + + // Calculate diff between tcp seq of SYN packet, and TCP ack of SYN+ACK packet + // For supporting firewalls who do TCP seq num randomization + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP)) { + if (node->is_nat_wait_state()) { + char *syn_pkt = node->m_flow_info->GetPacket(0)->m_packet->raw; + TCPHeader *tcp = (TCPHeader *)(syn_pkt + node->m_pkt_info->m_pkt_indication.getFastTcpOffset()); + node->set_nat_tcp_seq_diff_client(nat_msg->m_tcp_seq - tcp->getSeqNumber()); + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { + node->set_nat_wait_ack_state(); + second = false; + } else { + node->set_nat_learn_state(); + } + } else { + char *syn_ack_pkt = node->m_flow_info->GetPacket(1)->m_packet->raw; + TCPHeader *tcp = (TCPHeader *)(syn_ack_pkt + node->m_pkt_info->m_pkt_indication.getFastTcpOffset()); + node->set_nat_tcp_seq_diff_server(nat_msg->m_tcp_seq - tcp->getSeqNumber()); + assert(node->is_nat_wait_ack_state()); + node->set_nat_learn_state(); + first = false; } + } else { + assert(node->is_nat_wait_state()); + node->set_nat_learn_state(); } - node->set_nat_learn_state(); - /* remove from the hash */ - m_flow_id_to_node_lookup.remove_no_lookup(nat_msg->m_fid); - m_stats.m_nat_lookup_remove_flow_id++; + if (first) { +#ifdef NAT_TRACE_ + printf(" %.03f RX :set node %p:%x %x:%x TCP diff %x\n" + , now_sec(), node,nat_msg->m_fid, nat_msg->m_external_ip, nat_msg->m_external_port + , node->get_nat_tcp_seq_diff_client()); +#endif + + node->set_nat_ipv4_addr(nat_msg->m_external_ip); + node->set_nat_ipv4_port(nat_msg->m_external_port); + + if ( CGlobalInfo::is_learn_verify_mode() ){ + if (!node->is_external_is_eq_to_internal_ip() ){ + m_stats.m_nat_flow_learn_error++; + } + } + } + + if (second) { + /* remove from the hash */ + m_flow_id_to_node_lookup.remove_no_lookup(nat_msg->m_fid); + m_stats.m_nat_lookup_remove_flow_id++; + } } } @@ -4273,7 +4362,7 @@ void CFlowGenListPerThread::start_generate_stateful(std::string erf_file_name, fprintf(stderr," nothing to generate no template loaded \n"); return; } - + m_preview_mode = preview; m_node_gen.open_file(erf_file_name,&m_preview_mode); dsec_t d_time_flow=get_delta_flow_is_sec(); @@ -5055,7 +5144,7 @@ void CErfIF::apply_client_config(const ClientCfg *cfg, pkt_dir_t dir) { /* VLAN */ if (cfg_dir.has_vlan()) { add_vlan(cfg_dir.get_vlan()); - } + } } int CErfIF::send_node(CGenNode *node){ @@ -6422,7 +6511,7 @@ void CGenNodeBase::free_base(){ CGenNodePCAP *p = (CGenNodePCAP *)this; p->destroy(); return; - } + } if ( m_type == COMMAND ) { CGenNodeCommand* p=(CGenNodeCommand*)this; @@ -6430,4 +6519,3 @@ void CGenNodeBase::free_base(){ } } - diff --git a/src/bp_sim.h b/src/bp_sim.h index d2812688..49e0e8dc 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -65,8 +65,6 @@ limitations under the License. class CGenNodePCAP; -#undef NAT_TRACE_ - #define FORCE_NO_INLINE __attribute__ ((noinline)) #define FORCE_INLINE __attribute__((always_inline)) @@ -84,10 +82,6 @@ typedef struct { */ #define INET_PORTSTRLEN 5 - - - - /* VM commands */ class CMiniVMCmdBase { @@ -757,7 +751,10 @@ public: LEARN_MODE_DISABLED=0, LEARN_MODE_TCP_ACK=1, LEARN_MODE_IP_OPTION=2, - LEARN_MODE_MAX=LEARN_MODE_IP_OPTION + LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND=3, + LEARN_MODE_MAX=LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND, + // This is used to check if 1 or 3 exist + LEARN_MODE_TCP=100 }; public: @@ -1246,7 +1243,11 @@ public: } static inline bool is_learn_mode(CParserOption::trex_learn_mode_e mode){ - return ( (m_options.m_learn_mode == mode)); + if (mode == CParserOption::LEARN_MODE_TCP) { + return ((m_options.m_learn_mode == CParserOption::LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND) + || (m_options.m_learn_mode == CParserOption::LEARN_MODE_TCP_ACK)); + } else + return (m_options.m_learn_mode == mode); } static inline bool is_ipv6_enable(void){ @@ -1558,11 +1559,11 @@ public: CTupleGeneratorSmart *m_tuple_gen; // cache line 1 - 64bytes waste of space ! - uint32_t m_nat_external_ipv4; /* client */ - uint32_t m_nat_external_ipv4_server; - uint16_t m_nat_external_port; - - uint16_t m_nat_pad[3]; + uint32_t m_nat_external_ipv4; // NAT client IP + uint32_t m_nat_tcp_seq_diff_client; // support for firewalls that do TCP seq num randomization + uint32_t m_nat_tcp_seq_diff_server; // And some do seq num randomization for server->client also + uint16_t m_nat_external_port; // NAT client port + uint16_t m_nat_pad[1]; const ClientCfg *m_client_cfg; uint32_t m_src_idx; uint32_t m_dest_idx; @@ -1699,6 +1700,15 @@ public: return (btGetMaskBit16(m_flags,4,3)==2?true:false) ; } + // We saw first TCP SYN. Waiting for SYN+ACK + inline void set_nat_wait_ack_state() { + btSetMaskBit16(m_flags, 4, 3, 3); + } + + inline bool is_nat_wait_ack_state(){ + return (btGetMaskBit16(m_flags,4,3) == 3) ? true : false; + } + inline void set_nat_learn_state(){ m_type=FLOW_PKT; /* normal operation .. repeat might work too */ } @@ -1712,14 +1722,21 @@ public: return (m_thread_id); } - inline void set_nat_ipv4_addr_server(uint32_t ip){ - m_nat_external_ipv4_server =ip; + inline void set_nat_tcp_seq_diff_client(uint32_t diff) { + m_nat_tcp_seq_diff_client = diff; + } + + inline uint32_t get_nat_tcp_seq_diff_client() { + return m_nat_tcp_seq_diff_client; } - inline uint32_t get_nat_ipv4_addr_server(){ - return ( m_nat_external_ipv4_server ); + inline void set_nat_tcp_seq_diff_server(uint32_t diff) { + m_nat_tcp_seq_diff_server = diff; } + inline uint32_t get_nat_tcp_seq_diff_server() { + return m_nat_tcp_seq_diff_server; + } inline void set_nat_ipv4_addr(uint32_t ip){ m_nat_external_ipv4 =ip; @@ -1740,8 +1757,7 @@ public: bool is_external_is_eq_to_internal_ip(){ /* this API is used to check TRex itself */ if ( (get_nat_ipv4_addr() == m_src_ip ) && - (get_nat_ipv4_port()==m_src_port) && - ( get_nat_ipv4_addr_server() == m_dest_ip) ) { + (get_nat_ipv4_port()==m_src_port)) { return (true); }else{ return (false); @@ -3004,6 +3020,8 @@ inline void CFlowPktInfo::update_pkt_info(char *p, (void)et; uint16_t src_port = node->m_src_port; + uint32_t tcp_seq_diff_client = 0; + uint32_t tcp_seq_diff_server = 0; pkt_dir_t ip_dir = node->cur_pkt_ip_addr_dir(); pkt_dir_t port_dir = node->cur_pkt_port_addr_dir(); @@ -3024,7 +3042,6 @@ inline void CFlowPktInfo::update_pkt_info(char *p, }else{ if ( unlikely ( CGlobalInfo::is_learn_mode() ) ){ - if (m_pkt_indication.m_desc.IsLearn()) { /* might be done twice */ #ifdef NAT_TRACE_ @@ -3033,42 +3050,48 @@ inline void CFlowPktInfo::update_pkt_info(char *p, ipv4->setTimeToLive(TTL_RESERVE_DUPLICATE); /* first ipv4 option add the info in case of learn packet, usualy only the first packet */ - if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION)) { - CNatOption *lpNat =(CNatOption *)ipv4->getOption(); - lpNat->set_fid(node->get_short_fid()); - lpNat->set_thread_id(node->get_thread_id()); - } else { - // This method only work on first TCP SYN - if (ipv4->getProtocol() == IPPROTO_TCP) { - TCPHeader *tcp = (TCPHeader *)(((uint8_t *)ipv4) + ipv4->getHeaderLength()); - if (tcp->getSynFlag()) { - tcp->setAckNumber(CNatRxManager::calc_tcp_ack_val(node->get_short_fid(), node->get_thread_id())); - } + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION)) { + CNatOption *lpNat =(CNatOption *)ipv4->getOption(); + lpNat->set_fid(node->get_short_fid()); + lpNat->set_thread_id(node->get_thread_id()); + } else { + // This method only work on first TCP SYN + if (ipv4->getProtocol() == IPPROTO_TCP) { + TCPHeader *tcp = (TCPHeader *)(((uint8_t *)ipv4) + ipv4->getHeaderLength()); + if (tcp->getSynFlag()) { + tcp->setAckNumber(CNatRxManager::calc_tcp_ack_val(node->get_short_fid(), node->get_thread_id())); + } #ifdef NAT_TRACE_ - printf(" %.3f : flow_id: %x thread_id %x TCP ack %x\n",now_sec(), node->get_short_fid(), node->get_thread_id(), tcp->getAckNumber()); + printf(" %.3f : flow_id: %x thread_id %x TCP ack %x seq %x\n" + ,now_sec(), node->get_short_fid(), node->get_thread_id(), tcp->getAckNumber() + , tcp->getSeqNumber()); #endif - } - } + } + } } /* in all cases update the ip using the outside ip */ if ( m_pkt_indication.m_desc.IsInitSide() ) { #ifdef NAT_TRACE_ if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) { - printf(" %.3f : DP : i %x:%x -> %x flow_id: %lx\n",now_sec(),node->m_src_ip,node->m_src_port,node->m_dest_ip,node->m_flow_id); + printf(" %.3f : DP : i %x:%x -> %x flow_id: %lx\n",now_sec(), node->m_src_ip + , node->m_src_port, node->m_dest_ip, node->m_flow_id); } #endif + tcp_seq_diff_server = node->get_nat_tcp_seq_diff_server(); ipv4->updateIpSrc(node->m_src_ip); ipv4->updateIpDst(node->m_dest_ip); - }else{ + } else { #ifdef NAT_TRACE_ if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) { - printf(" %.3f : r %x -> %x:%x flow_id: %lx \n",now_sec(),node->m_dest_ip,node->m_src_ip,node->m_src_port,node->m_flow_id); + printf(" %.3f : r %x -> %x:%x flow_id: %lx \n", now_sec(), node->m_dest_ip + , node->m_src_ip, node->m_src_port, node->m_flow_id); } #endif src_port = node->get_nat_ipv4_port(); - ipv4->updateIpSrc(node->get_nat_ipv4_addr_server()); + tcp_seq_diff_client = node->get_nat_tcp_seq_diff_client(); + ipv4->updateIpSrc(node->m_dest_ip); ipv4->updateIpDst(node->get_nat_ipv4_addr()); } @@ -3076,7 +3099,7 @@ inline void CFlowPktInfo::update_pkt_info(char *p, #ifdef NAT_TRACE_ if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) { if ( m_pkt_indication.m_desc.IsInitSide() ==false ){ - printf(" %.3f : pkt ==> %x:%x %x:%x \n",now_sec(),node->get_nat_ipv4_addr(),node->get_nat_ipv4_addr_server(), + printf(" %.3f : pkt ==> %x %x:%x \n",now_sec(),node->get_nat_ipv4_addr(), node->get_nat_ipv4_port(),node->m_src_port); }else{ printf(" %.3f : pkt ==> init pkt sent \n",now_sec()); @@ -3116,8 +3139,10 @@ inline void CFlowPktInfo::update_pkt_info(char *p, /* replace port */ if ( port_dir == CLIENT_SIDE ) { m_tcp->setSourcePort(src_port); + m_tcp->setAckNumber(m_tcp->getAckNumber() + tcp_seq_diff_server); }else{ m_tcp->setDestPort(src_port); + m_tcp->setAckNumber(m_tcp->getAckNumber() + tcp_seq_diff_client); } }else { if ( m_pkt_indication.m_desc.IsUdp() ){ @@ -3352,6 +3377,8 @@ public: class CCapFileFlowInfo { public: + const int LEARN_MODE_MIN_IPG = 10; // msec + enum load_cap_file_err { kOK = 0, kFileNotExist, @@ -3359,9 +3386,14 @@ public: kNoSyn, kTCPOffsetTooBig, kNoTCPFromServer, + kNoTCPSynAck, + kTCPLearnModeBadFlow, kPktNotSupp, kPktProcessFail, - kCapFileErr + kCapFileErr, + kPlugInWithLearn, + kIPOptionNotAllowed, + kTCPIpgTooLow }; bool Create(); @@ -3378,7 +3410,7 @@ public: /* update flow info */ void update_info(); - bool is_valid_template_load_time(std::string & err); + enum CCapFileFlowInfo::load_cap_file_err is_valid_template_load_time(); void save_to_erf(std::string cap_file_name,int pcap); diff --git a/src/common/Network/Packet/TcpHeader.h b/src/common/Network/Packet/TcpHeader.h index c19cd262..97575a60 100755 --- a/src/common/Network/Packet/TcpHeader.h +++ b/src/common/Network/Packet/TcpHeader.h @@ -23,6 +23,11 @@ class TCPHeader { public: + enum TCPHeader_enum_t + { + TCP_INVALID_PORT = 0 + }; + TCPHeader(){} TCPHeader(uint16_t argSourcePort, diff --git a/src/latency.cpp b/src/latency.cpp index 841913cf..b9ce2177 100644 --- a/src/latency.cpp +++ b/src/latency.cpp @@ -387,6 +387,12 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) { if ( ! is_lateancy_pkt) { +#if 0 + TCPHeader *tcp = (TCPHeader *)parser.m_l4; //????? remove + if (parser.m_ipv4->getProtocol() == 0x6 && tcp->getSynFlag()) { + tcp->dump(stdout); //???? remove + } +#endif #ifdef NAT_TRACE_ printf(" %.3f RX : got packet !!! \n",now_sec() ); #endif @@ -436,7 +442,7 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) { m_no_ipv4_option++; return (false); } - m_parent->get_nat_manager()->handle_packet_ipv4(lp,parser.m_ipv4); + m_parent->get_nat_manager()->handle_packet_ipv4(lp, parser.m_ipv4, true); opt_len -= CNatOption::noOPTION_LEN; opt_ptr += CNatOption::noOPTION_LEN; break; @@ -445,10 +451,11 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) { return (false); } // End of switch } // End of while - if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK) - && parser.IsNatInfoPkt()) { - m_parent->get_nat_manager()->handle_packet_ipv4(NULL, parser.m_ipv4); - } + + bool first; + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP) && parser.IsNatInfoPkt(first)) { + m_parent->get_nat_manager()->handle_packet_ipv4(NULL, parser.m_ipv4, first); + } return (true); } // End of check for non-latency packet diff --git a/src/latency.h b/src/latency.h index 724621f0..552b3999 100644 --- a/src/latency.h +++ b/src/latency.h @@ -107,19 +107,27 @@ public: } // Check if this packet contains NAT info in TCP ack - inline bool IsNatInfoPkt() { - if (!m_ipv4 || (m_protocol != IPPROTO_TCP)) { - return false; - } - if (! m_l4 || (m_l4 - rte_pktmbuf_mtod(m_m, uint8_t*) + TCP_HEADER_LEN) > m_m->data_len) { - return false; - } - // If we are here, relevant fields from tcp header are guaranteed to be in first mbuf - TCPHeader *tcp = (TCPHeader *)m_l4; - if (!tcp->getSynFlag() || (tcp->getAckNumber() == 0)) { - return false; - } - return true; + // first - set to true if this is the first packet of the flow. false otherwise. + // relevant only if return value is true + inline bool IsNatInfoPkt(bool &first) { + if (!m_ipv4 || (m_protocol != IPPROTO_TCP)) { + return false; + } + if (! m_l4 || (m_l4 - rte_pktmbuf_mtod(m_m, uint8_t*) + TCP_HEADER_LEN) > m_m->data_len) { + return false; + } + // If we are here, relevant fields from tcp header are guaranteed to be in first mbuf + // We want to handle SYN and SYN+ACK packets + TCPHeader *tcp = (TCPHeader *)m_l4; + if (! tcp->getSynFlag()) + return false; + + if (! tcp->getAckFlag()) { + first = true; + } else { + first = false; + } + return true; } public: diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index a2bfefe3..d5e7c9b5 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -687,9 +687,10 @@ static int usage(){ printf(" --ipv6 : work in ipv6 mode\n"); printf(" --learn (deprecated). Replaced by --learn-mode. To get older behaviour, use --learn-mode 2\n"); - printf(" --learn-mode [1-2] : Work in NAT environments, learn the dynamic NAT translation and ALG \n"); - printf(" 1 Use TCP ACK in first SYN to pass NAT translation information. Will work only for TCP streams. Initial SYN packet must be present in stream.\n"); + printf(" --learn-mode [1-3] : Work in NAT environments, learn the dynamic NAT translation and ALG \n"); + printf(" 1 Use TCP ACK in first SYN to pass NAT translation information. Will work only for TCP streams. Initial SYN packet must be first packet in stream.\n"); printf(" 2 Add special IP option to pass NAT translation information. Will not work on certain firewalls if they drop packets with IP options\n"); + printf(" 3 Like 1, but without support for sequence number randomization in server->clien direction. Performance (flow/second) better than 1\n"); printf(" --learn-verify : Learn the translation, but intended for verification of the mechanism in cases that NAT does not exist \n"); printf(" \n"); printf(" --l-pkt-mode [0-3] : Set mode for sending latency packets.\n"); diff --git a/src/nat_check.cpp b/src/nat_check.cpp index 7e224430..c7262e50 100755 --- a/src/nat_check.cpp +++ b/src/nat_check.cpp @@ -41,7 +41,8 @@ void CGenNodeNatInfo::dump(FILE *fd){ int i; for (i=0; i<m_cnt; i++) { CNatFlowInfo * lp=&m_data[i]; - fprintf (fd," id:%d , external ip:%08x:%x , ex_port: %04x , fid: %d \n",i,lp->m_external_ip,lp->m_external_ip_server,lp->m_external_port,lp->m_fid); + fprintf (fd," id:%d , external ip:%08x , ex_port: %04x , TCP seq:%x fid: %d \n" + , i, lp->m_external_ip, lp->m_external_port, lp->m_tcp_seq, lp->m_fid); } } @@ -51,6 +52,28 @@ void CGenNodeNatInfo::init(){ m_cnt=0; } +bool CNatCheckFlowTableMap::find(uint64_t key, uint32 &val) { + nat_check_flow_map_t::iterator iter; + iter = m_map.find(key); + if (iter != m_map.end() ) { + val = (*iter).second; + return true; + }else{ + return false; + } +} + +void CNatCheckFlowTableMap::dump(FILE *fd) { + nat_check_flow_map_iter_t it; + uint32_t val; + uint64_t key; + + for (it = m_map.begin(); it != m_map.end(); it++) { + val = it->second; + key = it->first; + fprintf(fd, "%lx->%x\n", key, val); + } +} void CNatStats::reset(){ m_total_rx=0; @@ -147,14 +170,17 @@ void CNatRxManager::get_info_from_tcp_ack(uint32_t tcp_ack, uint32_t &fid, uint8 * option - pointer to our proprietary NAT info IP option. * If it is NULL, the NAT info is in the TCP ACK number * ipv4 - pointer to ipv4 header to extract info from. + * is_first - Is this the first packet of the flow or second. To handle firewalls that do + * TCP seq randomization on the server->client side, we also look at the second + * packet of the flow (SYN+ACK), and extract its seq num. */ -void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4) { +void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4, bool is_first) { CNatPerThreadInfo * thread_info; uint32_t fid=0; + uint32_t tcp_seq; /* Extract info from the packet ! */ uint32_t ext_ip = ipv4->getSourceIp(); - uint32_t ext_ip_server = ipv4->getDestIp(); uint8_t proto = ipv4->getProtocol(); /* must be TCP/UDP this is the only supported proto */ if (!( (proto==6) || (proto==17) )){ @@ -165,21 +191,49 @@ void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4) { TCPHeader *tcp = (TCPHeader *) (((char *)ipv4)+ ipv4->getHeaderLength()); uint16_t ext_port = tcp->getSourcePort(); + tcp_seq = tcp->getSeqNumber(); + if (option) { thread_info = get_thread_info(option->get_thread_id()); fid = option->get_fid(); } else { - uint8_t thread_id; - get_info_from_tcp_ack(tcp->getAckNumber(), fid, thread_id); - thread_info = get_thread_info(thread_id); + uint8_t thread_id; + + if (is_first) { + uint32_t tcp_ack = tcp->getAckNumber(); + get_info_from_tcp_ack(tcp_ack, fid, thread_id); + thread_info = get_thread_info(thread_id); + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { + uint32_t dst_ip = ipv4->getDestIp(); + uint16_t dst_port = tcp->getDestPort(); + uint64_t map_key = (dst_ip << 16) + dst_port; + m_fm.insert(map_key, tcp_ack); + } + } else { + uint32_t val; + // server->client packet. IP/port reversed in regard to first SYN packet + uint64_t map_key = (ext_ip << 16) + ext_port; + + if (m_fm.find(map_key, val)) { + get_info_from_tcp_ack(val, fid, thread_id); + thread_info = get_thread_info(thread_id); + m_fm.erase(map_key); + } else { + thread_info = 0; + // ??? Handle error + // ??? handle aging of flow info + } + } } + if (unlikely(!thread_info)) { return; } #ifdef NAT_TRACE_ - printf("rx msg ext ip : %08x:%08x ext port : %04x flow_id : %d \n",ext_ip,ext_ip_server,ext_port, fid); + printf("rx msg ext ip: %08x ext port: %04x TCP Seq: %08x flow_id : %d (%s) \n", ext_ip, ext_port, tcp_seq, fid + , is_first ? "first":"second"); #endif CGenNodeNatInfo * node=thread_info->m_cur_nat_msg; @@ -194,9 +248,13 @@ void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4) { CNatFlowInfo * msg=node->get_next_msg(); /* fill the message */ - msg->m_external_ip = ext_ip; - msg->m_external_ip_server = ext_ip_server; - msg->m_external_port = ext_port; + if (is_first) { + msg->m_external_ip = ext_ip; + msg->m_external_port = ext_port; + } else { + msg->m_external_port = TCPHeader::TCP_INVALID_PORT; + } + msg->m_tcp_seq = tcp_seq; msg->m_fid = fid; msg->m_pad = 0xee; diff --git a/src/nat_check.h b/src/nat_check.h index 133501ae..3b526c0b 100755 --- a/src/nat_check.h +++ b/src/nat_check.h @@ -21,6 +21,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include <map> #include "msg_manager.h" #include <common/Network/Packet/TcpHeader.h> #include <common/Network/Packet/UdpHeader.h> @@ -121,7 +122,7 @@ private: struct CNatFlowInfo { uint32_t m_external_ip; - uint32_t m_external_ip_server; + uint32_t m_tcp_seq; uint32_t m_fid; uint16_t m_external_port; uint16_t m_pad; @@ -210,13 +211,28 @@ public: void Dump(FILE *fd); }; +typedef std::map<uint64_t, uint32_t, std::less<uint64_t> > nat_check_flow_map_t; +typedef nat_check_flow_map_t::iterator nat_check_flow_map_iter_t; + +class CNatCheckFlowTableMap { +public: + void erase(uint64_t key) {m_map.erase(key);} + bool find(uint64_t fid, uint32_t &val); + void insert(uint64_t key, uint32_t val) {m_map.insert(std::pair<uint64_t, uint32_t>(key, val));} + void clear(void) {m_map.clear();} + void dump(FILE *fd); + uint64_t size(void) {return m_map.size();} + +public: + nat_check_flow_map_t m_map; +}; class CNatRxManager { public: bool Create(); void Delete(); - void handle_packet_ipv4(CNatOption * option, IPHeader * ipv4); + void handle_packet_ipv4(CNatOption * option, IPHeader * ipv4, bool is_first); void handle_aging(); void Dump(FILE *fd); void DumpShort(FILE *fd); @@ -232,6 +248,7 @@ private: uint8_t m_max_threads; CNatPerThreadInfo * m_per_thread; CNatStats m_stats; + CNatCheckFlowTableMap m_fm; }; |