common code: KW fixes for common code
[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(struct ftp_alg_table_entry));
178
179         if (!new_alg_data) {
180                 printf("new_alg_data could not be allocated\n");
181                 return;
182         }
183
184         //new_alg_data->status = INCOMPLETE;
185         new_alg_data->l4port = rte_bswap16(portid);
186         new_alg_data->ip_address = rte_bswap32(ipaddr);
187         rte_hash_add_key_data(ftp_alg_hash_handle, &alg_key, new_alg_data);
188
189         #ifdef ALGDBG
190                 // print entire hash table
191                 printf
192                                 ("\tALG: table update - ip=%d.%d.%d.%d  on port=%d\n",
193                                  (alg_key.ip_address >> 24),
194                                  ((alg_key.ip_address & 0x00ff0000) >> 16),
195                                  ((alg_key.ip_address & 0x0000ff00) >> 8),
196                                  ((alg_key.ip_address & 0x000000ff)), portid);
197                 /* print_arp_table(); */
198                 puts("");
199         #endif
200 }
201
202 /*
203  * ftp_alg payload modification for PORT and PASV command
204  * Input - cgnapt table entry - for taking the public /translated ip/port ,
205  * incoming PORT/PASV string, Session type - PORT or PASV
206  * Output - Translated string
207  */
208 int ftp_alg_modify_payload(
209         struct cgnapt_table_entry *egress_entry,
210         char *port_string,
211         char *port_string_translated, int ftp_session_type)
212 {
213         uint32_t transport_ip;
214         uint16_t transport_port;
215         uint16_t tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
216         uint16_t new_port_string_length;
217
218         uint8_t *bptr_public_address;
219
220         transport_ip = egress_entry->data.pub_ip;
221         transport_port = egress_entry->data.pub_port;
222         tmp5 = (uint16_t) (transport_port/0x100);
223         tmp6 = (uint16_t) (transport_port % 0x100);
224
225         transport_ip = rte_bswap32(transport_ip);
226
227         bptr_public_address = (uint8_t *) &transport_ip;
228
229         tmp4 = bptr_public_address[3];
230         tmp3 = bptr_public_address[2];
231         tmp2 = bptr_public_address[1];
232         tmp1 = bptr_public_address[0];
233
234         if (ftp_session_type == 1)
235                 sprintf(port_string_translated, FTP_PASV_PARAMETER_STRING,
236                         FTP_PASV_RETURN_CODE, tmp1, tmp2, tmp3, tmp4,
237                         tmp5, tmp6);
238         else
239                 sprintf(port_string_translated, FTP_PORT_PARAMETER_STRING,
240                         tmp1, tmp2, tmp3, tmp4, tmp5, tmp6);
241         #ifdef ALGDBG
242         printf("FTP ALG: FTP new string: Len:%d %s\n",
243                         (uint16_t) strlen(port_string_translated)-2,
244                         port_string_translated);
245
246         printf("FTP non translated PASV string: Len:%d, %s\n",
247                 (uint16_t)strlen(port_string)-2, port_string);
248                 printf("old strlen:%d  new strlen:%d\n",
249                 (int)strlen(port_string),
250                 (int)strlen(port_string_translated));
251         #endif
252
253         return(new_port_string_length =
254                 (uint16_t) strlen(port_string_translated));
255 }
256
257 /*
258  * ftp_alg modify packet len (due to change in len of FTP payload )
259  * Input - pkt
260  * Output - Length append /Trimmed Pkt
261 **/
262 static inline void ftp_alg_modify_pkt_len(struct rte_mbuf *pkt)
263 {
264         uint16_t pkt_length = 0;
265         int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
266         void *iphdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
267
268         if (ip_hdr_size_bytes == IPv4_HEADER_SIZE) {
269                 struct ipv4_hdr *ihdr4 = (struct ipv4_hdr *)iphdr;
270                 pkt_length = rte_bswap16(ihdr4->total_length) + ETH_HDR_SIZE;
271         } else if (ip_hdr_size_bytes == IPv6_HEADER_SIZE) {
272                 struct ipv6_hdr *ihdr6 = (struct ipv6_hdr *)iphdr;
273                 pkt_length = rte_bswap16(ihdr6->payload_len) +
274                         IPv6_HEADER_SIZE + ETH_HDR_SIZE;
275         }
276
277         uint16_t mbuf_pkt_length = rte_pktmbuf_pkt_len(pkt);
278
279         if (pkt_length == mbuf_pkt_length)
280                 return;
281
282         if (pkt_length < mbuf_pkt_length) {
283                 rte_pktmbuf_trim(pkt, mbuf_pkt_length - pkt_length);
284                 return;
285         }
286
287         /* pkt_length > mbuf_pkt_length */
288         rte_pktmbuf_append(pkt, pkt_length - mbuf_pkt_length);
289 }
290
291 /*
292  * ftp_alg IP HDR size calculation
293  * Input - pkt
294  * Output - Length of IP HDR
295  */
296
297 /* same as rte_ct_get_IP_hdr_size()*/
298 uint16_t ftp_alg_get_IP_hdr_size(struct rte_mbuf *pkt)
299 {
300         /* NOTE: Only supporting IP headers with no options at this time
301         * so header is fixed size
302         */
303
304         uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, IP_START);
305         hdr_chk = hdr_chk >> 4;
306
307         if (hdr_chk == IP_VERSION_4)
308                 return IPv4_HEADER_SIZE;
309         else if (hdr_chk == IP_VERSION_6)
310                 return IPv6_HEADER_SIZE;
311         else            /* Not IPv4 header with no options, return negative. */
312                 return -1;
313
314 }
315
316 /*
317  * ftp_alg checksum re-computing due to change in payload , uses rte function,
318  * if HW Checksum is supported s/w checksum will be disabled
319  * Input - IP HDR and TCP HDR
320  * Output - Length of IP HDR
321  */
322 static void ftp_alg_compute_checksums(
323         void *i_hdr,
324         struct tcp_hdr *t_hdr)
325 /* same as rte_synproxy_compute_checksums*/
326 {
327         /*
328         * calculate IP and TCP checksums.
329         * Note that both checksum routines require
330         * checksum fields to be set to zero, and the the checksum is in the
331         * correct byte order, so no rte_bswap16 is required.
332         */
333
334         int8_t hdr_chk = rte_ct_ipversion(i_hdr);
335         t_hdr->cksum = 0;
336
337         if (hdr_chk == IP_VERSION_4) {
338                 struct ipv4_hdr *i4_hdr = (struct ipv4_hdr *)i_hdr;
339                 i4_hdr->hdr_checksum = 0;
340                 t_hdr->cksum = 0;
341                 t_hdr->cksum = rte_ipv4_udptcp_cksum(i4_hdr, t_hdr);
342
343                 #ifdef ALGDBG
344                 printf("cksum %x\n", rte_bswap32(t_hdr->cksum));
345                 #endif
346
347                 i4_hdr->hdr_checksum = rte_ipv4_cksum(i4_hdr);
348         } else if (hdr_chk == IP_VERSION_6) {
349                 struct ipv6_hdr *i6_hdr = (struct ipv6_hdr *)i_hdr;
350                 t_hdr->cksum = 0;
351                 t_hdr->cksum = rte_ipv6_udptcp_cksum(i6_hdr, t_hdr);
352         }
353 }
354
355 /*
356  * ftp_alg adjusting ACK from other end ;
357  * ACK field of return packet to be adjusted
358  * to the same value of length modified in the payload
359  * Input - pkt, ack diff - delta
360  * Output - None(void)
361  */
362 static void  ftp_alg_adjust_tcp_ack(struct rte_mbuf *pkt, int16_t ackSeqdiff)
363 {
364         /*Since v6 is not supported now*/
365         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
366         struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
367                 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
368         struct tcp_hdr *thdr = (struct tcp_hdr *)
369                 RTE_MBUF_METADATA_UINT32_PTR(pkt,
370                         IP_START + ip_hdr_size_bytes);
371         /*
372         * recv_ack and total length first to be chnaged to host byte order
373         * and then do the addition and then set back to network byte order
374         */
375         uint32_t temp;
376         temp = rte_bswap32(thdr->recv_ack);
377         //printf("%s: ackSeqdiff :%d %u\n", __FUNCTION__, ackSeqdiff, temp);
378         if (ackSeqdiff < 0)
379                 temp += abs(ackSeqdiff);
380         else
381                 temp -= abs(ackSeqdiff);
382
383         thdr->recv_ack = rte_bswap32(temp);
384 }
385 /*
386  * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress  packet
387  * to be adjusted to the same value of length modified in the payload
388  * Input - pkt, ack diff - delta
389  * Output - None(void)
390  */
391
392 static void  ftp_alg_adjust_tcp_seq(struct rte_mbuf *pkt, int16_t ackSeqdiff)
393 {
394         /*Since v6 is not supported now*/
395         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
396         struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
397                 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
398         struct tcp_hdr *thdr = (struct tcp_hdr *)
399                 RTE_MBUF_METADATA_UINT32_PTR(pkt,
400                         IP_START + ip_hdr_size_bytes);
401         uint32_t temp;
402
403         temp = rte_bswap32(thdr->sent_seq);
404         if (ackSeqdiff < 0)
405                 temp -= abs(ackSeqdiff);
406         else
407                 temp += abs(ackSeqdiff);
408
409         thdr->sent_seq = rte_bswap32(temp);
410 }
411 /*
412  * ftp_alg adjusting SEQ from other end ; SEQ field of onward/egress  packet
413  * to be adjusted to the same value of length modified in the payload;
414  * This function computes the delta and calls adjust_seq for chaging the packet
415  * Input - pkt,Original incoming String, Translated string and corresponding
416  * lengths of the string
417  * Output - Seq Diff between Original and translated string
418  */
419
420 static int ftp_alg_delta_tcp_sequence(
421         struct rte_mbuf *pkt,
422         char *port_string,
423         int16_t existing_tcpSeqdiff,
424         uint16_t old_port_string_length,
425         uint16_t new_port_string_length)
426 {
427         int16_t current_sequence_number_delta=0;
428         int16_t final_sequence_number_delta;
429         /*Since v6 is not supported now*/
430         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
431         struct ipv4_hdr *iphdr = (struct ipv4_hdr *)
432                                 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
433         struct tcp_hdr *thdr = (struct tcp_hdr *)
434                                 RTE_MBUF_METADATA_UINT32_PTR(pkt,
435                                         IP_START + ip_hdr_size_bytes);
436         /*
437         * recv_ack and total length first to be chnaged to host byte order
438         * and then do the addition and then set back to network byte order
439         */
440         current_sequence_number_delta = (int16_t) (new_port_string_length -
441                                         old_port_string_length);
442         iphdr->total_length = rte_bswap16(iphdr->total_length);
443
444         #ifdef ALGDBG
445         printf("total_length :%u\n", iphdr->total_length);
446         #endif
447         if(current_sequence_number_delta < 0)
448                 iphdr->total_length -= abs(current_sequence_number_delta);
449         else
450                 iphdr->total_length += current_sequence_number_delta;
451
452         iphdr->total_length = rte_bswap16(iphdr->total_length);
453         if (existing_tcpSeqdiff !=0)
454                 ftp_alg_adjust_tcp_seq(pkt,existing_tcpSeqdiff);
455         final_sequence_number_delta= current_sequence_number_delta + existing_tcpSeqdiff;
456         return final_sequence_number_delta;
457 }
458
459
460 /*
461  * ftp_alg dpi - this function parses the packet and does the respective
462  * action based on the type PORT or PASV, based on the direction of packet
463  * (Private or Public) This is called from CGNAPT
464  * Input - cgnapt pipeline struct, cgnapt key, pkt, CT ,
465  * position of packet assigned by CT, direction of packet
466  * Output - None - as it calls respective action functions
467  */
468 void ftp_alg_dpi(
469         struct pipeline_cgnapt *p_nat,
470         struct pipeline_cgnapt_entry_key *nat_entry_key,
471         struct rte_mbuf *pkt,
472         struct rte_ct_cnxn_tracker *cgnat_cnxn_tracker,
473         int32_t ct_position,
474         uint8_t direction)
475 {
476         /*
477         * recv_ack and total length first to be chnaged to host byte order
478         * and then do the addition and then set back to network byte order
479         */
480
481         /*entry key to be framed in cgnat and pass it over here*/
482         char *port_cmd_string;
483         char *port_cmd_end_string;
484         char *tcp_header_end;
485         char *tcp_start;
486
487
488         uint16_t private_port_number;
489         uint16_t public_port_number;
490         uint16_t ip1, ip2, ip3, ip4, port1, port2;
491         int16_t tcpSeqdiff = 0;
492         int16_t ackSeqdiff, ackAdjust;
493         uint32_t private_address;
494         uint32_t public_address;
495         uint8_t *bptr_private_address;
496         /* also for PASV string */
497         char port_string[65];
498         char port_string_translated[FTP_MAXIMUM_PORT_STRING_LENGTH];
499         int16_t new_port_string_length = 0;
500         int16_t old_port_string_length;
501         int dummy_value;
502         struct cgnapt_table_entry *egress_entry = NULL, *ingress_entry;
503         uint32_t ct_key[10];
504         uint8_t key_direction;
505         /*Since v6 is not supported now*/
506         uint16_t ip_hdr_size_bytes = IPv4_HEADER_SIZE;
507
508         struct ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset(pkt,
509                         struct ipv4_hdr *, sizeof(struct ether_hdr));
510         /* TCP and UDP ports at same offset,
511         * just use TCP for offset calculation
512         */
513         struct tcp_hdr *thdr = rte_pktmbuf_mtod_offset(pkt, struct tcp_hdr *,
514                         (sizeof(struct ether_hdr)+sizeof(struct ipv4_hdr)));
515         uint16_t src_port = rte_bswap16(thdr->src_port);
516         uint16_t dst_port = rte_bswap16(thdr->dst_port);
517         uint8_t proto = ip_hdr->next_proto_id;
518         uint32_t src_addr = rte_bswap32(ip_hdr->src_addr);
519         uint32_t dst_addr = rte_bswap32(ip_hdr->dst_addr);
520         uint32_t tmp_tcp_paylod_size;
521
522         #if 0
523         - src_port & dst_port checking to be moved from cgnat to dpi
524         - For control channel
525                 first validation of tcpSeqdiff to be checked
526                 IF <  > 0
527                         ftp_alg_tcp_ack() to be called(this includes PORT
528                         response and PASV response ack as well)
529                         Return
530                 ELSE
531                         the port/pasv paramter checkign to be done
532         - For data channel
533         -retreive ALG entry
534                 IF found
535                         - remove the ALG entry
536                 even if not found(found cases too)
537         - set the bypass flag in the CT session table
538
539         #endif
540
541         #ifdef ALGDBG
542         {
543                 printf("ftp port number: %d, %d\n", src_port, dst_port);
544                 printf("ftp TCP seq num diff: %d\n",
545                         cgnat_cnxn_tracker->hash_table_entries[
546                                         ct_position].tcpSeqdiff);
547                 printf("tcp data offset: %d\n",
548                         ((thdr->data_off & 0xf0) >> 2));
549                 printf("ct position in dpi:%d\n", ct_position);
550         }
551         #endif
552
553         if (src_port == 21 || dst_port == 21)/* Control Channel*/{
554         /* Control Channel Start */
555         /*
556         * need to look for the port or pasv command.  Then have to look for
557         * the IP address and the port address. Then must create a TCP control
558         * block and spoof the port number, and change the ip address, and do
559         * the sequence number setting.
560         */
561         /* Handle TCP headers.*/
562         tcp_start = (char *)thdr;
563
564         /* start of TCP payload */
565         port_cmd_string = (char * )(tcp_start+((thdr->data_off & 0xf0) >> 2));
566         tcp_header_end = port_cmd_string;
567
568         if (direction == PRIVATE) {
569
570                 #ifdef ALGDBG
571                 printf("In PRIVATE  ");
572                 #endif
573
574                 cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_client
575                                 = rte_bswap32(thdr->sent_seq);
576                 cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_client
577                                 = rte_bswap32(thdr->recv_ack);
578                 #ifdef ALGDBG
579                 printf("-->Seq_cli:%u, Ack_cli:%u, Len:%4d\n",
580                         rte_bswap32(thdr->sent_seq),
581                         rte_bswap32(thdr->recv_ack),
582                         (rte_bswap16(ip_hdr->total_length) -
583                         (((thdr->data_off & 0xf0) >> 4) * 4)) - 20);
584                 #endif
585         } else {
586
587                 #ifdef ALGDBG
588                 printf("In PUBLIC  ");
589                 #endif
590                 cgnat_cnxn_tracker->hash_table_entries[ct_position].seq_server
591                                 = rte_bswap32(thdr->sent_seq);
592                 cgnat_cnxn_tracker->hash_table_entries[ct_position].ack_server
593                                 = rte_bswap32(thdr->recv_ack);
594                 #ifdef ALGDBG
595                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
596                 rte_bswap32(thdr->sent_seq), rte_bswap32(thdr->recv_ack),
597                 (ip_hdr->total_length - (((thdr->data_off & 0xf0) >> 2))
598                         - 20));
599                 #endif
600         }
601
602         if (sscanf(port_cmd_string, FTP_PASV_PARAMETER_STRING, &dummy_value,
603                 &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
604                 FTP_PASV_PARAMETER_COUNT){
605
606         snprintf (port_string, sizeof(port_string), FTP_PASV_PARAMETER_STRING, FTP_PASV_RETURN_CODE,
607                 ip1, ip2, ip3, ip4, port1, port2);
608
609         int i = 0;
610         while (port_cmd_string[i] != '\r' && port_cmd_string[i+1] != '\n')
611                 i++;
612
613         i += 2; // now it points to end of port cmd string.
614
615         old_port_string_length = i;
616
617         private_port_number = (uint16_t) (port1 * 0x100 + port2);
618         bptr_private_address = (uint8_t *) &private_address;
619
620         bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
621         bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
622         bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
623         bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
624
625         /* Not needed as got the position from CT*/
626
627         if (direction == PUBLIC) {
628         /*Client in Private, Server in Public*/
629         /* Not to convert in the payload for PASV resp from Pub side*/
630         /* Only Table creation and no payload modification*/
631         /* DAta Channel also no need to create as it will be done by NAT
632         * when initiated by Client later
633         */
634         populate_ftp_alg_entry(private_address, private_port_number);
635         /*
636         * Bypass ALG flag to be set ,
637         * seqnumber -delta either to be 0 or not needed ,
638         * direction checking for all scenarios
639         */
640         cgnat_cnxn_tracker->hash_table_entries[ct_position].
641                         server_direction = SERVER_IN_PUBLIC;
642         cgnat_cnxn_tracker->hash_table_entries[ct_position].
643                         ftp_session_type= 1; // Passive session type
644         } else if (direction == PRIVATE) {
645         /*Client in Public , Server in Private*/
646
647         struct pipeline_cgnapt_entry_key data_channel_key;
648         private_address = rte_bswap32(private_address);
649         data_channel_key.ip = private_address;
650         data_channel_key.port = private_port_number;
651         /* to be checked if it can be passed as param from NAT*/
652         data_channel_key.pid = pkt->port;
653
654         /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
655         /*Will be getting Private IP and port from Server ,
656         * with that NAPT entry egress and ingress can be added ,
657         * for further data channel communication
658         */
659         #ifdef FTP_ALG
660         if (add_dynamic_cgnapt_entry_alg((struct pipeline *)p_nat,
661         &data_channel_key, &egress_entry, &ingress_entry) == 0){
662
663                 #ifdef ALGDBG
664                 printf("Wrong FTP ALG packet\n");
665                 #endif
666                 //p_nat->invalid_packets |= pkt_mask;
667
668                 p_nat->naptDroppedPktCount++;
669
670                 #ifdef CGNAPT_DEBUGGING
671                 p_nat->naptDroppedPktCount4++;
672                 #endif
673                 return;
674         }
675         #endif
676
677         tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
678                         ((thdr->data_off & 0xf0) >> 2) - ip_hdr_size_bytes;
679         cgnat_cnxn_tracker->hash_table_entries[ct_position].
680                         tcp_payload_size = tmp_tcp_paylod_size;
681         if(egress_entry) {
682
683                 /*Adding ALG entry , params to be derived from egress entry*/
684                 populate_ftp_alg_entry(egress_entry->data.pub_ip,
685                                 egress_entry->data.pub_port);
686
687                 /* payload modification */
688                 new_port_string_length = ftp_alg_modify_payload(egress_entry,
689                                 port_string,
690                                 port_string_translated, 1);
691                 strncpy(tcp_header_end, port_string_translated,
692                                 strlen(port_string_translated));
693                 tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
694                         cgnat_cnxn_tracker->hash_table_entries
695                         [ct_position].tcpSeqdiff,
696                         old_port_string_length,
697                         new_port_string_length);
698
699         }
700         /* same as rte_synproxy_adjust_pkt_length() in ct */
701         ftp_alg_modify_pkt_len(pkt);
702         /*
703         * Store sequence_number_delta in Session_data structure, also bypass
704         * flag to be set as NO (expecting TCP ack from other end then set the
705         * bypass accordingly , handled earlier in the function
706         */
707
708         cgnat_cnxn_tracker->hash_table_entries[ct_position].
709                         alg_bypass_flag = NO_BYPASS;
710         cgnat_cnxn_tracker->hash_table_entries[ct_position].
711                         tcpSeqdiff = tcpSeqdiff;
712         cgnat_cnxn_tracker->hash_table_entries[ct_position].
713                         server_direction = SERVER_IN_PRIVATE;
714         cgnat_cnxn_tracker->hash_table_entries[ct_position].
715                         ftp_session_type = 1; // Passive session type
716                 return;
717
718         } /* PRIVATE dir */
719         } else if (sscanf(port_cmd_string, FTP_PORT_PARAMETER_STRING,
720                         &ip1, &ip2, &ip3, &ip4, &port1, &port2) ==
721                                 FTP_PORT_PARAMETER_COUNT){
722
723                 int i = 0;
724                 static uint8_t port_hit;
725                 while (port_cmd_string[i] != '\r' &&
726                         port_cmd_string[i+1] != '\n')
727                         i++;
728
729                 i += 2; // now it points to end of port cmd string.
730
731                 old_port_string_length = i;
732
733                 #ifdef ALGDBG
734                 printf( " Existing Seq Diff = %d", cgnat_cnxn_tracker->
735                         hash_table_entries[ct_position].tcpSeqdiff);
736                 printf("FTP ALG: FTP PORT command length: %d\n",
737                         old_port_string_length);
738                 #endif
739
740                 private_port_number = (uint16_t) (port1 * 0x100 + port2);
741
742                 #ifdef ALGDBG
743                 printf("FTP ALG: private port number before swap: %u\n",
744                                 private_port_number);
745                 #endif
746
747                 bptr_private_address = (uint8_t *) &private_address;
748                 bptr_private_address[3] = (uint8_t) (ip4 & 0x00FF);
749                 bptr_private_address[2] = (uint8_t) (ip3 & 0x00FF);
750                 bptr_private_address[1] = (uint8_t) (ip2 & 0x00FF);
751                 bptr_private_address[0] = (uint8_t) (ip1 & 0x00FF);
752
753                 sprintf(port_string, FTP_PORT_PARAMETER_STRING, ip1, ip2,
754                                 ip3, ip4, port1, port2);
755
756                 #ifdef ALGDBG
757                 printf("FTP ALG: FTP original PORT string: %d,%s\n",
758                                 (int) strlen(port_string)-2, port_string);
759                 printf("prv addr: %x\n", private_address);
760                 #endif
761
762
763                 if (direction == PUBLIC) {
764                         /* Client in Public*/
765                         /* retreive_cgnat_entry()* for Data Channel*/
766                         /* Pub port and ip address to be used for framing key ,
767                         * the private phrase is a misnomer
768                         */
769                         struct pipeline_cgnapt_entry_key data_channel_key;
770                         data_channel_key.ip = private_address;
771                         data_channel_key.port = private_port_number;
772                         data_channel_key.pid = 0xffff;
773
774
775                         cgnat_cnxn_tracker->hash_table_entries[ct_position].
776                                 server_direction = SERVER_IN_PRIVATE;
777                         cgnat_cnxn_tracker->hash_table_entries[ct_position].
778                                 ftp_session_type= 0; // Active session type
779
780                         /* No payload modificaiton*/
781                         #ifdef ALGDBG
782                         printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
783                         rte_bswap32(thdr->sent_seq),
784                         rte_bswap32(thdr->recv_ack),
785                         (ip_hdr->total_length -
786                                 (((thdr->data_off & 0xf0) >> 2)) - 20));
787                         #endif
788                         populate_ftp_alg_entry(private_address, private_port_number);
789                 } else if (direction == PRIVATE) {
790
791                         /* Client in Private Server in Public*/
792                         /* Populate_alg_entry*/
793                         /*add_dynamic_cgnapt_entry()*/
794                         /* payload modificaion*/
795                         struct pipeline_cgnapt_entry_key data_channel_key;
796                         private_address = rte_bswap32(private_address);
797                         data_channel_key.ip = private_address;
798                         data_channel_key.port = private_port_number;
799                         /* to be checked if it can be passed as param from NAT*/
800                         data_channel_key.pid = pkt->port;
801
802                         /* add_dynamic_cgnat_entry() */ /* for DAta Channel*/
803                         /*
804                         * Will be getting Private IP and port from Client ,
805                         * with that NAPT entry egress and ingress can be added ,
806                         * for further data channel communication
807                         */
808
809                         #ifdef FTP_ALG
810                         if (add_dynamic_cgnapt_entry_alg((struct pipeline *)
811                                 p_nat, &data_channel_key, &egress_entry,
812                                 &ingress_entry) == 0){
813
814                                 #ifdef ALGDBG
815                                 printf("Wrong FTP ALG packet\n");
816                                 #endif
817                                 //p_nat->invalid_packets |= pkt_mask;
818                                 p_nat->naptDroppedPktCount++;
819
820                                 #ifdef CGNAPT_DEBUGGING
821                                 p_nat->naptDroppedPktCount4++;
822                                 #endif
823                                 return;
824                         }
825                         #endif
826
827                 tmp_tcp_paylod_size = rte_bswap16(ip_hdr->total_length) -
828                                         ((thdr->data_off & 0xf0) >> 2) -
829                                         ip_hdr_size_bytes;
830                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
831                         tcp_payload_size = tmp_tcp_paylod_size;
832                 /*ALG entry add, params to be derived from egress entry*/
833
834                 if(egress_entry) {
835                         populate_ftp_alg_entry(egress_entry->data.pub_ip,
836                                         egress_entry->data.pub_port);
837                         /* payload modification */
838                         new_port_string_length = ftp_alg_modify_payload(egress_entry,
839                                         port_string,
840                                         port_string_translated, 0);
841                         strncpy(tcp_header_end, port_string_translated,
842                                         strlen(port_string_translated));
843                         tcpSeqdiff = ftp_alg_delta_tcp_sequence( pkt, port_string,
844                                         cgnat_cnxn_tracker->hash_table_entries
845                                         [ct_position].tcpSeqdiff,
846                                         old_port_string_length,
847                                         new_port_string_length);
848                 }
849                 /* same as rte_synproxy_adjust_pkt_length() in ct */
850                 ftp_alg_modify_pkt_len(pkt);
851
852                 /*
853                 * Store sequence_number_delta in Session_data structure ,
854                 * also bypass flag to be set as NO
855                 * While response from other end is received ,
856                 * modify the ack no using reverse sign of sequen
857                 */
858
859                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
860                         alg_bypass_flag = NO_BYPASS;
861                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
862                         tcpSeqdiff = tcpSeqdiff;
863                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
864                         server_direction = SERVER_IN_PUBLIC;
865                 cgnat_cnxn_tracker->hash_table_entries[ct_position].
866                         ftp_session_type = 0; // Active session type
867
868                 #ifdef ALGDBG
869                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
870                         rte_bswap32(thdr->sent_seq),
871                         rte_bswap32(thdr->recv_ack),
872                         (ip_hdr->total_length -
873                         (((thdr->data_off & 0xf0) >> 2)) - 20));
874
875                 #endif
876                 return;
877                 } /* PRIVATE dir */
878         } /* PORT cmd message */
879
880         if ((ackAdjust=cgnat_cnxn_tracker->hash_table_entries[
881                         ct_position].tcpSeqdiff) != 0) {
882                 if (direction == PRIVATE) {
883                         if (
884                                 cgnat_cnxn_tracker->hash_table_entries
885                                 [ct_position].seq_client !=
886                                 cgnat_cnxn_tracker->hash_table_entries
887                                 [ct_position].ack_server) {
888                                 static int Seqhits;
889                                 ftp_alg_adjust_tcp_seq( pkt,ackAdjust);
890                                 tmp_tcp_paylod_size = rte_bswap16(
891                                         ip_hdr->total_length) -
892                                         ((thdr->data_off & 0xf0) >> 2) -
893                                         ip_hdr_size_bytes;
894                                 cgnat_cnxn_tracker->hash_table_entries
895                                 [ct_position].tcp_payload_size = tmp_tcp_paylod_size;
896                 #ifdef ALGDBG
897                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
898                         rte_bswap32(thdr->sent_seq),
899                         rte_bswap32(thdr->recv_ack),
900                         (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
901                 #endif
902                         }
903                 } else {
904                         if (cgnat_cnxn_tracker->hash_table_entries
905                                 [ct_position].ack_server !=
906                                 (cgnat_cnxn_tracker->hash_table_entries
907                                 [ct_position].seq_client +
908                                 cgnat_cnxn_tracker->hash_table_entries
909                                 [ct_position].tcp_payload_size)) {
910                                 static int Ackhits;
911                                 ftp_alg_adjust_tcp_ack( pkt,ackAdjust);
912                 #ifdef ALGDBG
913                 printf("<--Seq_cli:%4d, Ack_cli%4d, Len:%4d\n",
914                         rte_bswap32(thdr->sent_seq),
915                         rte_bswap32(thdr->recv_ack),
916                         (ip_hdr->total_length -(((thdr->data_off & 0xf0) >> 2))- 20));
917                 #endif
918                         }
919                 }
920                 return;
921                         } /* expected_ack and sequence number updation for PUBLIC dir TCP window */
922         } /* Control Channel End */
923         else {
924                 /*remove the ALG entry, retreival is taken care by rte function  */
925                 #ifdef ALGDBG
926                 printf("In Data Channel \n");
927                 #endif
928                 remove_ftp_alg_entry (dst_addr,dst_port);/* remove the ALG entry */
929                 cgnat_cnxn_tracker->hash_table_entries[ct_position].alg_bypass_flag = BYPASS;
930         } /* Data Channel End */
931 }