ims_ipsec_pcscf: TCP support
authorTsvetomir Dimitrov <tsv.dimitrov@gmail.com>
Tue, 16 Oct 2018 12:44:00 +0000 (12:44 +0000)
committerTsvetomir Dimitrov <tsv.dimitrov@gmail.com>
Tue, 26 Feb 2019 11:14:07 +0000 (11:14 +0000)
Adds TCP support to the module. The client and server ports, specified
in the configuration, are bound on TCP and UDP protocols. All xfrm
related code is changed to work with both protocols.

src/modules/ims_ipsec_pcscf/cmd.c
src/modules/ims_ipsec_pcscf/ims_ipsec_pcscf_mod.c
src/modules/ims_ipsec_pcscf/ipsec.c
src/modules/ims_ipsec_pcscf/ipsec.h

index a662f0c..1a87b9d 100644 (file)
@@ -269,7 +269,7 @@ static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m)
     return 0;
 }
 
-static int create_ipsec_tunnel(const str remote_addr, ipsec_t* s)
+static int create_ipsec_tunnel(const str remote_addr, unsigned short proto, ipsec_t* s)
 {
     struct mnl_socket* sock = init_mnl_socket();
     if (sock == NULL) {
@@ -281,19 +281,19 @@ static int create_ipsec_tunnel(const str remote_addr, ipsec_t* s)
             remote_addr.len, remote_addr.s, s->port_uc, s->port_us);
 
     // P-CSCF 'client' tunnel to UE 'server'
-    add_sa    (sock, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, s->ck, s->ik);
-    add_policy(sock, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, IPSEC_POLICY_DIRECTION_OUT);
+    add_sa    (sock, proto, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, s->ck, s->ik);
+    add_policy(sock, proto,  ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, IPSEC_POLICY_DIRECTION_OUT);
 
     // UE 'client' to P-CSCF 'server' tunnel
-    add_sa    (sock, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, s->ck, s->ik);
-    add_policy(sock, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
+    add_sa    (sock, proto, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, s->ck, s->ik);
+    add_policy(sock, proto, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
 
     close_mnl_socket(sock);
 
     return 0;
 }
 
-static int destroy_ipsec_tunnel(const str remote_addr, ipsec_t* s)
+static int destroy_ipsec_tunnel(const str remote_addr, unsigned short proto, ipsec_t* s)
 {
     struct mnl_socket* sock = init_mnl_socket();
     if (sock == NULL) {
@@ -306,11 +306,11 @@ static int destroy_ipsec_tunnel(const str remote_addr, ipsec_t* s)
 
     // P-CSCF 'client' tunnel to UE 'server'
     remove_sa    (sock, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us);
-    remove_policy(sock, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, IPSEC_POLICY_DIRECTION_OUT);
+    remove_policy(sock, proto, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, IPSEC_POLICY_DIRECTION_OUT);
 
     // UE 'client' to P-CSCF 'server' tunnel
     remove_sa    (sock, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps);
-    remove_policy(sock, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
+    remove_policy(sock, proto, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
 
     // Release SPIs
     release_spi(s->spi_uc);
@@ -340,7 +340,7 @@ static void on_expire(struct pcontact *c, int type, void *param)
         return;
     }
 
-    destroy_ipsec_tunnel(c->received_host, c->security_temp->data.ipsec);
+    destroy_ipsec_tunnel(c->received_host, c->received_proto, c->security_temp->data.ipsec);
 }
 
 int add_supported_secagree_header(struct sip_msg* m)
@@ -451,7 +451,7 @@ int ipsec_create(struct sip_msg* m, udomain_t* d)
         goto cleanup;
     }
 
-    if(create_ipsec_tunnel(ci.received_host, s) != 0) {
+    if(create_ipsec_tunnel(ci.received_host, ci.received_proto, s) != 0) {
         goto cleanup;
     }
 
@@ -633,7 +633,7 @@ int ipsec_destroy(struct sip_msg* m, udomain_t* d)
         goto cleanup;
     }
 
-    destroy_ipsec_tunnel(ci.received_host, pcontact->security_temp->data.ipsec);
+    destroy_ipsec_tunnel(ci.received_host, ci.received_proto, pcontact->security_temp->data.ipsec);
 
     ret = IPSEC_CMD_SUCCESS;    // all good, set ret to SUCCESS, and exit
 
index 8806057..c177c88 100644 (file)
@@ -85,7 +85,7 @@ struct module_exports exports = {
        cmds,           /* exported functions */
        params,         /* exported params */
        0,              /*·exported·RPC·methods·*/
-       0,              /* exported pseudo-variables */ 
+       0,              /* exported pseudo-variables */
        0,              /*·response·function·*/
        mod_init,       /* module initialization function */
        child_init,     /* Per-child init function */
@@ -97,7 +97,6 @@ struct module_exports exports = {
  * Initialize parent
  */
 static int mod_init(void) {
-    struct socket_info * bind_addr = NULL;
     char addr[128];
     if(ipsec_listen_addr.len > sizeof(addr)-1) {
         LM_ERR("Bad value for ipsec listen address: %.*s\n", ipsec_listen_addr.len, ipsec_listen_addr.s);
@@ -128,42 +127,28 @@ static int mod_init(void) {
 
 
     //add listen interfaces
-    if(add_listen_iface(addr, NULL, ipsec_client_port, PROTO_UDP, 0) != 0) {
+    if(add_listen_iface(addr, NULL, ipsec_client_port, PROTO_TCP, 0) != 0) {
         LM_ERR("Error adding listen ipsec client interface\n");
         return -1;
     }
 
-    if(add_listen_iface(addr, NULL, ipsec_server_port, PROTO_UDP, 0) != 0) {
+    if(add_listen_iface(addr, NULL, ipsec_server_port, PROTO_TCP, 0) != 0) {
         LM_ERR("Error adding listen ipsec server interface\n");
         return -1;
     }
 
-    if(fix_all_socket_lists() != 0) {
-        LM_ERR("Error calling fix_all_socket_lists() during module initialisation\n");
-        return -1;
-    }
-
-    //bind client port
-    bind_addr = grep_sock_info(&ipsec_listen_addr, ipsec_client_port, PROTO_UDP);
-    if(!bind_addr) {
-        LM_ERR("Error calling grep_sock_info() for ipsec client port during module initialisation\n");
-        return -1;
-    }
-
-    if(udp_init(bind_addr) != 0) {
-        LM_ERR("Error calling udp_init() during for ipsec client port module initialisation\n");
+    if(add_listen_iface(addr, NULL, ipsec_client_port, PROTO_UDP, 0) != 0) {
+        LM_ERR("Error adding listen ipsec client interface\n");
         return -1;
     }
 
-    //bind server port
-    bind_addr = grep_sock_info(&ipsec_listen_addr, ipsec_server_port, PROTO_UDP);
-    if(!bind_addr) {
-        LM_ERR("Error calling grep_sock_info() for ipsec server port during module initialisation\n");
+    if(add_listen_iface(addr, NULL, ipsec_server_port, PROTO_UDP, 0) != 0) {
+        LM_ERR("Error adding listen ipsec server interface\n");
         return -1;
     }
 
-    if(udp_init(bind_addr) != 0) {
-        LM_ERR("Error calling udp_init() during for ipsec server port module initialisation\n");
+    if(fix_all_socket_lists() != 0) {
+        LM_ERR("Error calling fix_all_socket_lists() during module initialisation\n");
         return -1;
     }
 
index 55eced7..3b0c149 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "../../core/dprint.h"
 #include "../../core/mem/pkg.h"
+#include "../../core/ip_addr.h"
 
 #include <errno.h>
 #include <arpa/inet.h>
@@ -89,7 +90,26 @@ static void string_to_key(char* dst, const str key_string)
     }
 }
 
-int add_sa(struct mnl_socket* nl_sock, str src_addr_param, str dest_addr_param, int s_port, int d_port, int long id, str ck, str ik)
+// Converts the protocol enum used in Kamailio to the constants used in Linux
+unsigned short kamailio_to_linux_proto(const unsigned short kamailio_proto)
+{
+    switch(kamailio_proto) {
+        case PROTO_UDP:
+            return IPPROTO_UDP;
+        case PROTO_TCP:
+            return IPPROTO_TCP;
+        case PROTO_NONE:
+        case PROTO_TLS:
+        case PROTO_SCTP:
+           case PROTO_WS:
+        case PROTO_WSS:
+        case PROTO_OTHER:
+        default:
+            return IPPROTO_MAX;
+    };
+}
+
+int add_sa(struct mnl_socket* nl_sock, unsigned short proto, str src_addr_param, str dest_addr_param, int s_port, int d_port, int long id, str ck, str ik)
 {
     char l_msg_buf[MNL_SOCKET_BUFFER_SIZE];
     char l_auth_algo_buf[XFRM_TMPLS_BUF_SIZE];
@@ -107,16 +127,22 @@ int add_sa(struct mnl_socket* nl_sock, str src_addr_param, str dest_addr_param,
     memset(l_auth_algo_buf, 0, sizeof(l_auth_algo_buf));
     memset(l_enc_algo_buf, 0, sizeof(l_enc_algo_buf));
 
+    unsigned sel_proto = 0;
+    if((sel_proto = kamailio_to_linux_proto(proto)) == IPPROTO_MAX) {
+        LM_ERR("Invalid port was passed to the function: %d\n", proto);
+        return -1;
+    }
+
     // convert input IP addresses and keys to char*
     if((src_addr = pkg_malloc(src_addr_param.len+1)) == NULL) {
         LM_ERR("Error allocating memory for src addr during SA creation\n");
-        return -1;
+        return -2;
     }
 
     if((dest_addr = pkg_malloc(dest_addr_param.len+1)) == NULL) {
         pkg_free(src_addr);
         LM_ERR("Error allocating memory for dest addr during SA creation\n");
-        return -2;
+        return -3;
     }
 
     memset(src_addr, 0, src_addr_param.len+1);
@@ -143,7 +169,7 @@ int add_sa(struct mnl_socket* nl_sock, str src_addr_param, str dest_addr_param,
     l_xsainfo->sel.sport        = htons(s_port);
     l_xsainfo->sel.sport_mask   = 0xFFFF;
     l_xsainfo->sel.prefixlen_s  = 32;
-    l_xsainfo->sel.proto        = IPPROTO_UDP;
+    l_xsainfo->sel.proto        = sel_proto;
     l_xsainfo->sel.user         = htonl(xfrm_user_selector);
 
     l_xsainfo->saddr.a4         = inet_addr(src_addr);
@@ -255,13 +281,19 @@ int remove_sa(struct mnl_socket* nl_sock, str src_addr_param, str dest_addr_para
 }
 
 
-int add_policy(struct mnl_socket* mnl_socket, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir)
+int add_policy(struct mnl_socket* mnl_socket, unsigned short proto, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir)
 {
     char                            l_msg_buf[MNL_SOCKET_BUFFER_SIZE];
     char                            l_tmpls_buf[XFRM_TMPLS_BUF_SIZE];
     struct nlmsghdr*                l_nlh;
     struct xfrm_userpolicy_info*    l_xpinfo;
 
+    unsigned sel_proto = 0;
+    if((sel_proto = kamailio_to_linux_proto(proto)) == IPPROTO_MAX) {
+        LM_ERR("Invalid port was passed to the function: %d\n", proto);
+        return -1;
+    }
+
     char* src_addr = NULL;
     char* dest_addr = NULL;
 
@@ -304,7 +336,7 @@ int add_policy(struct mnl_socket* mnl_socket, str src_addr_param, str dest_addr_
     l_xpinfo->sel.sport         = htons(src_port);
     l_xpinfo->sel.sport_mask    = 0xFFFF;
     l_xpinfo->sel.prefixlen_s   = 32;
-    l_xpinfo->sel.proto         = IPPROTO_UDP;
+    l_xpinfo->sel.proto         = sel_proto;
     l_xpinfo->sel.user          = htonl(xfrm_user_selector);
 
     l_xpinfo->lft.soft_byte_limit   = XFRM_INF;
@@ -358,9 +390,14 @@ int add_policy(struct mnl_socket* mnl_socket, str src_addr_param, str dest_addr_
     return 0;
 }
 
-
-int remove_policy(struct mnl_socket* mnl_socket, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir)
+int remove_policy(struct mnl_socket* mnl_socket, unsigned short proto, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir)
 {
+    unsigned sel_proto = 0;
+    if((sel_proto = kamailio_to_linux_proto(proto)) == IPPROTO_MAX) {
+        LM_ERR("Invalid port was passed to the function: %d\n", proto);
+        return -1;
+    }
+
     unsigned char policy_dir = 0;
 
     if(dir == IPSEC_POLICY_DIRECTION_IN) {
@@ -413,7 +450,7 @@ int remove_policy(struct mnl_socket* mnl_socket, str src_addr_param, str dest_ad
         .xpid.sel.sport         = htons(src_port),
         .xpid.sel.sport_mask    = 0xFFFF,
         .xpid.sel.prefixlen_s   = 32,
-        .xpid.sel.proto         = IPPROTO_UDP
+        .xpid.sel.proto         = sel_proto
     };
 
     if(mnl_socket_sendto(mnl_socket, &req.n, req.n.nlmsg_len) < 0)
index 82ad405..71390f1 100644 (file)
@@ -38,12 +38,14 @@ enum ipsec_policy_direction {
 
 struct mnl_socket* init_mnl_socket();
 void close_mnl_socket(struct mnl_socket* sock);
+unsigned short kamailio_to_linux_proto(const unsigned short kamailio_proto);
 
-int add_sa(struct mnl_socket* nl_sock, str src_addr_param, str dest_addr_param, int s_port, int d_port, int long id, str ck, str ik);
+
+int add_sa(struct mnl_socket* nl_sock,  unsigned short proto, str src_addr_param, str dest_addr_param, int s_port, int d_port, int long id, str ck, str ik);
 int remove_sa(struct mnl_socket* nl_sock, str src_addr_param, str dest_addr_param, int s_port, int d_port, int long id);
 
-int add_policy(struct mnl_socket* mnl_socket, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir);
-int remove_policy(struct mnl_socket* mnl_socket, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir);
+int add_policy(struct mnl_socket* mnl_socket,  unsigned short proto, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir);
+int remove_policy(struct mnl_socket* mnl_socket,  unsigned short proto, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir);
 
 int clean_sa(struct mnl_socket*  mnl_socket);
 int clean_policy(struct mnl_socket*  mnl_socket);