BUGFix: Allow the vCGNAPT compile without FTP/SIP functionality
[samplevnf.git] / common / VIL / alg / lib_ftp_alg.c
1 /*
2 // Copyright (c) 2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <app.h>
23 #include <rte_common.h>
24 #include <rte_malloc.h>
25 #include <rte_mbuf.h>
26 #include <rte_ip.h>
27 #include <rte_byteorder.h>
28 #include <rte_table_lpm.h>
29 #include <rte_table_hash.h>
30 #include <rte_pipeline.h>
31 #include <rte_arp.h>
32 #include <rte_icmp.h>
33 #include <rte_hash.h>
34 #include <rte_jhash.h>
35 #include <rte_cycles.h>
36 #include "pipeline_cgnapt_common.h"
37 #include "pipeline_actions_common.h"
38 #include "pipeline_cgnapt_be.h"
39 #include "hash_func.h"
40 #include "lib_ftp_alg.h"
41 #include "vnf_common.h"
42 #include "pipeline_common_be.h"
43 #include "rte_ct_tcp.h"
44 #include "rte_cnxn_tracking.h"
45 #define ALG_DEBUG 1
46
47 #if 1
48 extern uint8_t
49 rte_ct_create_cnxn_hashkey(
50         uint32_t *src_addr,
51         uint32_t *dst_addr,
52         uint16_t src_port,
53         uint16_t dst_port,
54         uint8_t proto,
55         uint32_t *key,
56         uint8_t type);
57 #endif
58
59 struct rte_mbuf *lib_alg_pkt;
60 enum {PRIVATE, PUBLIC};
61 struct rte_hash_parameters ftp_alg_hash_params = {
62         .name = "FTP ALG",
63         .entries = 1024,
64         .reserved = 0,
65         .key_len = sizeof(struct ftp_alg_key),
66         .hash_func = rte_jhash,
67         .hash_func_init_val = 0,
68 };
69
70 struct rte_hash *ftp_alg_hash_handle;
71
72 /**
73  * ftp_alg Init function
74  */
75 void lib_ftp_alg_init(void)
76 {
77 printf("NAT FTP ALG initialization ...\n");
78
79         /* FTP ALG hash table initialization */
80
81         ftp_alg_hash_handle = rte_hash_create(&ftp_alg_hash_params);
82
83         #ifdef ALGDBG
84         if (ftp_alg_hash_handle == NULL)
85                 printf("FTP ALG rte_hash_create failed ...\n");
86         else
87                 printf("ftp_alg_hash_table %p\n\n",
88                         (void *)ftp_alg_hash_handle);
89
90         #endif
91 }
92
93 /*
94  * ftp_alg table retreive function
95  * Input - alg key
96  * Output - Entry
97  */
98
99 struct ftp_alg_table_entry *retrieve_ftp_alg_entry(struct ftp_alg_key alg_key)
100 {
101         struct ftp_alg_table_entry *ret_alg_data = NULL;
102         alg_key.filler1 = 0;
103         alg_key.filler2 = 0;
104
105         int ret = rte_hash_lookup_data(ftp_alg_hash_handle, &alg_key,
106                                                          (void **)&ret_alg_data);
107         if (ret < 0) {
108                 #ifdef ALGDBG
109                 printf("alg-hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
110                                          ret, EINVAL, ENOENT);
111                 #endif
112         } else {
113                 return ret_alg_data;
114         }
115
116         return NULL;
117 }
118
119 /*
120  * ftp_alg table entry delete
121  * Input - ipaddress, portid
122  * Output - sucess or failure
123  */
124 static int remove_ftp_alg_entry(uint32_t ipaddr, uint8_t portid)
125 {
126
127         /* need to lock here if multi-threaded... */
128         /* rte_hash_del_key is not thread safe */
129         struct ftp_alg_key alg_key;
130         alg_key.l4port = rte_bswap16(portid);
131         alg_key.ip_address = rte_bswap32(ipaddr);
132         alg_key.filler1 = 0;
133         alg_key.filler2 = 0;
134
135         #ifdef ALGDBG
136                 printf("remove_alg_entry ip %x, port %d\n", alg_key.ip_address,
137                                          alg_key.l4port);
138         #endif
139         return rte_hash_del_key(ftp_alg_hash_handle, &alg_key);
140 }
141 /*
142  * ftp_alg table entry add
143  * Input - ipaddress, portid
144  * Output - sucess or failure
145  */
146 void
147 populate_ftp_alg_entry(uint32_t ipaddr, uint8_t portid)
148 {
149         /* need to lock here if multi-threaded */
150         /* rte_hash_add_key_data is not thread safe */
151         struct ftp_alg_key alg_key;
152         alg_key.l4port = rte_bswap16(portid);
153         //arp_key.ip = rte_bswap32(ipaddr);
154         alg_key.ip_address = rte_bswap32(ipaddr);
155         alg_key.filler1 = 0;
156         alg_key.filler2 = 0;
157
158
159         //lib_arp_populate_called++;
160
161         #ifdef ALGDBG
162         printf("populate_ftp_alg_entry ip %x, port %d\n", alg_key.ip_address,
163                                          alg_key.l4port);
164         #endif
165
166         struct ftp_alg_table_entry *new_alg_data =
167                 retrieve_ftp_alg_entry(alg_key);
168         if (new_alg_data) {
169                 #ifdef ALGDBG
170                 printf("alg_entry exists ip%x, port %d\n", alg_key.ip_address,
171                                 alg_key.l4port);
172                 #endif
173                 //lib_arp_duplicate_found++;
174                 return;
175         }
176         new_alg_data = (struct ftp_alg_table_entry *)
177                         malloc(sizeof(new_alg_data));
178         //new_alg_data->status = INCOMPLETE;
179         new_alg_data->l4port = rte_bswap16(portid);
180         new_alg_data->ip_address = rte_bswap32(ipaddr);
181         rte_hash_add_key_data(ftp_alg_hash_handle, &alg_key, new_alg_data);
182
183         #ifdef ALGDBG
184                 // print entire hash table
185                 printf
186                                 ("\tALG: table update - ip=%d.%d.%d.%d  on port=%d\n",
187                                  (alg_key.ip_address >> 24),
188                                  ((alg_key.ip_address & 0x00ff0000) >> 16),
189                                  ((alg_key.ip_address & 0x0000ff00) >> 8),
190                                  ((alg_key.ip_address & 0x000000ff)), portid);
191                 /* print_arp_table(); */
192                 puts("");
193         #endif
194 }
195
196 /*
197  * ftp_alg payload modification for PORT and PASV command
198  * Input - cgnapt table entry - for taking the public /translated ip/port ,
199  * incoming PORT/PASV string, Session type - PORT or PASV
200  * Output - Translated string
201  */
202 int ftp_alg_modify_payload(
203         struct cgnapt_table_entry *egress_entry,
204         char *port_string,
205         char *port_string_translated, int ftp_session_type)
206 {
207         uint32_t transport_ip;
208         uint16_t transport_port;
209         uint16_t tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
210         uint16_t new_port_string_length;
211
212         uint8_t *bptr_public_address;
213
214         transport_ip = egress_entry->data.pub_ip;
215         transport_port = egress_entry->data.pub_port;
216         tmp5 = (uint16_t) (transport_port/0x100);
217         tmp6 = (uint16_t) (transport_port % 0x100);
218
219         transport_ip = rte_bswap32(transport_ip);
220
221         bptr_public_address = (uint8_t *) &transport_ip;
222
223         tmp4 = bptr_public_address[3];
224         tmp3 = bptr_public_address[2];
225         tmp2 = bptr_public_address[1];
226         tmp1 = bptr_public_address[0];
227
228         if (ftp_session_type == 1)
229                 sprintf(port_string_translated, FTP_PASV_PARAMETER_STRING,
230                         FTP_PASV_RETURN_CODE, tmp1, tmp2, tmp3, tmp4,
231                         tmp5, tmp6);
232         else
233                 sprintf(port_string_translated, FTP_PORT_PARAMETER_STRING,
234                         tmp1, tmp2, tmp3, tmp4, tmp5, tmp6);
235         #ifdef ALGDBG
236         printf("FTP ALG: FTP new string: Len:%d %s\n",
237                         (uint16_t) strlen(port_string_translated)-2,
238                         port_string_translated);
239
240         printf("FTP non translated PASV string: Len:%d, %s\n",
241                 (uint16_t)strlen(port_string)-2, port_string);
242                 printf("old strlen:%d  new strlen:%d\n",
243                 (int)strlen(port_string),
244                 (int)strlen(port_string_translated));
245         #endif
246
247         return(new_port_string_length =
248                 (uint16_t) strlen(port_string_translated));
249 }
250
251 /*
252  * ftp_alg modify packet len (due to change in len of FTP payload )
253  * Input - pkt
254  * Output - Length append /Trimmed Pkt
255 **/
256 static inline void ftp_alg_modify_pkt_len(struct rte_mbuf *pkt)
257 {
258         uint16_t pkt_length = 0;
259         int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
260         void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
261
262         if (ip_hdr_size_bytes == IPv4_HEADER_SIZE) {
263                 struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)iphdr;
264                 pkt_length = rte_bswap16(ihdr4->total_length) + ETH_HDR_SIZE;
265         } else if (ip_hdr_size_bytes == IPv6_HEADER_SIZE) {
266                 struct ipv6_hdr *ihdr6 = (struct ipv6_hdr *)iphdr;
267                 pkt_length = rte_bswap16(ihdr6->payload_len) +
268                         IPv6_HEADER_SIZE + ETH_HDR_SIZE;
269         }
270
271         uint16_t mbuf_pkt_length = rte_pktmbuf_pkt_len(pkt);
272
273         if (pkt_length == mbuf_pkt_length)
274                 return;
275
276         if (pkt_length < mbuf_pkt_length) {
277                 rte_pktmbuf_trim(pkt, mbuf_pkt_length - pkt_length);
278                 return;
279         }
280
281         /* pkt_length > mbuf_pkt_length */
282         rte_pktmbuf_append(pkt, pkt_length - mbuf_pkt_length);
283 }
284
285 /*
286  * ftp_alg IP HDR size calculation
287  * Input - pkt
288  * Output - Length of IP HDR
289  */
290
291 /* same as rte_ct_get_IP_hdr_size()*/
292 uint16_t ftp_alg_get_IP_hdr_size(struct rte_mbuf *pkt)
293 {
294         /* NOTE: Only supporting IP headers with no options at this time
295         * so header is fixed size
296         */
297
298         uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, IP_START);
299         hdr_chk = hdr_chk >> 4;
300
301         if (hdr_chk == IP_VERSION_4)
302                 return IPv4_HEADER_SIZE;
303         else if (hdr_chk == IP_VERSION_6)
304                 return IPv6_HEADER_SIZE;
305         else            /* Not IPv4 header with no options, return negative. */
306                 return -1;
307
308 }
309
310 /*
311  * ftp_alg checksum re-computing due to change in payload , uses rte function,
312  * if HW Checksum is supported s/w checksum will be disabled
313  * Input - IP HDR and TCP HDR
314  * Output - Length of IP HDR
315  */
316 static void ftp_alg_compute_checksums(
317         void *i_hdr,
318         struct tcp_hdr *t_hdr)
319 /* same as rte_synproxy_compute_checksums*/
320 {
321         /*
322         * calculate IP and TCP checksums.
323         * Note that both checksum routines require
324         * checksum fields to be set to zero, and the the checksum is in the
325         * correct byte order, so no rte_bswap16 is required.
326         */
327
328         int8_t hdr_chk = rte_ct_ipversion(i_hdr);
329         t_hdr->cksum = 0;
330
331         if (hdr_chk == IP_VERSION_4) {
332                 struct ipv4_hdr *i4_hdr = (struct ipv4_hdr *)i_hdr;
333                 i4_hdr->hdr_checksum = 0;
334                 t_hdr->cksum = 0;
335                 t_hdr->cksum = rte_ipv4_udptcp_cksum(i4_hdr, t_hdr);
336
337                 #ifdef ALGDBG
338                 printf("cksum %x\n", rte_bswap32(t_hdr->cksum));
339                 #endif
340
341                 i4_hdr->hdr_checksum = rte_ipv4_cksum(i4_hdr);
342         } else if (hdr_chk == IP_VERSION_6) {
343                 struct ipv6_hdr *i6_hdr = (struct ipv6_hdr *)i_hdr;
344                 t_hdr->cksum = 0;
345                 t_hdr->cksum = rte_ipv6_udptcp_cksum(i6_hdr, t_hdr);
346         }
347 }
348
349 /*
350  * ftp_alg adjusting ACK from other end ;
351  * ACK field of return packet to be adjusted
352  * to the same value of length modified in the payload
353  * Input - pkt, ack diff - delta
354  * Output - None(void)
355  */
356 static void  ftp_alg_adjust_tcp_ack(struct rte_mbuf *pkt, int16_t ackSeqdiff)
357 {
358         /*Since v6 is not supported now*/
359         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
360         struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
361                 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
362         struct tcp_hdr *thdr = (struct tcp_hdr *)
363                 RTE_MBUF_METADATA_UINT32_PTR(pkt,
364                         IP_START + ip_hdr_size_bytes);
365         /*
366         * recv_ack and total length first to be chnaged to host byte order
367         * and then do the addition and then set back to network byte order
368         */
369         uint32_t temp;
370         temp = rte_bswap32(thdr->recv_ack);
371         //printf("%s: ackSeqdiff :%d %u\n", __FUNCTION__, ackSeqdiff, temp);
372         if (ackSeqdiff < 0)
373                 temp += abs(ackSeqdiff);
374         else
375                 temp -= abs(ackSeqdiff);
376
377         thdr->recv_ack = rte_bswap32(temp);
378 }
379 /*
380  * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress  packet
381  * to be adjusted to the same value of length modified in the payload
382  * Input - pkt, ack diff - delta
383  * Output - None(void)
384  */
385
386 static void  ftp_alg_adjust_tcp_seq(struct rte_mbuf *pkt, int16_t ackSeqdiff)
387 {
388         /*Since v6 is not supported now*/
389         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
390         struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
391                 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
392         struct tcp_hdr *thdr = (struct tcp_hdr *)
393                 RTE_MBUF_METADATA_UINT32_PTR(pkt,
394                         IP_START + ip_hdr_size_bytes);
395         uint32_t temp;
396
397         temp = rte_bswap32(thdr->sent_seq);
398         if (ackSeqdiff < 0)
399                 temp -= abs(ackSeqdiff);
400         else
401                 temp += abs(ackSeqdiff);
402
403         thdr->sent_seq = rte_bswap32(temp);
404 }
405 /*
406  * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress  packet
407  * to be adjusted to the same value of length modified in the payload;
408  * This function computes the delta and calls adjust_seq for chaging the packet
409  * Input - pkt,Original incoming String, Translated string and corresponding
410  * lengths of the string
411  * Output - Seq Diff between Original and translated string
412  */
413
414 static int ftp_alg_delta_tcp_sequence(
415         struct rte_mbuf *pkt,
416         char *port_string,
417         int16_t existing_tcpSeqdiff,
418         uint16_t old_port_string_length,
419         uint16_t new_port_string_length)
420 {
421         int16_t current_sequence_number_delta=0;
422         int16_t final_sequence_number_delta;
423         /*Since v6 is not supported now*/
424         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
425         struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
426                                 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
427         struct tcp_hdr *thdr = (struct tcp_hdr *)
428                                 RTE_MBUF_METADATA_UINT32_PTR(pkt,
429                                         IP_START + ip_hdr_size_bytes);
430         /*
431         * recv_ack and total length first to be chnaged to host byte order
432         * and then do the addition and then set back to network byte order
433         */
434         current_sequence_number_delta = (int16_t) (new_port_string_length -
435                                         old_port_string_length);
436         iphdr->total_length = rte_bswap16(iphdr->total_length);
437
438         #ifdef ALGDBG
439         printf("total_length :%u\n", iphdr->total_length);
440         #endif
441         if(current_sequence_number_delta < 0)
442                 iphdr->total_length -= abs(current_sequence_number_delta);
443         else
444                 iphdr->total_length += current_sequence_number_delta;
445
446         iphdr->total_length = rte_bswap16(iphdr->total_length);
447         if (existing_tcpSeqdiff !=0)
448                 ftp_alg_adjust_tcp_seq(pkt,existing_tcpSeqdiff);
449         final_sequence_number_delta= current_sequence_number_delta + existing_tcpSeqdiff;
450         return final_sequence_number_delta;
451 }
452
453
454 /*
455  * ftp_alg dpi - this function parses the packet and does the respective
456  * action based on the type PORT or PASV, based on the direction of packet
457  * (Private or Public) This is called from CGNAPT
458  * Input - cgnapt pipeline struct, cgnapt key, pkt, CT ,
459  * position of packet assigned by CT, direction of packet
460  * Output - None - as it calls respective action functions
461  */
462 void ftp_alg_dpi(
463         struct pipeline_cgnapt *p_nat,
464         struct pipeline_cgnapt_entry_key *nat_entry_key,
465         struct rte_mbuf *pkt,
466         struct rte_ct_cnxn_tracker *cgnat_cnxn_tracker,
467         int32_t ct_position,
468         uint8_t direction)
469 {
470         /*
471         * recv_ack and total length first to be chnaged to host byte order
472         * and then do the addition and then set back to network byte order
473         */
474
475         /*entry key to be framed in cgnat and pass it over here*/
476         char *port_cmd_string;
477         char *port_cmd_end_string;
478         char *tcp_header_end;
479         char *tcp_start;
480
481
482         uint16_t private_port_number;
483         uint16_t public_port_number;
484         uint16_t ip1, ip2, ip3, ip4, port1, port2;
485         int16_t tcpSeqdiff;
486         int16_t ackSeqdiff, ackAdjust;
487         uint32_t private_address;
488         uint32_t public_address;
489         uint8_t *bptr_private_address;
490         /* also for PASV string */
491         char port_string[FTP_MAXIMUM_PORT_STRING_LENGTH];
492         char port_string_translated[FTP_MAXIMUM_PORT_STRING_LENGTH];
493         int16_t new_port_string_length;
494         int16_t old_port_string_length;
495         int dummy_value;
496         struct cgnapt_table_entry *egress_entry, *ingress_entry;
497         uint32_t ct_key[10];
498         uint8_t key_direction;
499         /*Since v6 is not supported now*/
500         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
501
502         struct ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset(pkt,
503                         struct ipv4_hdr *, sizeof(struct ether_hdr));
504         /* TCP and UDP ports at same offset,
505         * just use TCP for offset calculation
506         */
507         struct tcp_hdr *thdr = rte_pktmbuf_mtod_offset(pkt, struct tcp_hdr *,
508                         (sizeof(struct ether_hdr)+sizeof(struct ipv4_hdr)));
509         uint16_t src_port = rte_bswap16(thdr->src_port);
510         uint16_t dst_port = rte_bswap16(thdr->dst_port);
511         uint8_t proto = ip_hdr->next_proto_id;
512         uint32_t src_addr = rte_bswap32(ip_hdr->src_addr);
513         uint32_t dst_addr = rte_bswap32(ip_hdr->dst_addr);
514         uint32_t tmp_tcp_paylod_size;
515
516         #if 0
517         - src_port & dst_port checking to be moved from cgnat to dpi
518         - For control channel
519                 first validation of tcpSeqdiff to be checked
520                 IF <  > 0
521                         ftp_alg_tcp_ack() to be called(this includes PORT
522                         response and PASV response ack as well)
523                         Return
524                 ELSE
525                         the port/pasv paramter checkign to be done
526         - For data channel
527         -retreive ALG entry
528                 IF found
529                         - remove the ALG entry
530                 even if not found(found cases too)
531         - set the bypass flag in the CT session table
532
533         #endif
534
535         #ifdef ALGDBG
536         {
537                 printf("ftp port number: %d, %d\n", src_port, dst_port);
538                 printf("ftp TCP seq num diff: %d\n",
539                         cgnat_cnxn_tracker->hash_table_entries[
540                                         ct_position].tcpSeqdiff);
541                 printf("tcp data offset: %d\n",
542                         ((thdr->data_off & 0xf0) >> 2));
543                 printf("ct position in dpi:%d\n", ct_position);
544         }
545         #endif
546
547         if (src_port == 21 || dst_port == 21)/* Control Channel*/{
548         /* Control Channel Start */
549         /*
550         * need to look for the port or pasv command.  Then have to look for
551         * the IP address and the port address. Then must create a TCP control
552         * block and spoof the port number, and change the ip address, and do
553         * the sequence number setting.
554         */
555         /* Handle TCP headers.*/
556         tcp_start = (char *)thdr;
557
558         /* start of TCP payload */
559         port_cmd_string = (char * )(tcp_start+((thdr->data_off & 0xf0) >> 2));
560         tcp_header_end = port_cmd_string;
561
562         if (direction == PRIVATE) {
563
564                 #ifdef ALGDBG
565                 printf("In PRIVATE  ");
566                 #endif
567
568                 cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_client
569                                 = rte_bswap32(thdr->sent_seq);
570                 cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_client
571                                 = rte_bswap32(thdr->recv_ack);
572                 #ifdef ALGDBG
573                 printf("-->Seq_cli:%u, Ack_cli:%u, Len:%4d\n",
574                         rte_bswap32(thdr->sent_seq),
575                         rte_bswap32(thdr->recv_ack),
576                         (rte_bswap16(ip_hdr->total_length) -
577                         (((thdr->data_off & 0xf0) >> 4) * 4)) - 20);
578                 #endif
579         } else {
580
581                 #ifdef ALGDBG
582                 printf("In PUBLIC  ");
583                 #endif
584                 cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_server
585                                 = rte_bswap32(thdr->sent_seq);
586                 cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_server
587                                 = rte_bswap32(thdr->recv_ack);
588                 #ifdef ALGDBG
589                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
590                 rte_bswap32(thdr->sent_seq), rte_bswap32(thdr->recv_ack),
591                 (ip_hdr->total_length - (((thdr->data_off & 0xf0) >> 2))
592                         - 20));
593                 #endif
594         }
595
596         if (sscanf(port_cmd_string, FTP_PASV_PARAMETER_STRING, &dummy_value,
597                 &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
598                 FTP_PASV_PARAMETER_COUNT){
599
600         sprintf (port_string, FTP_PASV_PARAMETER_STRING, FTP_PASV_RETURN_CODE,
601                 ip1, ip2, ip3, ip4, port1, port2);
602
603         int i = 0;
604         while (port_cmd_string[i] != '\r' && port_cmd_string[i+1] != '\n')
605                 i++;
606
607         i += 2; // now it points to end of port cmd string.
608
609         old_port_string_length = i;
610
611         private_port_number = (uint16_t) (port1 * 0x100 + port2);
612         bptr_private_address = (uint8_t *) &private_address;
613
614         bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
615         bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
616         bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
617         bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
618
619         /* Not needed as got the position from CT*/
620
621         if (direction == PUBLIC) {
622         /*Client in Private, Server in Public*/
623         /* Not to convert in the payload for PASV resp from Pub side*/
624         /* Only Table creation and no payload modification*/
625         /* DAta Channel also no need to create as it will be done by NAT
626         * when initiated by Client later
627         */
628         populate_ftp_alg_entry(private_address, private_port_number);
629         /*
630         * Bypass ALG flag to be set ,
631         * seqnumber -delta either to be 0 or not needed ,
632         * direction checking for all scenarios
633         */
634         cgnat_cnxn_tracker->hash_table_entries[ct_position].
635                         server_direction = SERVER_IN_PUBLIC;
636         cgnat_cnxn_tracker->hash_table_entries[ct_position].
637                         ftp_session_type= 1; // Passive session type
638         } else if (direction == PRIVATE) {
639         /*Client in Public , Server in Private*/
640
641         struct pipeline_cgnapt_entry_key data_channel_key;
642         private_address = rte_bswap32(private_address);
643         data_channel_key.ip = private_address;
644         data_channel_key.port = private_port_number;
645         /* to be checked if it can be passed as param from NAT*/
646         data_channel_key.pid = pkt->port;
647
648         /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
649         /*Will be getting Private IP and port from Server ,
650         * with that NAPT entry egress and ingress can be added ,
651         * for further data channel communication
652         */
653         #ifdef FTP_ALG
654         if (add_dynamic_cgnapt_entry_alg((struct pipeline *)p_nat,
655         &data_channel_key, &egress_entry, &ingress_entry) == 0){
656
657                 #ifdef ALGDBG
658                 printf("Wrong FTP ALG packet\n");
659                 #endif
660                 //p_nat->invalid_packets |= pkt_mask;
661
662                 p_nat->naptDroppedPktCount++;
663
664                 #ifdef CGNAPT_DEBUGGING
665                 p_nat->naptDroppedPktCount4++;
666                 #endif
667                 return;
668         }
669         #endif
670
671         tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
672                         ((thdr->data_off & 0xf0) >> 2) - ip_hdr_size_bytes;
673         cgnat_cnxn_tracker->hash_table_entries[ct_position].
674                         tcp_payload_size = tmp_tcp_paylod_size;
675
676         /*Adding ALG entry , params to be derived from egress entry*/
677         populate_ftp_alg_entry(egress_entry->data.pub_ip,
678                         egress_entry->data.pub_port);
679         /* payload modification */
680         new_port_string_length = ftp_alg_modify_payload(egress_entry,
681                                         port_string,
682                                         port_string_translated, 1);
683         strncpy(tcp_header_end, port_string_translated,
684                 strlen(port_string_translated));
685         tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
686                         cgnat_cnxn_tracker->hash_table_entries
687                         [ct_position].tcpSeqdiff,
688                         old_port_string_length,
689                         new_port_string_length);
690
691         /* same as rte_synproxy_adjust_pkt_length() in ct */
692         ftp_alg_modify_pkt_len(pkt);
693         /*
694         * Store sequence_number_delta in Session_data structure, also bypass
695         * flag to be set as NO (expecting TCP ack from other end then set the
696         * bypass accordingly , handled earlier in the function
697         */
698
699         cgnat_cnxn_tracker->hash_table_entries[ct_position].
700                         alg_bypass_flag = NO_BYPASS;
701         cgnat_cnxn_tracker->hash_table_entries[ct_position].
702                         tcpSeqdiff = tcpSeqdiff;
703         cgnat_cnxn_tracker->hash_table_entries[ct_position].
704                         server_direction = SERVER_IN_PRIVATE;
705         cgnat_cnxn_tracker->hash_table_entries[ct_position].
706                         ftp_session_type = 1; // Passive session type
707                 return;
708
709         } /* PRIVATE dir */
710         } else if (sscanf(port_cmd_string, FTP_PORT_PARAMETER_STRING,
711                         &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
712                                 FTP_PORT_PARAMETER_COUNT){
713
714                 int i = 0;
715                 static uint8_t port_hit;
716                 while (port_cmd_string[i] != '\r' &&
717                         port_cmd_string[i+1] != '\n')
718                         i++;
719
720                 i += 2; // now it points to end of port cmd string.
721
722                 old_port_string_length = i;
723
724                 #ifdef ALGDBG
725                 printf( " Existing Seq Diff = %d", cgnat_cnxn_tracker->
726                         hash_table_entries[ct_position].tcpSeqdiff);
727                 printf("FTP ALG: FTP PORT command length: %d\n",
728                         old_port_string_length);
729                 #endif
730
731                 private_port_number = (uint16_t) (port1 * 0x100 + port2);
732
733                 #ifdef ALGDBG
734                 printf("FTP ALG: private port number before swap: %u\n",
735                                 private_port_number);
736                 #endif
737
738                 bptr_private_address = (uint8_t *) &private_address;
739                 bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
740                 bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
741                 bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
742                 bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
743
744                 sprintf(port_string, FTP_PORT_PARAMETER_STRING, ip1, ip2,
745                                 ip3, ip4, port1, port2);
746
747                 #ifdef ALGDBG
748                 printf("FTP ALG: FTP original PORT string: %d,%s\n",
749                                 (int) strlen(port_string)-2, port_string);
750                 printf("prv addr: %x\n", private_address);
751                 #endif
752
753
754                 if (direction == PUBLIC) {
755                         /* Client in Public*/
756                         /* retreive_cgnat_entry()* for Data Channel*/
757                         /* Pub port and ip address to be used for framing key ,
758                         * the private phrase is a misnomer
759                         */
760                         struct pipeline_cgnapt_entry_key data_channel_key;
761                         data_channel_key.ip = private_address;
762                         data_channel_key.port = private_port_number;
763                         data_channel_key.pid = 0xffff;
764
765
766                         cgnat_cnxn_tracker->hash_table_entries[ct_position].
767                                 server_direction = SERVER_IN_PRIVATE;
768                         cgnat_cnxn_tracker->hash_table_entries[ct_position].
769                                 ftp_session_type= 0; // Active session type
770
771                         /* No payload modificaiton*/
772                         #ifdef ALGDBG
773                         printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
774                         rte_bswap32(thdr->sent_seq),
775                         rte_bswap32(thdr->recv_ack),
776                         (ip_hdr->total_length -
777                                 (((thdr->data_off & 0xf0) >> 2)) - 20));
778                         #endif
779                         populate_ftp_alg_entry(private_address, private_port_number);
780                 } else if (direction == PRIVATE) {
781
782                         /* Client in Private Server in Public*/
783                         /* Populate_alg_entry*/
784                         /*add_dynamic_cgnapt_entry()*/
785                         /* payload modificaion*/
786                         struct pipeline_cgnapt_entry_key data_channel_key;
787                         private_address = rte_bswap32(private_address);
788                         data_channel_key.ip = private_address;
789                         data_channel_key.port = private_port_number;
790                         /* to be checked if it can be passed as param from NAT*/
791                         data_channel_key.pid = pkt->port;
792
793                         /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
794                         /*
795                         * Will be getting Private IP and port from Client ,
796                         * with that NAPT entry egress and ingress can be added ,
797                         * for further data channel communication
798                         */
799
800                         #ifdef FTP_ALG
801                         if (add_dynamic_cgnapt_entry_alg((struct pipeline *)
802                                 p_nat, &data_channel_key, &egress_entry,
803                                 &ingress_entry) == 0){
804
805                                 #ifdef ALGDBG
806                                 printf("Wrong FTP ALG packet\n");
807                                 #endif
808                                 //p_nat->invalid_packets |= pkt_mask;
809                                 p_nat->naptDroppedPktCount++;
810
811                                 #ifdef CGNAPT_DEBUGGING
812                                 p_nat->naptDroppedPktCount4++;
813                                 #endif
814                                 return;
815                         }
816                         #endif
817
818                 tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
819                                         ((thdr->data_off & 0xf0) >> 2) -
820                                         ip_hdr_size_bytes;
821                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
822                         tcp_payload_size = tmp_tcp_paylod_size;
823                 /*ALG entry add, params to be derived from egress entry*/
824
825                 populate_ftp_alg_entry(egress_entry->data.pub_ip,
826                         egress_entry->data.pub_port);
827                 /* payload modification */
828                 new_port_string_length = ftp_alg_modify_payload(egress_entry,
829                                                 port_string,
830                                                 port_string_translated, 0);
831                 strncpy(tcp_header_end, port_string_translated,
832                                 strlen(port_string_translated));
833                 tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
834                                 cgnat_cnxn_tracker->hash_table_entries
835                                 [ct_position].tcpSeqdiff,
836                                 old_port_string_length,
837                                 new_port_string_length);
838                 /* same as rte_synproxy_adjust_pkt_length() in ct */
839                 ftp_alg_modify_pkt_len(pkt);
840
841                 /*
842                 * Store sequence_number_delta in Session_data structure ,
843                 * also bypass flag to be set as NO
844                 * While response from other end is received ,
845                 * modify the ack no using reverse sign of sequen
846                 */
847
848                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
849                         alg_bypass_flag = NO_BYPASS;
850                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
851                         tcpSeqdiff = tcpSeqdiff;
852                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
853                         server_direction = SERVER_IN_PUBLIC;
854                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
855                         ftp_session_type = 0; // Active session type
856
857                 #ifdef ALGDBG
858                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
859                         rte_bswap32(thdr->sent_seq),
860                         rte_bswap32(thdr->recv_ack),
861                         (ip_hdr->total_length -
862                         (((thdr->data_off & 0xf0) >> 2)) - 20));
863
864                 #endif
865                 return;
866                 } /* PRIVATE dir */
867         } /* PORT cmd message */
868
869         if ((ackAdjust=cgnat_cnxn_tracker->hash_table_entries[
870                         ct_position].tcpSeqdiff) != 0) {
871                 if (direction == PRIVATE) {
872                         if (
873                                 cgnat_cnxn_tracker->hash_table_entries
874                                 [ct_position].seq_client !=
875                                 cgnat_cnxn_tracker->hash_table_entries
876                                 [ct_position].ack_server) {
877                                 static int Seqhits;
878                                 ftp_alg_adjust_tcp_seq( pkt,ackAdjust);
879                                 tmp_tcp_paylod_size = rte_bswap16(
880                                         ip_hdr->total_length) -
881                                         ((thdr->data_off & 0xf0) >> 2) -
882                                         ip_hdr_size_bytes;
883                                 cgnat_cnxn_tracker->hash_table_entries
884                                 [ct_position].tcp_payload_size = tmp_tcp_paylod_size;
885                 #ifdef ALGDBG
886                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
887                         rte_bswap32(thdr->sent_seq),
888                         rte_bswap32(thdr->recv_ack),
889                         (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
890                 #endif
891                         }
892                 } else {
893                         if (cgnat_cnxn_tracker->hash_table_entries
894                                 [ct_position].ack_server !=
895                                 (cgnat_cnxn_tracker->hash_table_entries
896                                 [ct_position].seq_client +
897                                 cgnat_cnxn_tracker->hash_table_entries
898                                 [ct_position].tcp_payload_size)) {
899                                 static int Ackhits;
900                                 ftp_alg_adjust_tcp_ack( pkt,ackAdjust);
901                 #ifdef ALGDBG
902                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
903                         rte_bswap32(thdr->sent_seq),
904                         rte_bswap32(thdr->recv_ack),
905                         (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
906                 #endif
907                         }
908                 }
909                 return;
910                         } /* expected_ack and sequence number updation for PUBLIC dir TCP window */
911         } /* Control Channel End */
912         else {
913                 /*remove the ALG entry, retreival is taken care by rte function  */
914                 #ifdef ALGDBG
915                 printf("In Data Channel \n");
916                 #endif
917                 remove_ftp_alg_entry (dst_addr,dst_port);/* remove the ALG entry */
918                 cgnat_cnxn_tracker->hash_table_entries[ct_position].alg_bypass_flag = BYPASS;
919         } /* Data Channel End */
920 }