summaryrefslogtreecommitdiffstats
path: root/common/VIL/alg/lib_ftp_alg.c
diff options
context:
space:
mode:
authorVishwesh M Rudramuni <vishweshmr@gmail.com>2017-04-18 19:41:40 +0530
committerDeepak S <deepak.s@linux.intel.com>2017-04-18 02:59:07 -0700
commit51cd08d9a3f2826088d122e2a5683315c77a2786 (patch)
tree3fac17a8f7bf362f0c77f1003615b2063d900d35 /common/VIL/alg/lib_ftp_alg.c
parent03aef84e240c5be8813634735d825420129f1460 (diff)
common: Adding common library for sample vnf
JIRA: SAMPLEVNF-3 This patch adds common libraries required as part of the sample vnf. This includes the following libraries 1. ACL library 2. SIP 3. FTP 4. Connection tracker 5. L2l3 stack - Interface Manager - ARP & ICMPv4 - ND & ICMPv6 and other common libraries needed for ip pipeline framework Change-Id: I117690b6b63fbcd76974cd7274518484e60980ab Signed-off-by: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com> [Push patch to gerrit] Signed-off-by: Deepak S <deepak.s@linux.intel.com>
Diffstat (limited to 'common/VIL/alg/lib_ftp_alg.c')
-rw-r--r--common/VIL/alg/lib_ftp_alg.c917
1 files changed, 917 insertions, 0 deletions
diff --git a/common/VIL/alg/lib_ftp_alg.c b/common/VIL/alg/lib_ftp_alg.c
new file mode 100644
index 00000000..0a8a0e6d
--- /dev/null
+++ b/common/VIL/alg/lib_ftp_alg.c
@@ -0,0 +1,917 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <app.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_mbuf.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+#include <rte_table_lpm.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+#include <rte_arp.h>
+#include <rte_icmp.h>
+#include <rte_hash.h>
+#include <rte_jhash.h>
+#include <rte_cycles.h>
+#include "pipeline_cgnapt_common.h"
+#include "pipeline_actions_common.h"
+#include "pipeline_cgnapt_be.h"
+#include "hash_func.h"
+#include "lib_ftp_alg.h"
+#include "vnf_common.h"
+#include "pipeline_common_be.h"
+#include "rte_ct_tcp.h"
+#include "rte_cnxn_tracking.h"
+#define ALG_DEBUG 1
+
+#if 1
+extern uint8_t
+rte_ct_create_cnxn_hashkey(
+ uint32_t *src_addr,
+ uint32_t *dst_addr,
+ uint16_t src_port,
+ uint16_t dst_port,
+ uint8_t proto,
+ uint32_t *key,
+ uint8_t type);
+#endif
+
+struct rte_mbuf *lib_alg_pkt;
+enum {PRIVATE, PUBLIC};
+struct rte_hash_parameters ftp_alg_hash_params = {
+ .name = "FTP ALG",
+ .entries = 1024,
+ .reserved = 0,
+ .key_len = sizeof(struct ftp_alg_key),
+ .hash_func = rte_jhash,
+ .hash_func_init_val = 0,
+};
+
+struct rte_hash *ftp_alg_hash_handle;
+
+/**
+ * ftp_alg Init function
+ */
+void lib_ftp_alg_init(void)
+{
+printf("NAT FTP ALG initialization ...\n");
+
+ /* FTP ALG hash table initialization */
+
+ ftp_alg_hash_handle = rte_hash_create(&ftp_alg_hash_params);
+
+ #ifdef ALGDBG
+ if (ftp_alg_hash_handle == NULL)
+ printf("FTP ALG rte_hash_create failed ...\n");
+ else
+ printf("ftp_alg_hash_table %p\n\n",
+ (void *)ftp_alg_hash_handle);
+
+ #endif
+}
+
+/*
+ * ftp_alg table retreive function
+ * Input - alg key
+ * Output - Entry
+ */
+
+struct ftp_alg_table_entry *retrieve_ftp_alg_entry(struct ftp_alg_key alg_key)
+{
+ struct ftp_alg_table_entry *ret_alg_data = NULL;
+ alg_key.filler1 = 0;
+ alg_key.filler2 = 0;
+
+ int ret = rte_hash_lookup_data(ftp_alg_hash_handle, &alg_key,
+ (void **)&ret_alg_data);
+ if (ret < 0) {
+ #ifdef ALGDBG
+ printf("alg-hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
+ ret, EINVAL, ENOENT);
+ #endif
+ } else {
+ return ret_alg_data;
+ }
+
+ return NULL;
+}
+
+/*
+ * ftp_alg table entry delete
+ * Input - ipaddress, portid
+ * Output - sucess or failure
+ */
+static int remove_ftp_alg_entry(uint32_t ipaddr, uint8_t portid)
+{
+
+ /* need to lock here if multi-threaded... */
+ /* rte_hash_del_key is not thread safe */
+ struct ftp_alg_key alg_key;
+ alg_key.l4port = rte_bswap16(portid);
+ alg_key.ip_address = rte_bswap32(ipaddr);
+ alg_key.filler1 = 0;
+ alg_key.filler2 = 0;
+
+ #ifdef ALGDBG
+ printf("remove_alg_entry ip %x, port %d\n", alg_key.ip_address,
+ alg_key.l4port);
+ #endif
+ return rte_hash_del_key(ftp_alg_hash_handle, &alg_key);
+}
+/*
+ * ftp_alg table entry add
+ * Input - ipaddress, portid
+ * Output - sucess or failure
+ */
+void
+populate_ftp_alg_entry(uint32_t ipaddr, uint8_t portid)
+{
+ /* need to lock here if multi-threaded */
+ /* rte_hash_add_key_data is not thread safe */
+ struct ftp_alg_key alg_key;
+ alg_key.l4port = rte_bswap16(portid);
+ //arp_key.ip = rte_bswap32(ipaddr);
+ alg_key.ip_address = rte_bswap32(ipaddr);
+ alg_key.filler1 = 0;
+ alg_key.filler2 = 0;
+
+
+ //lib_arp_populate_called++;
+
+ #ifdef ALGDBG
+ printf("populate_ftp_alg_entry ip %x, port %d\n", alg_key.ip_address,
+ alg_key.l4port);
+ #endif
+
+ struct ftp_alg_table_entry *new_alg_data =
+ retrieve_ftp_alg_entry(alg_key);
+ if (new_alg_data) {
+ #ifdef ALGDBG
+ printf("alg_entry exists ip%x, port %d\n", alg_key.ip_address,
+ alg_key.l4port);
+ #endif
+ //lib_arp_duplicate_found++;
+ return;
+ }
+ new_alg_data = (struct ftp_alg_table_entry *)
+ malloc(sizeof(new_alg_data));
+ //new_alg_data->status = INCOMPLETE;
+ new_alg_data->l4port = rte_bswap16(portid);
+ new_alg_data->ip_address = rte_bswap32(ipaddr);
+ rte_hash_add_key_data(ftp_alg_hash_handle, &alg_key, new_alg_data);
+
+ #ifdef ALGDBG
+ // print entire hash table
+ printf
+ ("\tALG: table update - ip=%d.%d.%d.%d on port=%d\n",
+ (alg_key.ip_address >> 24),
+ ((alg_key.ip_address & 0x00ff0000) >> 16),
+ ((alg_key.ip_address & 0x0000ff00) >> 8),
+ ((alg_key.ip_address & 0x000000ff)), portid);
+ /* print_arp_table(); */
+ puts("");
+ #endif
+}
+
+/*
+ * ftp_alg payload modification for PORT and PASV command
+ * Input - cgnapt table entry - for taking the public /translated ip/port ,
+ * incoming PORT/PASV string, Session type - PORT or PASV
+ * Output - Translated string
+ */
+int ftp_alg_modify_payload(
+ struct cgnapt_table_entry *egress_entry,
+ char *port_string,
+ char *port_string_translated, int ftp_session_type)
+{
+ uint32_t transport_ip;
+ uint16_t transport_port;
+ uint16_t tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ uint16_t new_port_string_length;
+
+ uint8_t *bptr_public_address;
+
+ transport_ip = egress_entry->data.pub_ip;
+ transport_port = egress_entry->data.pub_port;
+ tmp5 = (uint16_t) (transport_port/0x100);
+ tmp6 = (uint16_t) (transport_port % 0x100);
+
+ transport_ip = rte_bswap32(transport_ip);
+
+ bptr_public_address = (uint8_t *) &transport_ip;
+
+ tmp4 = bptr_public_address[3];
+ tmp3 = bptr_public_address[2];
+ tmp2 = bptr_public_address[1];
+ tmp1 = bptr_public_address[0];
+
+ if (ftp_session_type == 1)
+ sprintf(port_string_translated, FTP_PASV_PARAMETER_STRING,
+ FTP_PASV_RETURN_CODE, tmp1, tmp2, tmp3, tmp4,
+ tmp5, tmp6);
+ else
+ sprintf(port_string_translated, FTP_PORT_PARAMETER_STRING,
+ tmp1, tmp2, tmp3, tmp4, tmp5, tmp6);
+ #ifdef ALGDBG
+ printf("FTP ALG: FTP new string: Len:%d %s\n",
+ (uint16_t) strlen(port_string_translated)-2,
+ port_string_translated);
+
+ printf("FTP non translated PASV string: Len:%d, %s\n",
+ (uint16_t)strlen(port_string)-2, port_string);
+ printf("old strlen:%d new strlen:%d\n",
+ (int)strlen(port_string),
+ (int)strlen(port_string_translated));
+ #endif
+
+ return(new_port_string_length =
+ (uint16_t) strlen(port_string_translated));
+}
+
+/*
+ * ftp_alg modify packet len (due to change in len of FTP payload )
+ * Input - pkt
+ * Output - Length append /Trimmed Pkt
+**/
+static inline void ftp_alg_modify_pkt_len(struct rte_mbuf *pkt)
+{
+ uint16_t pkt_length = 0;
+ int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
+ void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+
+ if (ip_hdr_size_bytes == IPv4_HEADER_SIZE) {
+ struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)iphdr;
+ pkt_length = rte_bswap16(ihdr4->total_length) + ETH_HDR_SIZE;
+ } else if (ip_hdr_size_bytes == IPv6_HEADER_SIZE) {
+ struct ipv6_hdr *ihdr6 = (struct ipv6_hdr *)iphdr;
+ pkt_length = rte_bswap16(ihdr6->payload_len) +
+ IPv6_HEADER_SIZE + ETH_HDR_SIZE;
+ }
+
+ uint16_t mbuf_pkt_length = rte_pktmbuf_pkt_len(pkt);
+
+ if (pkt_length == mbuf_pkt_length)
+ return;
+
+ if (pkt_length < mbuf_pkt_length) {
+ rte_pktmbuf_trim(pkt, mbuf_pkt_length - pkt_length);
+ return;
+ }
+
+ /* pkt_length > mbuf_pkt_length */
+ rte_pktmbuf_append(pkt, pkt_length - mbuf_pkt_length);
+}
+
+/*
+ * ftp_alg IP HDR size calculation
+ * Input - pkt
+ * Output - Length of IP HDR
+ */
+
+/* same as rte_ct_get_IP_hdr_size()*/
+uint16_t ftp_alg_get_IP_hdr_size(struct rte_mbuf *pkt)
+{
+ /* NOTE: Only supporting IP headers with no options at this time
+ * so header is fixed size
+ */
+
+ uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, IP_START);
+ hdr_chk = hdr_chk >> 4;
+
+ if (hdr_chk == IP_VERSION_4)
+ return IPv4_HEADER_SIZE;
+ else if (hdr_chk == IP_VERSION_6)
+ return IPv6_HEADER_SIZE;
+ else /* Not IPv4 header with no options, return negative. */
+ return -1;
+
+}
+
+/*
+ * ftp_alg checksum re-computing due to change in payload , uses rte function,
+ * if HW Checksum is supported s/w checksum will be disabled
+ * Input - IP HDR and TCP HDR
+ * Output - Length of IP HDR
+ */
+static void ftp_alg_compute_checksums(
+ void *i_hdr,
+ struct tcp_hdr *t_hdr)
+/* same as rte_synproxy_compute_checksums*/
+{
+ /*
+ * calculate IP and TCP checksums.
+ * Note that both checksum routines require
+ * checksum fields to be set to zero, and the the checksum is in the
+ * correct byte order, so no rte_bswap16 is required.
+ */
+
+ int8_t hdr_chk = rte_ct_ipversion(i_hdr);
+ t_hdr->cksum = 0;
+
+ if (hdr_chk == IP_VERSION_4) {
+ struct ipv4_hdr *i4_hdr = (struct ipv4_hdr *)i_hdr;
+ i4_hdr->hdr_checksum = 0;
+ t_hdr->cksum = 0;
+ t_hdr->cksum = rte_ipv4_udptcp_cksum(i4_hdr, t_hdr);
+
+ #ifdef ALGDBG
+ printf("cksum %x\n", rte_bswap32(t_hdr->cksum));
+ #endif
+
+ i4_hdr->hdr_checksum = rte_ipv4_cksum(i4_hdr);
+ } else if (hdr_chk == IP_VERSION_6) {
+ struct ipv6_hdr *i6_hdr = (struct ipv6_hdr *)i_hdr;
+ t_hdr->cksum = 0;
+ t_hdr->cksum = rte_ipv6_udptcp_cksum(i6_hdr, t_hdr);
+ }
+}
+
+/*
+ * ftp_alg adjusting ACK from other end ;
+ * ACK field of return packet to be adjusted
+ * to the same value of length modified in the payload
+ * Input - pkt, ack diff - delta
+ * Output - None(void)
+ */
+static void ftp_alg_adjust_tcp_ack(struct rte_mbuf *pkt, int16_t ackSeqdiff)
+{
+ /*Since v6 is not supported now*/
+ uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
+ struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
+ RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+ struct tcp_hdr *thdr = (struct tcp_hdr *)
+ RTE_MBUF_METADATA_UINT32_PTR(pkt,
+ IP_START + ip_hdr_size_bytes);
+ /*
+ * recv_ack and total length first to be chnaged to host byte order
+ * and then do the addition and then set back to network byte order
+ */
+ uint32_t temp;
+ temp = rte_bswap32(thdr->recv_ack);
+ //printf("%s: ackSeqdiff :%d %u\n", __FUNCTION__, ackSeqdiff, temp);
+ if (ackSeqdiff < 0)
+ temp += abs(ackSeqdiff);
+ else
+ temp -= abs(ackSeqdiff);
+
+ thdr->recv_ack = rte_bswap32(temp);
+}
+/*
+ * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress packet
+ * to be adjusted to the same value of length modified in the payload
+ * Input - pkt, ack diff - delta
+ * Output - None(void)
+ */
+
+static void ftp_alg_adjust_tcp_seq(struct rte_mbuf *pkt, int16_t ackSeqdiff)
+{
+ /*Since v6 is not supported now*/
+ uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
+ struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
+ RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+ struct tcp_hdr *thdr = (struct tcp_hdr *)
+ RTE_MBUF_METADATA_UINT32_PTR(pkt,
+ IP_START + ip_hdr_size_bytes);
+ uint32_t temp;
+
+ temp = rte_bswap32(thdr->sent_seq);
+ if (ackSeqdiff < 0)
+ temp -= abs(ackSeqdiff);
+ else
+ temp += abs(ackSeqdiff);
+
+ thdr->sent_seq = rte_bswap32(temp);
+}
+/*
+ * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress packet
+ * to be adjusted to the same value of length modified in the payload;
+ * This function computes the delta and calls adjust_seq for chaging the packet
+ * Input - pkt,Original incoming String, Translated string and corresponding
+ * lengths of the string
+ * Output - Seq Diff between Original and translated string
+ */
+
+static int ftp_alg_delta_tcp_sequence(
+ struct rte_mbuf *pkt,
+ char *port_string,
+ int16_t existing_tcpSeqdiff,
+ uint16_t old_port_string_length,
+ uint16_t new_port_string_length)
+{
+ int16_t current_sequence_number_delta=0;
+ int16_t final_sequence_number_delta;
+ /*Since v6 is not supported now*/
+ uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
+ struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
+ RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
+ struct tcp_hdr *thdr = (struct tcp_hdr *)
+ RTE_MBUF_METADATA_UINT32_PTR(pkt,
+ IP_START + ip_hdr_size_bytes);
+ /*
+ * recv_ack and total length first to be chnaged to host byte order
+ * and then do the addition and then set back to network byte order
+ */
+ current_sequence_number_delta = (int16_t) (new_port_string_length -
+ old_port_string_length);
+ iphdr->total_length = rte_bswap16(iphdr->total_length);
+
+ #ifdef ALGDBG
+ printf("total_length :%u\n", iphdr->total_length);
+ #endif
+ if(current_sequence_number_delta < 0)
+ iphdr->total_length -= abs(current_sequence_number_delta);
+ else
+ iphdr->total_length += current_sequence_number_delta;
+
+ iphdr->total_length = rte_bswap16(iphdr->total_length);
+ if (existing_tcpSeqdiff !=0)
+ ftp_alg_adjust_tcp_seq(pkt,existing_tcpSeqdiff);
+ final_sequence_number_delta= current_sequence_number_delta + existing_tcpSeqdiff;
+ return final_sequence_number_delta;
+}
+
+
+/*
+ * ftp_alg dpi - this function parses the packet and does the respective
+ * action based on the type PORT or PASV, based on the direction of packet
+ * (Private or Public) This is called from CGNAPT
+ * Input - cgnapt pipeline struct, cgnapt key, pkt, CT ,
+ * position of packet assigned by CT, direction of packet
+ * Output - None - as it calls respective action functions
+ */
+void ftp_alg_dpi(
+ struct pipeline_cgnapt *p_nat,
+ struct pipeline_cgnapt_entry_key *nat_entry_key,
+ struct rte_mbuf *pkt,
+ struct rte_ct_cnxn_tracker *cgnat_cnxn_tracker,
+ int32_t ct_position,
+ uint8_t direction)
+{
+ /*
+ * recv_ack and total length first to be chnaged to host byte order
+ * and then do the addition and then set back to network byte order
+ */
+
+ /*entry key to be framed in cgnat and pass it over here*/
+ char *port_cmd_string;
+ char *port_cmd_end_string;
+ char *tcp_header_end;
+ char *tcp_start;
+
+
+ uint16_t private_port_number;
+ uint16_t public_port_number;
+ uint16_t ip1, ip2, ip3, ip4, port1, port2;
+ int16_t tcpSeqdiff;
+ int16_t ackSeqdiff, ackAdjust;
+ uint32_t private_address;
+ uint32_t public_address;
+ uint8_t *bptr_private_address;
+ /* also for PASV string */
+ char port_string[FTP_MAXIMUM_PORT_STRING_LENGTH];
+ char port_string_translated[FTP_MAXIMUM_PORT_STRING_LENGTH];
+ int16_t new_port_string_length;
+ int16_t old_port_string_length;
+ int dummy_value;
+ struct cgnapt_table_entry *egress_entry, *ingress_entry;
+ uint32_t ct_key[10];
+ uint8_t key_direction;
+ /*Since v6 is not supported now*/
+ uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
+
+ struct ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset(pkt,
+ struct ipv4_hdr *, sizeof(struct ether_hdr));
+ /* TCP and UDP ports at same offset,
+ * just use TCP for offset calculation
+ */
+ struct tcp_hdr *thdr = rte_pktmbuf_mtod_offset(pkt, struct tcp_hdr *,
+ (sizeof(struct ether_hdr)+sizeof(struct ipv4_hdr)));
+ uint16_t src_port = rte_bswap16(thdr->src_port);
+ uint16_t dst_port = rte_bswap16(thdr->dst_port);
+ uint8_t proto = ip_hdr->next_proto_id;
+ uint32_t src_addr = rte_bswap32(ip_hdr->src_addr);
+ uint32_t dst_addr = rte_bswap32(ip_hdr->dst_addr);
+ uint32_t tmp_tcp_paylod_size;
+
+ #if 0
+ - src_port & dst_port checking to be moved from cgnat to dpi
+ - For control channel
+ first validation of tcpSeqdiff to be checked
+ IF < > 0
+ ftp_alg_tcp_ack() to be called(this includes PORT
+ response and PASV response ack as well)
+ Return
+ ELSE
+ the port/pasv paramter checkign to be done
+ - For data channel
+ -retreive ALG entry
+ IF found
+ - remove the ALG entry
+ even if not found(found cases too)
+ - set the bypass flag in the CT session table
+
+ #endif
+
+ #ifdef ALGDBG
+ {
+ printf("ftp port number: %d, %d\n", src_port, dst_port);
+ printf("ftp TCP seq num diff: %d\n",
+ cgnat_cnxn_tracker->hash_table_entries[
+ ct_position].tcpSeqdiff);
+ printf("tcp data offset: %d\n",
+ ((thdr->data_off & 0xf0) >> 2));
+ printf("ct position in dpi:%d\n", ct_position);
+ }
+ #endif
+
+ if (src_port == 21 || dst_port == 21)/* Control Channel*/{
+ /* Control Channel Start */
+ /*
+ * need to look for the port or pasv command. Then have to look for
+ * the IP address and the port address. Then must create a TCP control
+ * block and spoof the port number, and change the ip address, and do
+ * the sequence number setting.
+ */
+ /* Handle TCP headers.*/
+ tcp_start = (char *)thdr;
+
+ /* start of TCP payload */
+ port_cmd_string = (char * )(tcp_start+((thdr->data_off & 0xf0) >> 2));
+ tcp_header_end = port_cmd_string;
+
+ if (direction == PRIVATE) {
+
+ #ifdef ALGDBG
+ printf("In PRIVATE ");
+ #endif
+
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_client
+ = rte_bswap32(thdr->sent_seq);
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_client
+ = rte_bswap32(thdr->recv_ack);
+ #ifdef ALGDBG
+ printf("-->Seq_cli:%u, Ack_cli:%u, Len:%4d\n",
+ rte_bswap32(thdr->sent_seq),
+ rte_bswap32(thdr->recv_ack),
+ (rte_bswap16(ip_hdr->total_length) -
+ (((thdr->data_off & 0xf0) >> 4) * 4)) - 20);
+ #endif
+ } else {
+
+ #ifdef ALGDBG
+ printf("In PUBLIC ");
+ #endif
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_server
+ = rte_bswap32(thdr->sent_seq);
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_server
+ = rte_bswap32(thdr->recv_ack);
+ #ifdef ALGDBG
+ printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+ rte_bswap32(thdr->sent_seq), rte_bswap32(thdr->recv_ack),
+ (ip_hdr->total_length - (((thdr->data_off & 0xf0) >> 2))
+ - 20));
+ #endif
+ }
+
+ if (sscanf(port_cmd_string, FTP_PASV_PARAMETER_STRING, &dummy_value,
+ &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
+ FTP_PASV_PARAMETER_COUNT){
+
+ sprintf (port_string, FTP_PASV_PARAMETER_STRING, FTP_PASV_RETURN_CODE,
+ ip1, ip2, ip3, ip4, port1, port2);
+
+ int i = 0;
+ while (port_cmd_string[i] != '\r' && port_cmd_string[i+1] != '\n')
+ i++;
+
+ i += 2; // now it points to end of port cmd string.
+
+ old_port_string_length = i;
+
+ private_port_number = (uint16_t) (port1 * 0x100 + port2);
+ bptr_private_address = (uint8_t *) &private_address;
+
+ bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
+ bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
+ bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
+ bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
+
+ /* Not needed as got the position from CT*/
+
+ if (direction == PUBLIC) {
+ /*Client in Private, Server in Public*/
+ /* Not to convert in the payload for PASV resp from Pub side*/
+ /* Only Table creation and no payload modification*/
+ /* DAta Channel also no need to create as it will be done by NAT
+ * when initiated by Client later
+ */
+ populate_ftp_alg_entry(private_address, private_port_number);
+ /*
+ * Bypass ALG flag to be set ,
+ * seqnumber -delta either to be 0 or not needed ,
+ * direction checking for all scenarios
+ */
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ server_direction = SERVER_IN_PUBLIC;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ ftp_session_type= 1; // Passive session type
+ } else if (direction == PRIVATE) {
+ /*Client in Public , Server in Private*/
+
+ struct pipeline_cgnapt_entry_key data_channel_key;
+ private_address = rte_bswap32(private_address);
+ data_channel_key.ip = private_address;
+ data_channel_key.port = private_port_number;
+ /* to be checked if it can be passed as param from NAT*/
+ data_channel_key.pid = pkt->port;
+
+ /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
+ /*Will be getting Private IP and port from Server ,
+ * with that NAPT entry egress and ingress can be added ,
+ * for further data channel communication
+ */
+
+ if (add_dynamic_cgnapt_entry_alg((struct pipeline *)p_nat,
+ &data_channel_key, &egress_entry, &ingress_entry) == 0){
+
+ #ifdef ALGDBG
+ printf("Wrong FTP ALG packet\n");
+ #endif
+ //p_nat->invalid_packets |= pkt_mask;
+
+ p_nat->naptDroppedPktCount++;
+
+ #ifdef CGNAPT_DEBUGGING
+ p_nat->naptDroppedPktCount4++;
+ #endif
+ return;
+ }
+
+ tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
+ ((thdr->data_off & 0xf0) >> 2) - ip_hdr_size_bytes;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ tcp_payload_size = tmp_tcp_paylod_size;
+
+ /*Adding ALG entry , params to be derived from egress entry*/
+ populate_ftp_alg_entry(egress_entry->data.pub_ip,
+ egress_entry->data.pub_port);
+ /* payload modification */
+ new_port_string_length = ftp_alg_modify_payload(egress_entry,
+ port_string,
+ port_string_translated, 1);
+ strncpy(tcp_header_end, port_string_translated,
+ strlen(port_string_translated));
+ tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
+ cgnat_cnxn_tracker->hash_table_entries
+ [ct_position].tcpSeqdiff,
+ old_port_string_length,
+ new_port_string_length);
+
+ /* same as rte_synproxy_adjust_pkt_length() in ct */
+ ftp_alg_modify_pkt_len(pkt);
+ /*
+ * Store sequence_number_delta in Session_data structure, also bypass
+ * flag to be set as NO (expecting TCP ack from other end then set the
+ * bypass accordingly , handled earlier in the function
+ */
+
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ alg_bypass_flag = NO_BYPASS;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ tcpSeqdiff = tcpSeqdiff;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ server_direction = SERVER_IN_PRIVATE;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ ftp_session_type = 1; // Passive session type
+ return;
+
+ } /* PRIVATE dir */
+ } else if (sscanf(port_cmd_string, FTP_PORT_PARAMETER_STRING,
+ &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
+ FTP_PORT_PARAMETER_COUNT){
+
+ int i = 0;
+ static uint8_t port_hit;
+ while (port_cmd_string[i] != '\r' &&
+ port_cmd_string[i+1] != '\n')
+ i++;
+
+ i += 2; // now it points to end of port cmd string.
+
+ old_port_string_length = i;
+
+ #ifdef ALGDBG
+ printf( " Existing Seq Diff = %d", cgnat_cnxn_tracker->
+ hash_table_entries[ct_position].tcpSeqdiff);
+ printf("FTP ALG: FTP PORT command length: %d\n",
+ old_port_string_length);
+ #endif
+
+ private_port_number = (uint16_t) (port1 * 0x100 + port2);
+
+ #ifdef ALGDBG
+ printf("FTP ALG: private port number before swap: %u\n",
+ private_port_number);
+ #endif
+
+ bptr_private_address = (uint8_t *) &private_address;
+ bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
+ bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
+ bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
+ bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
+
+ sprintf(port_string, FTP_PORT_PARAMETER_STRING, ip1, ip2,
+ ip3, ip4, port1, port2);
+
+ #ifdef ALGDBG
+ printf("FTP ALG: FTP original PORT string: %d,%s\n",
+ (int) strlen(port_string)-2, port_string);
+ printf("prv addr: %x\n", private_address);
+ #endif
+
+
+ if (direction == PUBLIC) {
+ /* Client in Public*/
+ /* retreive_cgnat_entry()* for Data Channel*/
+ /* Pub port and ip address to be used for framing key ,
+ * the private phrase is a misnomer
+ */
+ struct pipeline_cgnapt_entry_key data_channel_key;
+ data_channel_key.ip = private_address;
+ data_channel_key.port = private_port_number;
+ data_channel_key.pid = 0xffff;
+
+
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ server_direction = SERVER_IN_PRIVATE;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ ftp_session_type= 0; // Active session type
+
+ /* No payload modificaiton*/
+ #ifdef ALGDBG
+ printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+ rte_bswap32(thdr->sent_seq),
+ rte_bswap32(thdr->recv_ack),
+ (ip_hdr->total_length -
+ (((thdr->data_off & 0xf0) >> 2)) - 20));
+ #endif
+ populate_ftp_alg_entry(private_address, private_port_number);
+ } else if (direction == PRIVATE) {
+
+ /* Client in Private Server in Public*/
+ /* Populate_alg_entry*/
+ /*add_dynamic_cgnapt_entry()*/
+ /* payload modificaion*/
+ struct pipeline_cgnapt_entry_key data_channel_key;
+ private_address = rte_bswap32(private_address);
+ data_channel_key.ip = private_address;
+ data_channel_key.port = private_port_number;
+ /* to be checked if it can be passed as param from NAT*/
+ data_channel_key.pid = pkt->port;
+
+ /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
+ /*
+ * Will be getting Private IP and port from Client ,
+ * with that NAPT entry egress and ingress can be added ,
+ * for further data channel communication
+ */
+
+ if (add_dynamic_cgnapt_entry_alg((struct pipeline *)
+ p_nat, &data_channel_key, &egress_entry,
+ &ingress_entry) == 0){
+
+ #ifdef ALGDBG
+ printf("Wrong FTP ALG packet\n");
+ #endif
+ //p_nat->invalid_packets |= pkt_mask;
+ p_nat->naptDroppedPktCount++;
+
+ #ifdef CGNAPT_DEBUGGING
+ p_nat->naptDroppedPktCount4++;
+ #endif
+ return;
+ }
+
+ tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
+ ((thdr->data_off & 0xf0) >> 2) -
+ ip_hdr_size_bytes;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ tcp_payload_size = tmp_tcp_paylod_size;
+ /*ALG entry add, params to be derived from egress entry*/
+
+ populate_ftp_alg_entry(egress_entry->data.pub_ip,
+ egress_entry->data.pub_port);
+ /* payload modification */
+ new_port_string_length = ftp_alg_modify_payload(egress_entry,
+ port_string,
+ port_string_translated, 0);
+ strncpy(tcp_header_end, port_string_translated,
+ strlen(port_string_translated));
+ tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
+ cgnat_cnxn_tracker->hash_table_entries
+ [ct_position].tcpSeqdiff,
+ old_port_string_length,
+ new_port_string_length);
+ /* same as rte_synproxy_adjust_pkt_length() in ct */
+ ftp_alg_modify_pkt_len(pkt);
+
+ /*
+ * Store sequence_number_delta in Session_data structure ,
+ * also bypass flag to be set as NO
+ * While response from other end is received ,
+ * modify the ack no using reverse sign of sequen
+ */
+
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ alg_bypass_flag = NO_BYPASS;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ tcpSeqdiff = tcpSeqdiff;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ server_direction = SERVER_IN_PUBLIC;
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].
+ ftp_session_type = 0; // Active session type
+
+ #ifdef ALGDBG
+ printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+ rte_bswap32(thdr->sent_seq),
+ rte_bswap32(thdr->recv_ack),
+ (ip_hdr->total_length -
+ (((thdr->data_off & 0xf0) >> 2)) - 20));
+
+ #endif
+ return;
+ } /* PRIVATE dir */
+ } /* PORT cmd message */
+
+ if ((ackAdjust=cgnat_cnxn_tracker->hash_table_entries[
+ ct_position].tcpSeqdiff) != 0) {
+ if (direction == PRIVATE) {
+ if (
+ cgnat_cnxn_tracker->hash_table_entries
+ [ct_position].seq_client !=
+ cgnat_cnxn_tracker->hash_table_entries
+ [ct_position].ack_server) {
+ static int Seqhits;
+ ftp_alg_adjust_tcp_seq( pkt,ackAdjust);
+ tmp_tcp_paylod_size = rte_bswap16(
+ ip_hdr->total_length) -
+ ((thdr->data_off & 0xf0) >> 2) -
+ ip_hdr_size_bytes;
+ cgnat_cnxn_tracker->hash_table_entries
+ [ct_position].tcp_payload_size = tmp_tcp_paylod_size;
+ #ifdef ALGDBG
+ printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+ rte_bswap32(thdr->sent_seq),
+ rte_bswap32(thdr->recv_ack),
+ (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
+ #endif
+ }
+ } else {
+ if (cgnat_cnxn_tracker->hash_table_entries
+ [ct_position].ack_server !=
+ (cgnat_cnxn_tracker->hash_table_entries
+ [ct_position].seq_client +
+ cgnat_cnxn_tracker->hash_table_entries
+ [ct_position].tcp_payload_size)) {
+ static int Ackhits;
+ ftp_alg_adjust_tcp_ack( pkt,ackAdjust);
+ #ifdef ALGDBG
+ printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
+ rte_bswap32(thdr->sent_seq),
+ rte_bswap32(thdr->recv_ack),
+ (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
+ #endif
+ }
+ }
+ return;
+ } /* expected_ack and sequence number updation for PUBLIC dir TCP window */
+ } /* Control Channel End */
+ else {
+ /*remove the ALG entry, retreival is taken care by rte function */
+ #ifdef ALGDBG
+ printf("In Data Channel \n");
+ #endif
+ remove_ftp_alg_entry (dst_addr,dst_port);/* remove the ALG entry */
+ cgnat_cnxn_tracker->hash_table_entries[ct_position].alg_bypass_flag = BYPASS;
+ } /* Data Channel End */
+}