summaryrefslogtreecommitdiffstats
path: root/common/VIL/alg
diff options
context:
space:
mode:
Diffstat (limited to 'common/VIL/alg')
-rw-r--r--common/VIL/alg/lib_ftp_alg.c917
-rw-r--r--common/VIL/alg/lib_ftp_alg.h102
-rw-r--r--common/VIL/alg/lib_sip_alg.c2257
-rw-r--r--common/VIL/alg/lib_sip_alg.h156
4 files changed, 3432 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 */
+}
diff --git a/common/VIL/alg/lib_ftp_alg.h b/common/VIL/alg/lib_ftp_alg.h
new file mode 100644
index 00000000..875d6276
--- /dev/null
+++ b/common/VIL/alg/lib_ftp_alg.h
@@ -0,0 +1,102 @@
+/*
+// 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.
+*/
+#ifndef __INCLUDE_LIB_FTP_ALG_H__
+#define __INCLUDE_LIB_FTP_ALG_H__
+#include "rte_ether.h"
+#include "rte_ct_tcp.h"
+/*CT & CGNAT integration to be resolved for this definitions*/
+#define META_DATA_OFFSET 128
+#define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
+#define ETH_HDR_SIZE 14
+#define IP_START (ETHERNET_START + ETH_HDR_SIZE)
+#define PROTOCOL_START (IP_START + 9)
+#define TCP_START (IP_START + IP_V4_HEADER_SIZE)
+#define TCP_MIN_HDR_SIZE 20
+
+#define RTE_TCP_PROTO_ID 6
+#define RTE_SP_DEFAULT_TTL 64
+
+#define RTE_SYNPROXY_MAX_SPOOFED_PKTS 64
+
+#define RTE_TCP_SYN 0x02
+#define RTE_TCP_ACK 0x10
+#define RTE_TCP_SYN_ACK (RTE_TCP_SYN | RTE_TCP_ACK)
+#define IP_VERSION_4 4
+#define IP_VERSION_6 6
+#define IPv4_HEADER_SIZE 20
+#define IPv6_HEADER_SIZE 40
+
+//#define IPV4 4
+//#define IPV6 6
+enum ftp_alg_bypass {
+ NO_BYPASS,
+ BYPASS
+};
+
+enum ftp_alg_mode {
+ FTP_ALG_PORT,
+ FTP_ALG_PASV
+};
+enum ftp_alg_direction {
+ SERVER_IN_PRIVATE,
+ SERVER_IN_PUBLIC
+};
+enum phy_port {
+ PRIVATE_PORT,
+ PUBLIC_PORT
+};
+
+struct ftp_alg_key {
+ uint32_t ip_address;
+ uint16_t l4port;
+ uint8_t filler1;
+ uint8_t filler2;
+};
+struct ftp_alg_table_entry {
+ uint32_t ip_address;
+ uint16_t l4port;
+ uint8_t ftp_alg_mode;
+ uint8_t ftp_alg_direction;
+ uint32_t session_id; /*to be checked */
+ uint8_t alg_bypass_flag;
+ uint8_t dummy;
+ uint8_t dummy1;
+ //uint32_t napt_entry;/* to be checked*/
+} __rte_cache_aligned;
+
+#define FTP_SERVER_PORT 21
+#define FTP_PORT_STRING "PORT"
+#define FTP_PORT_PARAMETER_STRING "PORT %hu,%hu,%hu,%hu,%hu,%hu\r\n"
+#define FTP_PORT_PARAMETER_COUNT 6
+#define FTP_PORT_RESPONSE_STRING "200 PORT command successful.\r\n"
+#define FTP_PORT_STRING_END_MARKER '\n'
+#define FTP_MAXIMUM_PORT_STRING_LENGTH 60
+#define FTP_PASV_STRING "PASV"
+#define FTP_PASV_PARAMETER_STRING "%d Entering Passive Mode (%hu,%hu,%hu,%hu,%hu,%hu)\r\n"
+#define FTP_PASV_PARAMETER_COUNT 7
+#define FTP_PASV_STRING_END_MARKER '\n' /* not ')' */
+#define FTP_PASV_RETURN_CODE 227
+
+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);
+void lib_ftp_alg_init(void);
+extern int8_t rte_ct_ipversion(void *i_hdr);
+#endif
diff --git a/common/VIL/alg/lib_sip_alg.c b/common/VIL/alg/lib_sip_alg.c
new file mode 100644
index 00000000..9940d59a
--- /dev/null
+++ b/common/VIL/alg/lib_sip_alg.c
@@ -0,0 +1,2257 @@
+/*
+// 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.
+*/
+/*Sriramajeyam*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <math.h>
+
+#include <app.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_ip.h>
+#include <rte_udp.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_actions_common.h"
+#include "hash_func.h"
+#include "lib_sip_alg.h"
+#include "vnf_common.h"
+#include "pipeline_common_be.h"
+
+#define SIP_ALG_SIP "SIP"
+#define SIP_ALG_200_OK "200 OK"
+#define SIP_ALG_INVITE "INVITE"
+#define SIP_ALG_BYE "BYE"
+#define SIP_ALG_TRYING "100 Trying"
+#define SIP_ALG_RINGING "180 Ringing"
+#define SIP_ALG_ACK "ACK"
+#define SIP_ALG_CONTACT "Contact"
+#define SIP_ALG_CONTENT_LEN "Content-Length"
+#define SIP_ALG_VIA "Via"
+#define SIP_ALG_FROM "From"
+#define SIP_ALG_TO "To"
+#define SIP_ALG_CALLID "Call-ID"
+#define SIP_ALG_RTP "RTP"
+#define SIP_ALG_RTCP "a=RTCP"
+#define SIP_ALG_CANCEL "CANCEL"
+#define SIP_ALG_CONTYPE "Content-Type"
+#define SIP_ALG_APPSDP "application/sdp"
+#define SIP_ALG_CSEQ "CSeq"
+#define SIP_ALG_AUDIO "m=audio"
+#define SIP_ALG_DOUBLE_CRLF "\r\n\r\n"
+#define SIP_ALG_CRLF "\r\n"
+#define SIP_ALG_AT "@"
+#define SIP_ALG_GREAT ">"
+#define SIP_ALG_OWNER "o="
+#define SIP_ALG_IPV4 "IP4"
+#define SIP_ALG_CONN "c="
+#define SIP_ALG_REMOTE_PARTY_ID "Remote-Party-ID"
+#define SIP_ALG_SPACE " "
+#define SIP_ALG_SEMICOLON ";"
+
+#define SIP_DEFAULT_L4PORT 5060
+
+#define SIP_ALG_INVITE_MSGTYPE 1
+#define SIP_ALG_BYE_MSGTYPE 2
+#define SIP_ALG_200_OK_INVITE_MSGTYPE 3
+#define SIP_ALG_200_OK_BYE_MSGTYPE 4
+#define SIP_ALG_TRYING_RINGING_MSGTYPE 5
+#define SIP_ALG_ACK_MSGTYPE 6
+
+#define MAX_NUM_SIP_ALG_ENTRIES 16384
+
+#define SIP_ALG_VIA_FIELD_IPADDR 14
+#define SIP_ALG_CTAC_FIELD_IPADDR 7
+
+#define ADDRESS_PORT_STRING 1
+#define PORT_STRING 2
+
+#define MAX_ADDR_PORT_SIZE 30
+#define MAX_ADDR_SIZE 20
+#define MAX_PORT_SIZE 10
+#define MAX_SIP_UDP_MSG_SIZE 2000
+
+#define ALG_DEBUG 0
+
+enum { FALSE, TRUE };
+
+struct rte_mempool *lib_alg_pktmbuf_tx_pool;
+
+struct rte_mbuf *lib_alg_pkt;
+
+static struct rte_hash_parameters sip_alg_hash_params = {
+ .name = NULL,
+ .entries = MAX_NUM_SIP_ALG_ENTRIES,
+ .reserved = 0,
+ .key_len = sizeof(struct sip_alg_key),
+ .hash_func = rte_jhash,
+ .hash_func_init_val = 0,
+ .extra_flag = 1,
+};
+
+struct rte_hash *sip_alg_hash_table;
+
+struct sip_alg_table_entry *sip_alg_table[MAX_NUM_SIP_ALG_ENTRIES];
+
+char *sip_alg_process(struct rte_mbuf *pkt,
+ uint16_t pkt_direction, uint16_t call_direction,
+ uint16_t msgType, uint32_t modIp,
+ uint16_t modL4Port, uint32_t pubIp,
+ uint16_t pubL4Port, uint16_t modRtpPort,
+ uint16_t modRtcpPort, uint16_t *diffModSipLen);
+char *getSipCallIdStr(char *pMsg);
+char *natSipAlgModifyPayloadAddrPort(char *pSipMsg, char **pSipMsgEnd,
+ uint32_t oldStrLen, uint32_t *diffLen,
+ uint32_t pub_ip, uint16_t pub_port,
+ uint32_t type);
+char *natSipAlgAdjustMsg(char *pSipMsg, char **pSipMsgEnd,
+ uint32_t newStrLen, uint32_t oldStrLen);
+
+// This method will be called from other VNF to initialize SIP lib
+// Make an API out of it
+void lib_sip_alg_init(void)
+{
+ char *s = rte_zmalloc(NULL, 64, RTE_CACHE_LINE_SIZE);;
+ int socketid = 0;
+ /* create ipv4 hash */
+ if(!s){
+ printf("NAT SIP ALG Init failed\n");
+ return;
+ }
+ snprintf(s, strlen(s), "ipv4_sip_alg_hash_%d", socketid);
+ printf("NAT SIP ALG initialization ...\n");
+
+ /* SIP ALG hash table initialization */
+ sip_alg_hash_params.socket_id = SOCKET_ID_ANY;
+ sip_alg_hash_params.name = s;
+ sip_alg_hash_table = rte_hash_create(&sip_alg_hash_params);
+
+ if (sip_alg_hash_table == NULL) {
+ printf("SIP ALG rte_hash_create failed. socket %d ...\n",
+ sip_alg_hash_params.socket_id);
+ rte_exit(0, "SIP ALG rte_hash_create failed");
+ } else {
+ printf("sip_alg_hash_table %p\n\n", (void *)sip_alg_hash_table);
+ }
+
+}
+
+char *itoa(long n);
+char *itoa(long n)
+{
+ int len = n == 0 ? 1 : floor(log10l(labs(n))) + 1;
+
+ if (n < 0)
+ len++; /* room for negative sign '-' */
+
+ char *buf = calloc(sizeof(char), len + 1); // +1 for null
+ if(buf != NULL)
+ snprintf(buf, len + 1, "%ld", n);
+ return buf;
+}
+
+struct sip_alg_table_entry *retrieve_sip_alg_entry(
+ struct sip_alg_key *alg_key);
+
+struct sip_alg_table_entry *retrieve_sip_alg_entry(
+ struct sip_alg_key *alg_key)
+{
+ struct sip_alg_table_entry *sip_alg_data = NULL;
+
+ int ret = rte_hash_lookup(sip_alg_hash_table, alg_key);
+
+ if (ret < 0) {
+ #ifdef ALGDBG
+ printf("alg-hash lookup failed ret %d, "
+ "EINVAL %d, ENOENT %d\n",
+ ret, EINVAL, ENOENT);
+ #endif
+ } else {
+ sip_alg_data = sip_alg_table[ret];
+ return sip_alg_data;
+ }
+
+ return NULL;
+}
+
+//int remove_sip_alg_entry(uint32_t ipaddr, uint16_t portid);
+int remove_sip_alg_entry(uint32_t ipaddr, uint16_t portid)
+{
+ struct sip_alg_key alg_key;
+ void *sip_alg_entry_data;
+ int ret;
+
+ alg_key.l4port = portid;
+ alg_key.ip_address = ipaddr;
+ alg_key.filler1 = 0;
+ alg_key.filler2 = 0;
+
+ if (ALG_DEBUG)
+ printf("remove_sip_entry ip %x, port %d\n", alg_key.ip_address,
+ alg_key.l4port);
+
+ ret = rte_hash_lookup(sip_alg_hash_table, &alg_key);
+ if (ret < 0) {
+ if (ALG_DEBUG)
+ printf("removesipalgentry: "
+ "rtehashlookup failed with error %d",
+ ret);
+ return -1;
+ }
+
+ sip_alg_entry_data = sip_alg_table[ret];
+
+ free(sip_alg_entry_data);
+ rte_hash_del_key(sip_alg_hash_table, &alg_key);
+
+ return 0;
+}
+
+/*
+ * Function for populating SIP ALG entry. return 0 - success &
+ * return -1 - failure
+ */
+int populate_sip_alg_entry(uint32_t ipaddr, uint16_t portid,
+ char *sip_call_id, uint8_t call_direction,
+ enum sip_alg_port_type port_type);
+int populate_sip_alg_entry(uint32_t ipaddr, uint16_t portid,
+ char *sip_call_id, uint8_t call_direction,
+ enum sip_alg_port_type port_type)
+{
+ struct sip_alg_key alg_key;
+
+ alg_key.l4port = portid;
+ alg_key.ip_address = ipaddr;
+ alg_key.filler1 = 0;
+ alg_key.filler2 = 0;
+ int ret;
+
+ if (ALG_DEBUG)
+ printf("populate_sip_alg_entry port %d, ip %x\n",
+ alg_key.l4port, alg_key.ip_address);
+
+ struct sip_alg_table_entry *new_alg_data =
+ retrieve_sip_alg_entry(&alg_key);
+
+ if (new_alg_data) {
+ if (ALG_DEBUG)
+ printf("sip_alg_entry exists ip%x, port %d\n",
+ alg_key.ip_address, alg_key.l4port);
+ return 0;
+ }
+
+ new_alg_data = NULL;
+ new_alg_data = (struct sip_alg_table_entry *)
+ malloc(sizeof(struct sip_alg_table_entry));
+ if (new_alg_data == NULL) {
+ printf("populate sip alg entry: allocation failed\n");
+ return -1;
+ }
+
+ new_alg_data->l4port = portid;
+ new_alg_data->ip_address = ipaddr;
+ new_alg_data->l4port_type = port_type;
+ new_alg_data->sip_alg_call_direction = call_direction;
+ strcpy((char *)new_alg_data->sip_alg_call_id, (char *)sip_call_id);
+ new_alg_data->filler1 = 0;
+ new_alg_data->filler2 = 0;
+ new_alg_data->filler3 = 0;
+
+ ret = rte_hash_add_key(sip_alg_hash_table, &alg_key);
+ if (ret < 0) {
+ printf("populate sip - rte_hash_add_key_data ERROR %d\n", ret);
+ free(new_alg_data);
+ return -1;
+ }
+
+ sip_alg_table[ret] = new_alg_data;
+
+ if (ALG_DEBUG) {
+ printf("SIP_ALG: table update - ip=%x on port=%d ret=%d\n",
+ alg_key.ip_address, portid, ret);
+ }
+ return 0;
+}
+
+int sip_alg_dpi(struct rte_mbuf *pkt, enum pkt_dir pkt_direction,
+ uint32_t modIp, uint16_t modL4Port,
+ uint32_t pubIp, uint16_t pubL4Port,
+ uint16_t modRtpPort, uint16_t modRtcpPort)
+{
+ uint16_t msgType = 0;
+ enum sip_alg_call_direction call_direction = 0;
+ uint32_t ip_address = 0;
+ uint16_t port = 0;
+ int ret = 0;
+ struct ipv4_hdr *ip_h;
+ struct ether_hdr *eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ struct udp_hdr *udp_h;
+ char *pSipMsg = NULL;
+ struct sip_alg_table_entry *sip_alg_entry;
+ char *sip_call_id = NULL;
+ int pos = 0;
+ struct sip_alg_key alg_key;
+ uint16_t diffModSipLen = 0;
+
+ ip_h = (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+ udp_h = (struct udp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+ pSipMsg = ((char *)udp_h + sizeof(struct udp_hdr));
+
+ if (ALG_DEBUG) {
+ printf("%s: packet length(%u), buffer length(%u)\n", __func__,
+ rte_pktmbuf_pkt_len(pkt), pkt->buf_len);
+ printf("%s: last segment addr(%p %p)\n", __func__,
+ rte_pktmbuf_lastseg(pkt), pkt);
+ printf("%s: data len(%u, %u)\n", __func__, rte_pktmbuf_data_len(pkt),
+ rte_pktmbuf_data_len(rte_pktmbuf_lastseg(pkt)));
+ printf("%s: buffer addr(%p), data_off(%u), nb_segs(%u)\n", __func__,
+ pkt->buf_addr, pkt->data_off, pkt->nb_segs);
+ }
+
+ if (IS_STRING_SAME(pSipMsg, SIP_ALG_INVITE)) {
+ /* find the call id position in the message */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_CALLID, &pos, 0) ==
+ TRUE)
+ sip_call_id =
+ getSipCallIdStr(pSipMsg + pos +
+ TAG_TO_DATAPOS(SIP_ALG_CALLID));
+
+ if (ALG_DEBUG)
+ printf("sipalgdpi: %d call id %s\n", __LINE__,
+ sip_call_id);
+
+ if (pkt_direction == PRIVATE) {
+ call_direction = SIP_CALL_OUTGOING;
+ ip_address = rte_bswap32(ip_h->src_addr);
+ port = rte_bswap16(udp_h->src_port);
+ } else if (pkt_direction == PUBLIC) {
+ call_direction = SIP_CALL_INCOMING;
+ ip_address = pubIp;
+ port = pubL4Port;
+ }
+
+ if (ALG_DEBUG)
+ printf("0=>sip_alg_dpi: pkt_dir(%d), call_dir(%d), "
+ "ipaddr(%x) port(%x)\n",
+ pkt_direction, call_direction, ip_address, port);
+
+ /* add 3 entries in ALG table for SIP, RTP, RTCP */
+ ret = populate_sip_alg_entry(ip_address, port,
+ sip_call_id, call_direction,
+ SIP_UDP);
+ if (ret < 0) {
+ printf("sipalgdpi:populate SIP alg UDP entry failed\n");
+ return 0;
+ }
+ if (modRtpPort != 0) {
+ ret = populate_sip_alg_entry(ip_address, modRtpPort,
+ sip_call_id,
+ call_direction, SIP_RTP);
+ if (ret < 0) {
+ printf("sipalgdpi: "
+ "populate SIP alg entry RTP failed\n");
+ return 0;
+ }
+ }
+ if (modRtcpPort != 0) {
+ ret = populate_sip_alg_entry(ip_address, modRtcpPort,
+ sip_call_id,
+ call_direction, SIP_RTCP);
+ if (ret < 0) {
+ printf("sipalgdpi: "
+ "populate SIP alg entry RTCP failed\n");
+ return 0;
+ }
+ }
+
+/* Call ALG packet process function for checking & payload modification */
+ pSipMsg =
+ sip_alg_process(pkt, pkt_direction, call_direction,
+ SIP_ALG_INVITE_MSGTYPE, modIp, modL4Port, 0,
+ 0, modRtpPort, modRtcpPort, &diffModSipLen);
+ } else {
+ /*
+ * not SIP INVITE, could be SIP response 200 OK invite, 100 trying,
+ * 180 ringing or BYE or 200 OK BYe
+ */
+ /* retrieve ALG entry from SIP ALG table */
+ if (pkt_direction == PRIVATE) {
+ alg_key.ip_address = rte_bswap32(ip_h->src_addr);
+ alg_key.l4port = rte_bswap16(udp_h->src_port);
+ } else {
+ alg_key.ip_address = pubIp;
+ alg_key.l4port = pubL4Port;
+ }
+
+ alg_key.filler1 = 0;
+ alg_key.filler2 = 0;
+ sip_alg_entry = retrieve_sip_alg_entry(&alg_key);
+
+ if (ALG_DEBUG) {
+ printf("%s: sip_alg_entry_ptr(%p)\n", __func__,
+ sip_alg_entry);
+ printf("1=>%s: pkt_dir(%d), modIp(%x),modL4Port(%x), "
+ "modRtpPort(%x), modRtcpPort(%x), pubIp(%x), pubL4Port(%x)\n",
+ __func__, pkt_direction, modIp, modL4Port,
+ modRtpPort, modRtcpPort, pubIp, pubL4Port);
+ }
+
+ if (sip_alg_entry) {
+ call_direction = sip_alg_entry->sip_alg_call_direction;
+ if (IS_STRING_SAME(pSipMsg, SIP_ALG_BYE) ||
+ IS_STRING_SAME(pSipMsg, SIP_ALG_CANCEL)) {
+ msgType = SIP_ALG_BYE_MSGTYPE;
+
+ goto sipAlgProcess;
+ } else if (IS_STRING_SAME(pSipMsg, SIP_ALG_ACK)) {
+ msgType = SIP_ALG_ACK_MSGTYPE;
+
+ goto sipAlgProcess;
+ }
+
+ pSipMsg += 8;
+ /* checking if its OK or Trying or Ringing */
+ if (IS_STRING_SAME(pSipMsg, SIP_ALG_200_OK)) {
+ /* check CSEQ. Based on that update the msg type */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CSEQ, &pos, 0) == TRUE) {
+ char *pBye;
+
+ pBye =
+ pSipMsg + pos +
+ TAG_TO_DATAPOS(SIP_ALG_CSEQ);
+ SKIP_SPACES(pBye);
+ /* skip the number field */
+ while (*pBye != ' ')
+ pBye++;
+ SKIP_SPACES(pBye);
+ if (IS_STRING_SAME(pBye, SIP_ALG_BYE)
+ ||
+ (IS_STRING_SAME
+ (pBye, SIP_ALG_CANCEL)))
+ msgType =
+ SIP_ALG_200_OK_BYE_MSGTYPE;
+
+ else
+ msgType =
+ SIP_ALG_200_OK_INVITE_MSGTYPE;
+ }
+ } else if (IS_STRING_SAME(pSipMsg, SIP_ALG_TRYING) ||
+ IS_STRING_SAME(pSipMsg, SIP_ALG_RINGING)) {
+ msgType = SIP_ALG_TRYING_RINGING_MSGTYPE;
+ }
+
+ sipAlgProcess:
+ if (ALG_DEBUG)
+ printf("2=>%s: pkt_dir(%d), call_dir(%d), "
+ "msgType(%d), modIp(%x), modL4Port(%x), "
+ " modRtpPort(%x), modRtcpPort(%x)\n",
+ __func__, pkt_direction, call_direction,
+ msgType, modIp, modL4Port, modRtpPort,
+ modRtcpPort);
+ /* Call SIP alg processing for further processing. */
+ pSipMsg =
+ sip_alg_process(pkt, pkt_direction, call_direction,
+ msgType, modIp, modL4Port, pubIp,
+ pubL4Port, modRtpPort, modRtcpPort,
+ &diffModSipLen);
+ } else
+ pSipMsg = NULL;
+ }
+
+ if (ALG_DEBUG)
+ printf("%s: Before IP total length(%u), udp length(%u)\n", __func__,
+ rte_bswap16(ip_h->total_length), rte_bswap16(udp_h->dgram_len));
+ /*
+ * need to modify mbuf & modified length of payload in the IP/UDP
+ * header length fields and return to CGNAT for transmitting
+ */
+ uint16_t len = 0;
+ if (diffModSipLen > 0) {
+ len = rte_bswap16(udp_h->dgram_len);
+ len += diffModSipLen;
+ udp_h->dgram_len = rte_bswap16(len);
+
+ len = rte_bswap16(ip_h->total_length);
+ len += diffModSipLen;
+ ip_h->total_length = rte_bswap16(len);
+
+ if (rte_pktmbuf_append(pkt, diffModSipLen) == NULL)
+ printf("%s: pktmbuf_append returns NULL", __func__);
+
+ }
+
+ if (ALG_DEBUG)
+ printf("%s: After IP total length(%u), udp length(%u), "
+ "diffModSipLen(%u)\n", __func__,
+ rte_bswap16(ip_h->total_length),
+ rte_bswap16(udp_h->dgram_len),
+ diffModSipLen);
+
+ if (pSipMsg != NULL)
+ return 1;
+ else
+ return 0;
+}
+
+char *sip_alg_process(struct rte_mbuf *pkt, uint16_t pkt_direction,
+ uint16_t call_direction, uint16_t msgType, uint32_t modIp,
+ uint16_t modL4Port, uint32_t pubIp, uint16_t pubL4Port,
+ uint16_t modRtpPort, uint16_t modRtcpPort,
+ uint16_t *diffModSipLen)
+{
+ struct ipv4_hdr *ip_h;
+ struct ether_hdr *eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ struct udp_hdr *udp_h;
+ char *pSipMsg, *pStr, *pEndPtr;
+ int pos;
+ /* diff between old & new modified field len */
+ uint32_t diffLen, addrPortLen;
+ int sdpMsgLen = 0;
+ int sip_msg_len = 0;
+
+ ip_h = (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+ udp_h = (struct udp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+ pSipMsg = ((char *)udp_h + sizeof(struct udp_hdr));
+ char *pTmpSipMsg = pSipMsg;
+ char *pStartSipMsg = pSipMsg;
+
+ sip_msg_len =
+ rte_bswap16(ip_h->total_length) - sizeof(struct ipv4_hdr) -
+ sizeof(struct udp_hdr);
+
+ if (natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_CONTENT_LEN, &pos, 0) ==
+ TRUE)
+ pTmpSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_CONTENT_LEN));
+ else {
+ printf("sip_alg_process: Invalid Content Length\n");
+ return NULL;
+ }
+
+ SKIP_SPACES(pTmpSipMsg);
+ int sdpDataLen = strtol(pTmpSipMsg, &pStr, 10);
+
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg, SIP_ALG_DOUBLE_CRLF, &pos, 0);
+ pTmpSipMsg += (pos + strlen(SIP_ALG_DOUBLE_CRLF));
+
+ if (sdpDataLen != 0)
+ if (natSipAlgMsgFieldPos
+ (pTmpSipMsg, SIP_ALG_REMOTE_PARTY_ID, &pos, 0) == TRUE) {
+ pTmpSipMsg += pos + strlen(SIP_ALG_REMOTE_PARTY_ID);
+ /* move further to CRLF which is the end of SIP msg */
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_DOUBLE_CRLF, &pos,
+ 0);
+ pTmpSipMsg += (pos + strlen(SIP_ALG_DOUBLE_CRLF));
+ }
+
+ int sipMsgLen = (pTmpSipMsg - pSipMsg);
+
+ char *pSipMsgEnd = pSipMsg + sipMsgLen + sdpDataLen;
+
+ if (ALG_DEBUG)
+ printf("%s: pSipMsg: %p, pSipMsgEnd: %p, sipMsgLen: %d, "
+ "sdpDataLen: %d totalSipMsgLen: %d\n",
+ __func__, pSipMsg, pSipMsgEnd, sipMsgLen, sdpDataLen,
+ sip_msg_len);
+
+ if (call_direction == SIP_CALL_OUTGOING) {
+ if ((msgType == SIP_ALG_INVITE_MSGTYPE)
+ || (msgType == SIP_ALG_ACK_MSGTYPE)) {
+ /* Get to Via field IP address/Port to modify */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+ == TRUE) {
+ /* advance to IP/Port string */
+ pSipMsg +=
+ (pos + strlen(SIP_ALG_VIA) +
+ SIP_ALG_VIA_FIELD_IPADDR);
+ pTmpSipMsg = pSipMsg;
+ /* move pTmp to next field */
+ natSipAlgMsgFieldPos(pTmpSipMsg,
+ SIP_ALG_SEMICOLON, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; No valid VIA field\n");
+ return NULL;
+ }
+ /* Modify VIA field IP addr:port in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+ /* Advance to "From" field IP addr in payload */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos; /* Moving to "From" */
+ /* advance to IP/Port string */
+ pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf
+ ("sip_alg_process; No valid From field\n");
+ return NULL;
+ }
+ /* Modify "From" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+ /* Advance to Call id field */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+ pSipMsg += pos;
+/* moving it to start of string "Call-ID" */
+ pTmpSipMsg = pSipMsg;
+ /* move tmpSipMsg to next field */
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_CRLF, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ diffLen = pTmpSipMsg - pSipMsg;
+ /* Move pSipMsg to start of Call id "IP addr" string */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; "
+ " No valid Call Id field\n");
+ return NULL;
+ }
+ /* Modify "Call-id" field "addr:port" in payload */
+/* L4 port input is made as 0 as its only addr string modification */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp, 0,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+
+ /* Advance to "Contact" field */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CONTACT, &pos, 0) == TRUE) {
+ pSipMsg += pos;
+ /* move tmpMsg to CRLF */
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_CRLF, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ /* move sipMsg to addr:port string */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+
+ } else {
+ printf("sip_alg_process; "
+ "No valid Call Id field\n");
+ return NULL;
+ }
+ /* Modify "Contact" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+
+ if (msgType == SIP_ALG_INVITE_MSGTYPE) {
+/* Advance to check content type & get content length (SDP length) */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CONTYPE, &pos,
+ 0) == TRUE) {
+ pSipMsg +=
+ (pos +
+ TAG_TO_DATAPOS(SIP_ALG_CONTYPE));
+ SKIP_SPACES(pSipMsg);
+ /*check the application/sdp type, if not, exit */
+ if (!IS_STRING_SAME
+ (pSipMsg, SIP_ALG_APPSDP)) {
+ printf("sip_alg_process "
+ "Invalid Content type\n");
+ return NULL;
+ }
+ } else {
+ printf("sip_alg_process; "
+ "No valid Content field\n");
+ return NULL;
+ }
+
+ /* get the SDP content length */
+ natSipAlgMsgFieldPos(pSipMsg,
+ SIP_ALG_CONTENT_LEN, &pos,
+ 0);
+ pSipMsg +=
+ (pos + TAG_TO_DATAPOS(SIP_ALG_CONTENT_LEN));
+ SKIP_SPACES(pSipMsg);
+ sdpMsgLen = strtol(pSipMsg, &pEndPtr, 10);
+ if (!sdpMsgLen) {
+/* if ACK message, SDP content wont be there.go to ALG process complete */
+ if (msgType == SIP_ALG_ACK_MSGTYPE)
+ goto sipAlgProcessExit;
+
+ printf("sip_alg_process - "
+ "sdpMsgLen is 0\n");
+ return NULL;
+ }
+
+ /* Advance to SDP data message Owner address */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_OWNER, &pos,
+ 0) == TRUE) {
+ pSipMsg += pos;
+ /* at start of owner string "o=" */
+ pTmpSipMsg = pSipMsg;
+ /* move tmmsg to CRLF of owner field */
+ natSipAlgMsgFieldPosFindCrlf(pSipMsg,
+ SIP_ALG_CRLF,
+ &pos,
+ 0);
+ pTmpSipMsg += pos;
+/* start of CRLF "/r/n" */
+/* move pSipMsg to IP address string in owner field */
+ natSipAlgMsgFieldPos(pSipMsg,
+ SIP_ALG_IPV4, &pos,
+ 0);
+ pSipMsg += (pos + strlen(SIP_ALG_IPV4));
+ SKIP_SPACES(pSipMsg);
+/* after skipping spaces, pSip at start of addr */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_processing: "
+ "Invalid Owner field\n");
+ return NULL;
+ }
+/* Modify "Owner" field "addr" in payload. Input L4 port as 0 */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen,
+ modIp, 0,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ sdpMsgLen += diffLen;
+/* need to adjust the SDP msg len as modification done. */
+
+/* Advance to Connection information to modify IP address */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CONN, &pos,
+ 0) == TRUE) {
+ pSipMsg += pos;
+ pTmpSipMsg = pSipMsg;
+ /* move tmmsg to CRLF of owner field */
+ natSipAlgMsgFieldPosFindCrlf(pSipMsg,
+ SIP_ALG_CRLF,
+ &pos,
+ 0);
+ pTmpSipMsg += pos;
+ /* start of CRLF "/r/n" */
+ /* move pSipMsg to IP address string in owner field */
+ natSipAlgMsgFieldPos(pSipMsg,
+ SIP_ALG_IPV4, &pos,
+ 0);
+ pSipMsg += (pos + strlen(SIP_ALG_IPV4));
+ SKIP_SPACES(pSipMsg);
+/* after skipping spaces, pSip at start of addr */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_processing: "
+ "Invalid Owner field\n");
+ return NULL;
+ }
+/* Modify "Connection" field "addr" in payload. Input L4 port as 0 */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen,
+ modIp, 0,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ sdpMsgLen += diffLen;
+/* need to adjust the SDP msg len as modification done. */
+
+ /* Advance to RTP audio port */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_AUDIO, &pos,
+ 0) == TRUE) {
+ pSipMsg +=
+ (pos +
+ TAG_TO_DATAPOS(SIP_ALG_AUDIO));
+ SKIP_SPACES(pSipMsg);
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindSpace
+ (pTmpSipMsg, SIP_ALG_SPACE, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ }
+
+/* Modify "RTP Audio" port in payload. pass pub_ip as 0. */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, 0,
+ modRtpPort,
+ PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ sdpMsgLen += diffLen;
+/* need to adjust the SDP msg len as modification done. */
+
+ /* Advance to RTCP control port, if its there */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_RTCP, &pos,
+ 0) == TRUE) {
+ pSipMsg +=
+ (pos +
+ TAG_TO_DATAPOS(SIP_ALG_RTCP));
+ SKIP_SPACES(pSipMsg);
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindSpace
+ (pTmpSipMsg, SIP_ALG_SPACE, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+
+/* Modify "RTP Audio" port in payload. pass pub_ip as 0. */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort
+ (pSipMsg, &pSipMsgEnd, addrPortLen,
+ &diffLen, 0, modRtcpPort,
+ PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ sdpMsgLen += diffLen;
+/* need to adjust the SDP msg len as modification done. */
+ }
+ }
+/* with this SIP payload modification is complete for outbound invite message */
+ } else if ((msgType == SIP_ALG_TRYING_RINGING_MSGTYPE)
+ || (msgType == SIP_ALG_200_OK_INVITE_MSGTYPE)) {
+ /* Get to Via field IP address/Port to modify */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+ == TRUE) {
+ /* advance to IP/Port string */
+ pSipMsg +=
+ (pos + strlen(SIP_ALG_VIA) +
+ SIP_ALG_VIA_FIELD_IPADDR);
+ pTmpSipMsg = pSipMsg;
+ /* move pTmp to next field */
+ natSipAlgMsgFieldPos(pTmpSipMsg,
+ SIP_ALG_SEMICOLON, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; No valid VIA field\n");
+ return NULL;
+ }
+ /* Modify VIA field IP addr:port in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen = diffLen;
+
+ /* Advance to "From" field IP addr in payload */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos; /* Moving to "From" */
+ /* advance to IP/Port string */
+ pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ //diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf
+ ("sip_alg_process; No valid From field\n");
+ return NULL;
+ }
+ /* Modify "From" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+ /* Advance to Call id field */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+ pSipMsg += pos;
+/* moving it to start of string "Call-ID" */
+ pTmpSipMsg = pSipMsg;
+ /* move tmpSipMsg to next field */
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_CRLF, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ //diffLen = pTmpSipMsg - pSipMsg;
+ /* Move pSipMsg to start of Call id "IP addr" string */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; "
+ "No valid Call Id field\n");
+ return NULL;
+ }
+ /* Modify "Call-id" field "addr" in payload */
+/* L4 port input is made as 0 as its only addr string modification */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp, 0,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+
+ } else if (pkt_direction == PRIVATE
+ && msgType == SIP_ALG_BYE_MSGTYPE) {
+ /* change via, from, call-id and contact field */
+
+ /* Get to Via field IP address to modify */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+ == TRUE) {
+ /* advance to IP/Port string */
+ pSipMsg +=
+ (pos + strlen(SIP_ALG_VIA) +
+ SIP_ALG_VIA_FIELD_IPADDR);
+ pTmpSipMsg = pSipMsg;
+ /* move pTmp to next field */
+ natSipAlgMsgFieldPos(pTmpSipMsg,
+ SIP_ALG_SEMICOLON, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; No valid VIA field\n");
+ return NULL;
+ }
+ /* Modify VIA field IP addr in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp, 0,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen = diffLen;
+
+ /* Advance to "From" field IP addr in payload */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos; /* Moving to "From" */
+ /* advance to IP/Port string */
+ pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf
+ ("sip_alg_process; No valid From field\n");
+ return NULL;
+ }
+ /* Modify "From" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+ /* Advance to Call id field */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+ pSipMsg += pos;
+/* moving it to start of string "Call-ID" */
+ pTmpSipMsg = pSipMsg;
+ /* move tmpSipMsg to next field */
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_CRLF, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ diffLen = pTmpSipMsg - pSipMsg;
+ /* Move pSipMsg to start of Call id "IP addr" string */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; "
+ "No valid Call Id field\n");
+ return NULL;
+ }
+ /* Modify "Call-id" field "addr:port" in payload */
+ /* L4 port input is made as 0 as its only addr string modification */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp, 0,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+
+ /* Advance to "Contact" field */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CONTACT, &pos, 0) == TRUE) {
+ pSipMsg += pos;
+ /* move tmpMsg to semicolon */
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_CRLF, &pos, 0);
+ pTmpSipMsg += pos;
+ /* move sipMsg to addr:port string */
+ int flag = 0;
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT,
+ &pos, 0) == FALSE)
+ flag = 1;
+
+ if (flag)
+ goto SipMsgAdvance2;
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+
+ } else {
+ printf("sip_alg_process; "
+ "No valid Call Id field\n");
+ return NULL;
+ }
+ /* Modify "Contact" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ } else if (pkt_direction == PUBLIC
+ && msgType == SIP_ALG_BYE_MSGTYPE) {
+ /*
+ * Modify Bye URL (if its BYE), To field,
+ * Call-Id if call triggered from private, then modify
+ */
+
+ /* need to modify address:Port in Bye message string. */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos, 0);
+ pSipMsg += pos + 1;
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindSpace(pTmpSipMsg, SIP_ALG_SPACE,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ /* modify the "addr:port" in Bye message line */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+ /* Advance to 'To" field */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos;
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen,
+ modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+ }
+
+ /* check for Call-Id. */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+ pSipMsg += pos;
+/* moving it to start of string "Call-ID" */
+ pTmpSipMsg = pSipMsg;
+ /* move tmpSipMsg to next field */
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_CRLF, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ //diffLen = pTmpSipMsg - pSipMsg;
+ /* Move pSipMsg to start of Call id "IP addr" string */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; "
+ "No valid Call Id field\n");
+ return NULL;
+ }
+ /* Modify "Call-id" field "addr" in payload */
+ /* L4 port input is made as 0 as its only addr string modification */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp, 0,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ } else if (pkt_direction == PRIVATE
+ && (msgType == SIP_ALG_200_OK_BYE_MSGTYPE)) {
+ /*
+ * Need to modify To field, Call-Id,
+ * Contact if call triggered from private, then modify
+ */
+ /* Get to To field IP address to modify */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos; /* Moving to "From" */
+ /* advance to IP/Port string */
+ pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf
+ ("sip_alg_process; no valid from field\n");
+ return NULL;
+ }
+ /* Modify "From" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen = diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+ /* Advance to "Contact" field */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CONTACT, &pos, 0) == TRUE) {
+ pSipMsg += pos;
+ /* move tmpMsg to CRLF */
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_CRLF, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ /* move sipMsg to addr:port string */
+ int flag = 0;
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT,
+ &pos, 0) == FALSE)
+ flag = 1;
+
+ if (flag)
+ goto SipMsgAdvance2;
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; "
+ "No valid Call Id field\n");
+ return NULL;
+ }
+ /* Modify "Contact" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ } else if (pkt_direction == PUBLIC
+ && (msgType == SIP_ALG_200_OK_BYE_MSGTYPE)) {
+ /* change via and from field, call-id field */
+
+ /* Get to Via field IP address to modify */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+ == TRUE) {
+ /* advance to IP/Port string */
+ pSipMsg +=
+ (pos + strlen(SIP_ALG_VIA) +
+ SIP_ALG_VIA_FIELD_IPADDR);
+ pTmpSipMsg = pSipMsg;
+ /* move pTmp to next field */
+ natSipAlgMsgFieldPos(pTmpSipMsg,
+ SIP_ALG_SEMICOLON, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; No valid VIA field\n");
+ return NULL;
+ }
+ /* Modify VIA field IP addr in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp, 0,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen = diffLen;
+
+ /* Advance to "From" field IP addr in payload */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos; /* Moving to "From" */
+ /* advance to IP/Port string */
+ pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf
+ ("sip_alg_process; No valid From field\n");
+ return NULL;
+ }
+ /* Modify "From" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+
+ /* check for Call-Id. */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CALLID, &pos, 0) == TRUE) {
+ pSipMsg += pos;
+ /* Call id 'addr" need to modified. */
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_CRLF, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ /* modify call id "addr" */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen,
+ modIp, 0,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+ } else {
+ printf("sip_alg_process; "
+ "no valid Call-id field\n");
+ return NULL;
+ }
+/* increase the overall diff between old & mod sip msg */
+ }
+ } else if (call_direction == SIP_CALL_INCOMING) {
+ if ((msgType == SIP_ALG_INVITE_MSGTYPE)
+ || (msgType == SIP_ALG_ACK_MSGTYPE)) {
+ /* need to modify Invite RL, TO field */
+ /* move to Invite RL IP address string */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos + 1;
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_SIP,
+ &pos, 0);
+ pTmpSipMsg += (pos - 1);
+/* pointing to space before SIP/2.0 */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf
+ ("sip_alg_process: %d Invalid Invite RL\n",
+ __LINE__);
+ return NULL;
+ }
+ /* modify Invite RL URI in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+ /* Advance to 'To" field */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos;
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_processing; "
+ "%d Invalid To field\n",
+ __LINE__);
+ return NULL;
+ }
+ /* Modify TO field IP addr:port in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+ } else if ((msgType == SIP_ALG_TRYING_RINGING_MSGTYPE)
+ || (msgType == SIP_ALG_200_OK_INVITE_MSGTYPE)) {
+ /* Need to modify TO field */
+ /* Advance to 'To" field */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos;
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen,
+ modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+ }
+ if (msgType == SIP_ALG_200_OK_INVITE_MSGTYPE) {
+/* need to modify Contact, Remote-Party Id, SDP O=IN, C=IN, Audio Port */
+ /* Advance to "Contact" field */
+
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CONTACT, &pos,
+ 0) == TRUE) {
+ pSipMsg += pos;
+ /* move tmpMsg to CRLF */
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPos(pTmpSipMsg,
+ SIP_ALG_SEMICOLON,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ /* move sipMsg to addr:port string */
+ int flag = 0;
+ if (natSipAlgMsgFieldPos(pSipMsg,
+ SIP_ALG_AT, &pos,
+ 30) == FALSE)
+ flag = 1;
+
+ if (flag)
+ goto SipMsgAdvance;
+
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; "
+ "No valid Call Id field\n");
+ return NULL;
+ }
+ /* Modify "Contact" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen,
+ modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+SipMsgAdvance:
+ /* advance to Remote-Party Id */
+ pTmpSipMsg = pSipMsg;
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_REMOTE_PARTY_ID, &pos,
+ 0) == TRUE) {
+ pSipMsg += pos +
+ strlen(SIP_ALG_REMOTE_PARTY_ID);
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPos(pTmpSipMsg,
+ SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ natSipAlgMsgFieldPos(pSipMsg,
+ SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ /* modify the field */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort
+ (pSipMsg, &pSipMsgEnd, addrPortLen,
+ &diffLen, modIp, modL4Port,
+ ADDRESS_PORT_STRING);
+ diffModSipLen += diffLen;
+ } else {
+ printf("sip_alg_process: "
+ "Remote-party-id is not in the msg\n");
+ pSipMsg = pTmpSipMsg;
+ }
+
+ /* Advance to SDP data message Owner address */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_OWNER, &pos,
+ 0) == TRUE) {
+ pSipMsg += pos;
+ /* at start of owner string "o=" */
+ pTmpSipMsg = pSipMsg;
+ /* move tmmsg to CRLF of owner field */
+ natSipAlgMsgFieldPosFindCrlf(pSipMsg,
+ SIP_ALG_CRLF,
+ &pos,
+ 0);
+ pTmpSipMsg += pos;
+ /* start of CRLF "/r/n" */
+/* move pSipMsg to IP address string in owner field */
+ natSipAlgMsgFieldPos(pSipMsg,
+ SIP_ALG_IPV4, &pos,
+ 0);
+ pSipMsg += (pos + strlen(SIP_ALG_IPV4));
+ SKIP_SPACES(pSipMsg);
+/* after skipping spaces, pSip at start of addr */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_processing: "
+ "Invalid Owner field\n");
+ return NULL;
+ }
+/* Modify "Owner" field "addr" in payload. Input L4 port as 0 */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen,
+ modIp, 0,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ sdpMsgLen += diffLen;
+ /* update the sdpMsgLen after modification */
+
+ /* Advance to Connection information to modify IP address */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CONN, &pos,
+ 0) == TRUE) {
+ pSipMsg += pos;
+ pTmpSipMsg = pSipMsg;
+ /* move tmmsg to CRLF of owner field */
+ natSipAlgMsgFieldPosFindCrlf(pSipMsg,
+ SIP_ALG_CRLF,
+ &pos,
+ 0);
+ pTmpSipMsg += pos;
+ /* start of CRLF "/r/n" */
+ /* move pSipMsg to IP address string in owner field */
+ natSipAlgMsgFieldPos(pSipMsg,
+ SIP_ALG_IPV4, &pos,
+ 0);
+ pSipMsg += (pos + strlen(SIP_ALG_IPV4));
+ SKIP_SPACES(pSipMsg);
+/* after skipping spaces, pSip at start of addr */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_processing: "
+ "Invalid Connection field\n");
+ return NULL;
+ }
+/* Modify "Connection" field "addr" in payload. Input L4 port as 0 */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen,
+ modIp, 0,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ sdpMsgLen += diffLen;
+/* update the sdpMsgLen after modification */
+
+ /* Advance to RTP audio port */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_AUDIO, &pos,
+ 0) == TRUE) {
+ pSipMsg +=
+ (pos + strlen(SIP_ALG_AUDIO));
+ SKIP_SPACES(pSipMsg);
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindSpace
+ (pTmpSipMsg, SIP_ALG_SPACE, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ }
+
+/* Modify "RTP Audio" port in payload. pass pub_ip as 0. */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, 0,
+ modRtpPort,
+ PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ sdpMsgLen += diffLen;
+/* update the sdpMsgLen after modification */
+ }
+ } else if (pkt_direction == PUBLIC
+ && msgType == SIP_ALG_BYE_MSGTYPE) {
+ /* Modify Bye URL (if its BYE), To field */
+
+ /* need to modify address:Port in Bye message string. */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos, 0);
+ pSipMsg += pos + 1;
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindSpace(pTmpSipMsg, SIP_ALG_SPACE,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ /* modify the "addr:port" in Bye message line */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+ /* Advance to 'To" field */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos;
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen,
+ modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+ } else {
+ printf
+ ("sip_alg_processing: Invalid TO field\n");
+ return NULL;
+ }
+ } else if (pkt_direction == PRIVATE
+ && msgType == SIP_ALG_BYE_MSGTYPE) {
+ /* change via and from field */
+
+ /* Get to Via field IP address to modify */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+ == TRUE) {
+ /* advance to IP/Port string */
+ pSipMsg +=
+ (pos + strlen(SIP_ALG_VIA) +
+ SIP_ALG_VIA_FIELD_IPADDR);
+ pTmpSipMsg = pSipMsg;
+ /* move pTmp to next field */
+ natSipAlgMsgFieldPos(pTmpSipMsg,
+ SIP_ALG_SEMICOLON, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; No valid VIA field\n");
+ return NULL;
+ }
+ /* Modify VIA field IP addr in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp, 0,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen = diffLen;
+
+ /* Advance to "From" field IP addr in payload */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_FROM, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos; /* Moving to "From" */
+ /* advance to IP/Port string */
+ pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf
+ ("sip_alg_process; No valid From field\n");
+ return NULL;
+ }
+ /* Modify "From" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+ } else if (pkt_direction == PRIVATE
+ && msgType == SIP_ALG_200_OK_BYE_MSGTYPE) {
+ /* change via and from field */
+
+ /* Get to Via field IP address to modify */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_VIA, &pos, 0)
+ == TRUE) {
+ /* advance to IP/Port string */
+ pSipMsg +=
+ (pos + strlen(SIP_ALG_VIA) +
+ SIP_ALG_VIA_FIELD_IPADDR);
+ pTmpSipMsg = pSipMsg;
+ /* move pTmp to next field */
+ natSipAlgMsgFieldPos(pTmpSipMsg,
+ SIP_ALG_SEMICOLON, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; No valid VIA field\n");
+ return NULL;
+ }
+ /* Modify VIA field IP addr in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp, 0,
+ ADDRESS_PORT_STRING);
+ *diffModSipLen = diffLen;
+
+ /* Advance to "From" field IP addr in payload */
+ if (natSipAlgMsgFieldPos(pSipMsg,
+ SIP_ALG_FROM, &pos, 0) == TRUE) {
+ pSipMsg += pos; /* Moving to "From" */
+ /* advance to IP/Port string */
+ pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf
+ ("sip_alg_process; No valid From field\n");
+ return NULL;
+ }
+ /* Modify "From" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+/* increase the overall diff between old & mod sip msg */
+ } else if (pkt_direction == PUBLIC
+ && msgType == SIP_ALG_200_OK_BYE_MSGTYPE) {
+ /* Get to To field IP address to modify */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_TO, &pos, 0)
+ == TRUE) {
+ pSipMsg += pos; /* Moving to "From" */
+ /* advance to IP/Port string */
+ pTmpSipMsg = pSipMsg;
+/* move pTmpSipMsg to str ">" which is end of add:port string */
+ natSipAlgMsgFieldPos(pTmpSipMsg, SIP_ALG_GREAT,
+ &pos, 0);
+ pTmpSipMsg += pos;
+ diffLen = pTmpSipMsg - pSipMsg;
+/* find "@" from "From" string to ">" string which is start of "addr:port" */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+/* now its pointing to start of From field "address:port" */
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf
+ ("sip_alg_process; no valid from field\n");
+ return NULL;
+ }
+ /* Modify "From" field "addr:port" in payload */
+ pSipMsg = natSipAlgModifyPayloadAddrPort(pSipMsg,
+ &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen = diffLen;
+/* increase the overall diff between old & mod sip msg */
+
+ /* Advance to "Contact" field */
+ if (natSipAlgMsgFieldPos
+ (pSipMsg, SIP_ALG_CONTACT, &pos, 0) == TRUE) {
+ pSipMsg += pos;
+ /* move tmpMsg to CRLF */
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_CRLF, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ /* move sipMsg to addr:port string */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AT, &pos,
+ 0);
+ pSipMsg += pos + 1;
+ addrPortLen = pTmpSipMsg - pSipMsg;
+ } else {
+ printf("sip_alg_process; "
+ "No valid Call Id field\n");
+ return NULL;
+ }
+ /* Modify "Contact" field "addr:port" in payload */
+ pSipMsg =
+ natSipAlgModifyPayloadAddrPort(pSipMsg, &pSipMsgEnd,
+ addrPortLen,
+ &diffLen, modIp,
+ modL4Port,
+ ADDRESS_PORT_STRING);
+
+ *diffModSipLen += diffLen;
+ }
+ }
+
+SipMsgAdvance2:
+/* need to remove the SIP ALG entry if msg is 200 OK BYE response */
+ if (call_direction == SIP_CALL_OUTGOING) {
+ /* call remove sip alg entry here */
+ if (pkt_direction == PRIVATE) {
+ if (msgType == SIP_ALG_200_OK_BYE_MSGTYPE) {
+ if (remove_sip_alg_entry
+ (rte_bswap32(ip_h->src_addr),
+ rte_bswap16(udp_h->src_port)) < 0)
+ printf("removesipalgentry failed: "
+ "ipaddr %d, portid %d\n",
+ ip_h->src_addr, udp_h->src_port);
+ }
+ }
+ } else {
+ if (pkt_direction == PUBLIC) {
+ if (msgType == SIP_ALG_200_OK_BYE_MSGTYPE) {
+ if (remove_sip_alg_entry(pubIp, pubL4Port) < 0)
+ printf("removesipalgentry failed: "
+ " ipaddr %d, portid %d\n",
+ pubIp, pubL4Port);
+ }
+ }
+ }
+
+/* adjust SDP msg len (sdpMsgLen) in the content length field of SIP msg */
+ if ((sdpMsgLen > 0) && (sdpDataLen > 0)) {
+ pSipMsg = pStartSipMsg;
+ char *tmpSdpLen = NULL;
+
+ sdpMsgLen += sdpDataLen;
+ tmpSdpLen = itoa(sdpMsgLen);
+ int tmpStrLen = strlen(tmpSdpLen);
+
+ /* move to Content length field & change the length to sipMsgLen */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_CONTENT_LEN, &pos, 0)
+ == TRUE) {
+ pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_CONTENT_LEN));
+ SKIP_SPACES(pSipMsg);
+ pTmpSipMsg = pSipMsg;
+ natSipAlgMsgFieldPosFindCrlf(pTmpSipMsg,
+ SIP_ALG_DOUBLE_CRLF, &pos,
+ 0);
+ pTmpSipMsg += pos;
+ SKIP_SPACES(pSipMsg);
+ diffLen = pTmpSipMsg - pSipMsg;
+ natSipAlgAdjustMsg(pSipMsg, &pSipMsgEnd, tmpStrLen,
+ diffLen);
+ strncpy(pSipMsg, tmpSdpLen, tmpStrLen);
+ } else {
+ printf("sip_alg_process: Invalid Content Length\n");
+ return NULL;
+ }
+ }
+
+ sipAlgProcessExit:
+ /* need to return toe start of the SIP msg */
+ return pStartSipMsg;
+}
+
+/*
+ * Function to Fetch RTP & RTCP port & return. Invoked by CGNAT
+ * while adding NAPT entry for RTP & RTCP
+ */
+int natSipAlgGetAudioPorts(struct rte_mbuf *pkt, uint16_t *rtpPort,
+ uint16_t *rtcpPort)
+{
+ struct ipv4_hdr *ip_h;
+ struct ether_hdr *eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ struct udp_hdr *udp_h;
+ char *pSipMsg, *pEndPtr;
+ int pos, sdpMsgLen;
+
+ ip_h = (struct ipv4_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
+ udp_h = (struct udp_hdr *)((char *)ip_h + sizeof(struct ipv4_hdr));
+ pSipMsg = ((char *)udp_h + sizeof(struct udp_hdr));
+
+ /* Advance to check content type & get content length (SDP length) */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_CONTYPE, &pos, 0) == FALSE)
+ return -1;
+
+ pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_CONTYPE));
+ SKIP_SPACES(pSipMsg);
+
+ /*check the application/sdp type, if not, exit */
+ if (!IS_STRING_SAME(pSipMsg, SIP_ALG_APPSDP)) {
+ printf("sip_alg_getAudioPort Invalid Content type\n");
+ return -1;
+ }
+
+ /* get the SDP content length */
+ natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_CONTENT_LEN, &pos, 0);
+ pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_CONTENT_LEN));
+ SKIP_SPACES(pSipMsg);
+ sdpMsgLen = strtol(pSipMsg, &pEndPtr, 10);
+ if (!sdpMsgLen) {
+ printf("sipAlggetAudioport - sdpMsgLen is 0\n");
+ return -1;
+ }
+
+ /* advance to RTP audio port */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_AUDIO, &pos, 0) ==
+ TRUE) {
+ pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_AUDIO));
+ SKIP_SPACES(pSipMsg);
+ *rtpPort = strtol(pSipMsg, &pEndPtr, 10);
+ } else
+ *rtpPort = 0;
+
+ /* advance to RTCP audio control port */
+ if (natSipAlgMsgFieldPos(pSipMsg, SIP_ALG_RTCP, &pos, 0) ==
+ TRUE) {
+ pSipMsg += (pos + TAG_TO_DATAPOS(SIP_ALG_RTCP));
+ SKIP_SPACES(pSipMsg);
+ *rtcpPort = strtol(pSipMsg, &pEndPtr, 10);
+ } else
+ *rtcpPort = 0;
+
+ if (ALG_DEBUG)
+ printf(" sipAlgGetAudioPort; rtpPort %d, rtcpPort %d\n",
+ *rtpPort, *rtcpPort);
+ return 0;
+}
+
+/* function to find SPACES in ALG message */
+int
+natSipAlgMsgFieldPosFindSpace(char *pData, const char *pIdStr, int *pPos,
+ int searchLen)
+{
+ char *pStart = pData;
+ int i = 0;
+
+ if (!pIdStr)
+ return FALSE;
+
+ if (!searchLen)
+ searchLen = 1500; /* max default search length */
+
+ while (TRUE) {
+ while (*pData != ' ') {
+ pData++;
+ i++;
+ }
+
+ if (i > searchLen) {
+ printf("SIP ALG Find Field Pos: "
+ "Single message exceeds max len: %d\n",
+ searchLen);
+ *pPos = searchLen; /* reaches the end */
+ return FALSE;
+ }
+
+ if (bcmp(pData, pIdStr, strlen(pIdStr)) == 0)
+ break;
+ }
+
+ *pPos = pData - pStart;
+ return TRUE;
+}
+
+/* function to find CRLF in ALG message */
+int natSipAlgMsgFieldPosFindCrlf(
+ char *pData,
+ const char *pIdStr,
+ int *pPos,
+ int searchLen)
+{
+ char *pStart = pData;
+ int i = 0;
+
+ if (!pIdStr)
+ return FALSE;
+
+ if (!searchLen)
+ searchLen = 1500; /* max default search length */
+
+ while (TRUE) {
+ while (*pData != '\r' && *(pData + 1) != '\n') {
+ pData++;
+ i++;
+ }
+ if (i >= searchLen) {
+ printf("SIP ALG Find Field Pos: "
+ " Single message exceeds max len: %d\n",
+ searchLen);
+ *pPos = searchLen; /* reaches the end */
+ return FALSE;
+ }
+
+ if (bcmp(pData, pIdStr, strlen(pIdStr)) == 0)
+ break;
+ }
+
+ *pPos = pData - pStart;
+ return TRUE;
+}
+
+/* function to find field position in ALG message */
+int natSipAlgMsgFieldPos(char *pData,
+ const char *pIdStr,
+ int *pPos,
+ int searchLen)
+{
+ char *pStart = pData;
+ int i = 0, j = 0;
+
+ if (!pIdStr)
+ return FALSE;
+
+ if (!searchLen)
+ searchLen = 1500; /* max default search length */
+
+ while (TRUE) {
+ while (*pData != '\r' && *(pData + 1) != '\n') {
+ /* skip all space */
+
+ while (*pData == ' ') {
+ pData++;
+ j++;
+ }
+
+ if (*pData == '\r' && *(pData + 1) == '\n')
+ break;
+
+ if (bcmp(pData, pIdStr, strlen(pIdStr)) == 0) {
+ *pPos = pData - pStart;
+ return TRUE;
+ }
+
+ pData++;
+ j++;
+
+ if (j >= searchLen) {
+ *pPos = pData - pStart;
+ return FALSE;
+ }
+
+ }
+
+ /* advance to next line */
+
+ for (i = 0; i < (searchLen - 1); i++) {
+ if (pData[i] == '\r')
+ if (pData[i + 1] == '\n')
+ break;
+ }
+
+ if (i > searchLen) {
+ printf("SIP ALG Find Field Pos: "
+ "Single message exceeds max len: %d\n",
+ searchLen);
+ *pPos = searchLen; /* reaches the end */
+ return FALSE;
+ }
+
+ pData += i + 2;
+ searchLen -= (i + 2);
+
+ if ((pData[0] == '\r' && pData[1] == '\n') ||
+ (searchLen <= 0)) {
+ /* reach the end mark \r\n\r\n */
+
+ if (searchLen > 0) {
+ pData += 2;
+ continue;
+ }
+
+ *pPos = pData - pStart;
+
+ return FALSE;
+ }
+ }
+
+ *pPos = pData - pStart;
+ return TRUE;
+}
+
+/* get SIP Call id string */
+char *getSipCallIdStr(char *pMsg)
+{
+ char *pStart;
+ char *pCallId = NULL;
+ int i;
+
+ pStart = pMsg;
+ for (i = 0; i < 200; i++) {
+ if (*pMsg != '\r')
+ pMsg++;
+ else
+ break;
+ }
+ if (i >= 200) {
+ printf("SIP_ALG: getCallid wrong string format\n");
+ return NULL;
+ }
+
+ size_t size = RTE_CACHE_LINE_ROUNDUP(pMsg - pStart + 1);
+
+ pCallId = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+ if (!pCallId)
+ return NULL;
+
+ bcopy(pStart, pCallId, pMsg - pStart);
+ *(pCallId + (pMsg - pStart)) = 0;
+
+ if (ALG_DEBUG)
+ printf("%s: %s\n", __func__, pCallId);
+
+ return pCallId;
+}
+
+char *natSipAlgModifyPayloadAddrPort(
+ char *pSipMsg, char **pSipMsgEnd,
+ uint32_t oldStrLen, uint32_t *diffLen,
+ uint32_t modIp, uint16_t modPort, uint32_t type)
+{
+ char addrport[MAX_ADDR_PORT_SIZE];
+ struct in_addr ipAddr;
+ uint32_t newStrLen = 0;
+ char *tmpPort = NULL;
+
+ if (modPort != 0)
+ tmpPort = itoa(modPort);
+
+ *diffLen = 0;
+ if (type == ADDRESS_PORT_STRING) {
+ ipAddr.s_addr = htonl(modIp);
+ char *tmpAddr = inet_ntoa(ipAddr);
+
+ if (modPort != 0) /* for addr:port combo modification */
+ sprintf(addrport, "%s:%s", tmpAddr, tmpPort);
+ else /* if only address modification */
+ sprintf(addrport, "%s", tmpAddr);
+
+ newStrLen = strlen(addrport);
+
+ if (abs(newStrLen - oldStrLen) > 0) {
+ /*
+ * Call the function moving the SIP Msg pointer
+ * to modify the field
+ */
+ natSipAlgAdjustMsg(pSipMsg, pSipMsgEnd,
+ newStrLen, oldStrLen);
+ }
+
+ /* replace the old addr:port with new addr:port */
+ strncpy(pSipMsg, addrport, strlen(addrport));
+ } else if (type == PORT_STRING) { /* only port modification */
+ if(tmpPort)
+ newStrLen = strlen(tmpPort);
+
+ if (abs(newStrLen - oldStrLen) > 0) {
+ /*
+ * Call the function moving the SIP msg pointer
+ * to modify the field
+ */
+ natSipAlgAdjustMsg(pSipMsg, pSipMsgEnd,
+ newStrLen, oldStrLen);
+ }
+
+ /* replace the old port with new port */
+ if(tmpPort)
+ strncpy(pSipMsg, tmpPort, strlen(tmpPort));
+ }
+ /* output difflen between old str len & modified new str length */
+ if (newStrLen > oldStrLen)
+ *diffLen = newStrLen - oldStrLen;
+
+ return pSipMsg; /* modified SIP Msg */
+}
+
+char *natSipAlgAdjustMsg(char *pSipMsg, char **pSipMsgEnd,
+ uint32_t newStrLen, uint32_t oldStrLen)
+{
+ char MsgBuffer[MAX_SIP_UDP_MSG_SIZE];
+
+ if (newStrLen > oldStrLen) {
+ pSipMsg += oldStrLen;
+ int msgLen = *pSipMsgEnd - pSipMsg;
+
+ strncpy(MsgBuffer, pSipMsg, msgLen);
+ pSipMsg += (newStrLen - oldStrLen);
+ strncpy(pSipMsg, MsgBuffer, msgLen);
+
+ if (ALG_DEBUG)
+ printf("natSipAlgAdjustMsg: %u\n", msgLen);
+
+ /* moving output end of SIP MSG by difflen like pSipMsg */
+ *pSipMsgEnd += (newStrLen - oldStrLen);
+ } else {
+ /* Setting space on the oldStr position */
+ memset(pSipMsg, ' ', oldStrLen);
+ }
+
+ return pSipMsg;
+}
+
+/* end of file */
diff --git a/common/VIL/alg/lib_sip_alg.h b/common/VIL/alg/lib_sip_alg.h
new file mode 100644
index 00000000..b320a4f4
--- /dev/null
+++ b/common/VIL/alg/lib_sip_alg.h
@@ -0,0 +1,156 @@
+/*
+// 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.
+*/
+
+#ifndef __INCLUDE_LIB_ALG_H__
+#define __INCLUDE_LIB_ALG_H__
+
+#include "rte_ether.h"
+
+uint16_t sip_session_number;/* SIP session count */
+#define IS_STRING_SAME(pStr, strId) (bcmp((pStr), strId, strlen(strId)) == 0)
+#define TAG_TO_DATAPOS(str) (strlen(str) + 1)
+#define SKIP_SPACES(pStr) \
+{ \
+ while (*(char *)(pStr) == ' ') \
+ (char *)(pStr)++; \
+}
+
+enum pkt_dir {PRIVATE, PUBLIC};
+
+/* enum for SIP Call direction - NAT ALG */
+enum sip_alg_call_direction {
+ SIP_CALL_INCOMING, /* Incoming call public to private */
+ SIP_CALL_OUTGOING /* Outgoing call private to public */
+};
+
+/* enum of SIP port type - NAT ALG */
+enum sip_alg_port_type {
+ SIP_UDP, /* SIP SDP port 5460 */
+ SIP_RTP, /* RTP port number */
+ SIP_RTCP /* RTCP port number */
+};
+
+/*
+ * Data structure for NAT SIP ALG table key
+ * Key - IP address & L4 port number.
+ */
+struct sip_alg_key {
+ /*
+ * IP address based on direction.
+ * outgoing - public IP, incoming - destinatio IP of pkt
+ */
+ uint32_t ip_address;
+ uint16_t l4port; /* SIP SDP, RTP, RTCP port number */
+ uint8_t filler1;
+ uint8_t filler2;
+};
+
+/*
+ * Data structure for NAT SIP ALG table entry.
+ * Placeholder for storing SIP ALG entries.
+ */
+struct sip_alg_table_entry {
+ uint32_t ip_address;
+ /*
+ * IP address based on direction.
+ * outgoing - public IP, incoming - destinatio IP of pkt
+ */
+ uint16_t l4port; /* SIP UDP (5061), RTP, RTCP port number */
+ uint8_t sip_alg_call_direction;
+ /* Call incoming (pub to prv) or outgoing (prv to pub) */
+ uint8_t sip_alg_call_id[100];/* unique identfier for a SIP call */
+ uint8_t l4port_type;/* SIP_UDP or RTP or RTCP */
+ uint8_t filler1;
+ uint16_t filler2;
+ uint32_t filler3;
+} __rte_cache_aligned;
+
+
+/* Function declarations */
+
+/**
+ * To initalize SIP ALG library and should be called-
+ * - before other SIP ALG library funcitons
+ * @param params
+ * pipeline parameter structure pointer
+ * @param app
+ * pipeline application conext structure pointer
+ * @return
+ * void return
+ */
+void lib_sip_alg_init(void);
+
+/**
+ * Main SIP ALG DPI function for processing SIP ALG functionlity
+ * @param pkt
+ * mbuf packet pointer
+ * @param pkt_direction
+ * Indicates whether pkt is from PRIVATE or PUBLIC direction
+ * @param modIp
+ * NAPT tranlated IP address based on direction
+ * @param modL4Port
+ * NAPT translated L4 port based on direction
+ * @param pubIP
+ * Original IP address before translation
+ * @param pubL4Port
+ * Original L4 port before translation
+ * @param modRtpPort
+ * RTP port
+ * @param modRtcpPort
+ * RTCP port
+ * @return
+ * 0 means success, -1 means failure
+ */
+int sip_alg_dpi(struct rte_mbuf *pkt, enum pkt_dir pkt_direction,
+ uint32_t modIp, uint16_t modL4Port,
+ uint32_t pubIp, uint16_t pubL4Port,
+ uint16_t modRtpPort, uint16_t modRtcpPort);
+
+/**
+ * To get audio ports from SIP Packet
+ * @param pkt
+ * mbuf packet pointer
+ * @param rtpPort
+ * rtp port in parameter
+ * @param rtcpPort
+ * rtcp port in parameter
+ * @return
+ * 0 means success, -1 means failre
+ */
+int natSipAlgGetAudioPorts(
+ struct rte_mbuf *pkt,
+ uint16_t *rtpPort,
+ uint16_t *rtcp_port);
+int natSipAlgMsgFieldPos(
+ char *pData,
+ const char *pIdStr,
+ int *pos,
+ int searchLen);
+int natSipAlgMsgFieldPosFindCrlf(
+ char *pData,
+ const char *pIdStr,
+ int *pPos,
+ int searchLen);
+int natSipAlgMsgFieldPosFindSpace(
+ char *pData,
+ const char *pIdStr,
+ int *pPos,
+ int searchLen);
+int remove_sip_alg_entry(
+ uint32_t ipaddr,
+ uint16_t portid);
+
+#endif