diff options
author | Vishwesh M Rudramuni <vishweshmr@gmail.com> | 2017-04-18 19:41:40 +0530 |
---|---|---|
committer | Deepak S <deepak.s@linux.intel.com> | 2017-04-18 02:59:07 -0700 |
commit | 51cd08d9a3f2826088d122e2a5683315c77a2786 (patch) | |
tree | 3fac17a8f7bf362f0c77f1003615b2063d900d35 /common/VIL/alg | |
parent | 03aef84e240c5be8813634735d825420129f1460 (diff) |
common: Adding common library for sample vnf
JIRA: SAMPLEVNF-3
This patch adds common libraries required as part of the
sample vnf.
This includes the following libraries
1. ACL library
2. SIP
3. FTP
4. Connection tracker
5. L2l3 stack
- Interface Manager
- ARP & ICMPv4
- ND & ICMPv6
and other common libraries needed for ip pipeline framework
Change-Id: I117690b6b63fbcd76974cd7274518484e60980ab
Signed-off-by: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>
[Push patch to gerrit]
Signed-off-by: Deepak S <deepak.s@linux.intel.com>
Diffstat (limited to 'common/VIL/alg')
-rw-r--r-- | common/VIL/alg/lib_ftp_alg.c | 917 | ||||
-rw-r--r-- | common/VIL/alg/lib_ftp_alg.h | 102 | ||||
-rw-r--r-- | common/VIL/alg/lib_sip_alg.c | 2257 | ||||
-rw-r--r-- | common/VIL/alg/lib_sip_alg.h | 156 |
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 |