瀏覽代碼

Merge pull request #1974 from alexyosifov/ipsec_tcp

Ipsec tcp
Tsvetomir Dimitrov 6 年之前
父節點
當前提交
711da9ddac

+ 0 - 230
src/modules/ims_ipsec_pcscf/README

@@ -1,230 +0,0 @@
-The IMS IPSec-Registrar Module
-
-Dragos Vingarzan
-
-   FhG Fokus
-   <[email protected]>
-
-Jason Penton
-
-   Smile Communications
-   <[email protected]>
-
-Richard Good
-
-   Smile Communications
-   <[email protected]>
-
-Carsten Bock
-
-   ng-voice GmbH
-   <[email protected]>
-
-Tsvetomir Dimitrov
-
-   <[email protected]>
-
-   Copyright © 2007 FhG FOKUS
-
-   Copyright © 2012 Smile Communications
-
-   Copyright © 2015 ng-voice GmbH
-     __________________________________________________________________
-
-   Table of Contents
-
-   1. Admin Guide
-
-        1. Overview
-        2. Dependencies
-
-              2.1. Kamailio Modules
-              2.2. External Libraries or Applications
-
-        3. Parameters
-
-              3.1. ipsec_listen_addr (string)
-              3.2. ipsec_client_port (int)
-              3.3. ipsec_server_port (int)
-              3.4. ipsec_spi_id_start (int)
-              3.5. ipsec_spi_id_range (int)
-
-        4. Functions
-
-              4.1. ipsec_create(domain)
-              4.2. ipsec_forward(domain)
-              4.3. ipsec_destroy(domain)
-
-   List of Examples
-
-   1.1. ipsec_listen_addr parameter usage
-   1.2. ipsec_client_port parameter usage
-   1.3. ipsec_server_port parameter usage
-   1.4. ipsec_spi_id_start parameter usage
-   1.5. ipsec_spi_id_range parameter usage
-   1.6. ipsec_create
-   1.7. ipsec_forward
-   1.8. ipsec_forward
-
-Chapter 1. Admin Guide
-
-   Table of Contents
-
-   1. Overview
-   2. Dependencies
-
-        2.1. Kamailio Modules
-        2.2. External Libraries or Applications
-
-   3. Parameters
-
-        3.1. ipsec_listen_addr (string)
-        3.2. ipsec_client_port (int)
-        3.3. ipsec_server_port (int)
-        3.4. ipsec_spi_id_start (int)
-        3.5. ipsec_spi_id_range (int)
-
-   4. Functions
-
-        4.1. ipsec_create(domain)
-        4.2. ipsec_forward(domain)
-        4.3. ipsec_destroy(domain)
-
-1. Overview
-
-   This module contains methods for IPSec initialisation/deinitialisation
-   related for usage of Kamailio as a Proxy-CSCF.
-
-2. Dependencies
-
-   2.1. Kamailio Modules
-   2.2. External Libraries or Applications
-
-2.1. Kamailio Modules
-
-   The Following modules must be loaded before this module:
-     * Usrloc PCSCF
-     * TM
-
-2.2. External Libraries or Applications
-
-   This modules requires the internal IMS library and libmnl for operating
-   with netlink sockets.
-
-3. Parameters
-
-   3.1. ipsec_listen_addr (string)
-   3.2. ipsec_client_port (int)
-   3.3. ipsec_server_port (int)
-   3.4. ipsec_spi_id_start (int)
-   3.5. ipsec_spi_id_range (int)
-
-3.1. ipsec_listen_addr (string)
-
-   IP address which the Proxy-CSCF will use for incoming/outgoing SIP
-   traffic over IPSec.
-
-   Default value is "127.0.0.1"
-
-   Example 1.1. ipsec_listen_addr parameter usage
-...
-modparam("ims_ipsec_pcscf", "ipsec_listen_addr", "127.0.0.1")
-...
-
-3.2. ipsec_client_port (int)
-
-   Port number which will be bound for incoming (server) IPSec traffic.
-
-   Default value is 5963.
-
-   Example 1.2. ipsec_client_port parameter usage
-...
-modparam("ims_ipsec_pcscf", "ipsec_client_port", 5062)
-...
-
-3.3. ipsec_server_port (int)
-
-   Port number which will be bound for incoming (server) IPSec traffic.
-
-   Default value is 5063.
-
-   Example 1.3. ipsec_server_port parameter usage
-...
-modparam("ims_ipsec_pcscf", "ipsec_server_port", 5063)
-...
-
-3.4. ipsec_spi_id_start (int)
-
-   Each IPSec tunnel has a unique system-wide identifier. This and the
-   following option allows to tune the SPIs used by Kamailio in order to
-   avoid collisions with other IPSec useres. If Kamailio is the only
-   process on the system which uses IPSec, don't bother with this option.
-
-   Default value is 100.
-
-   Example 1.4. ipsec_spi_id_start parameter usage
-...
-modparam("ims_ipsec_pcscf", "ipsec_spi_id_start", 100)
-...
-
-3.5. ipsec_spi_id_range (int)
-
-   How many SPIs to be allocated for the process. E.g. if
-   ipsec_spi_id_start = 100 and ipsec_spi_id_range = 1000, SPIs between
-   100 and 1100 will be used.
-
-   Default value is 1000.
-
-   Example 1.5. ipsec_spi_id_range parameter usage
-...
-modparam("ims_ipsec_pcscf", "ipsec_spi_id_range", 1000)
-...
-
-4. Functions
-
-   4.1. ipsec_create(domain)
-   4.2. ipsec_forward(domain)
-   4.3. ipsec_destroy(domain)
-
-4.1. ipsec_create(domain)
-
-   This function creates IPSec SA and Policy based on the parameters sent
-   in Security-Client header in the REGISTER message. It's called when OK
-   is received. The function also adds Security-Server header to the
-   REGISTER.
-
-   Meaning of the parameters is as follows:
-     * domain - Logical domain within the registrar. If a database is used
-       then this must be name of the table which stores the contacts.
-
-   Example 1.6. ipsec_create
-...
-ipsec_create("location");
-...
-
-4.2. ipsec_forward(domain)
-
-   The function processes redirects outgoing message via the IPSec tunnel
-   initiated with ipsec_create().
-
-   Meaning of the parameters is as follows:
-     * domain - Logical domain within the registrar. If a database is used
-       then this must be name of the table which stores the contacts.
-
-   Example 1.7. ipsec_forward
-...
-ipsec_forward("location");
-...
-
-4.3. ipsec_destroy(domain)
-
-   The function destroys IPSec tunnel, created with ipsec_create.
-
-   Meaning of the parameters is as follows:
-     * domain - Logical domain within the registrar. If a database is used
-       then this must be name of the table which stores the contacts.
-
-   Example 1.8. ipsec_forward
-...
-ipsec_destroy("location");
-...

+ 123 - 84
src/modules/ims_ipsec_pcscf/cmd.c

@@ -57,6 +57,7 @@
 
 
 extern str ipsec_listen_addr;
+extern str ipsec_listen_addr6;
 extern short ipsec_listen_port;
 extern short ipsec_server_port;
 extern short ipsec_client_port;
@@ -111,23 +112,19 @@ static str get_www_auth_param(const char* param_name, str www_auth)
     return val;
 }
 
-
 static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
 {
     contact_body_t* cb = NULL;
     struct via_body* vb = NULL;
-    unsigned short port, proto = 0;
     struct sip_msg* req = NULL;
 
-
     if(!ci) {
-        LM_ERR("fill_contact() called with null ptr\n");
+        LM_ERR("called with null ptr\n");
         return -1;
     }
 
     memset(ci, 0, sizeof(struct pcontact_info));
 
-
     if(m->first_line.type == SIP_REQUEST) {
         struct sip_uri uri;
         memset(&uri, 0, sizeof(struct sip_uri));
@@ -140,21 +137,15 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
         // populate host,port, aor in CI
         ci->via_host = uri.host;
         ci->via_port = uri.port_no ? uri.port_no : 5060;
-        ci->via_prot = proto;
+        ci->via_prot = 0;
         ci->aor = m->first_line.u.request.uri;
 
         req = m;
     }
     else if(m->first_line.type == SIP_REPLY) {
-
-        cb = cscf_parse_contacts(m);
-        vb = cscf_get_ue_via(m);
-        port = vb->port?vb->port:5060;
-        proto = vb->proto;
-
         struct cell *t = tmb.t_gett();
         if (!t || t == (void*) -1) {
-            LM_ERR("fill_contact(): Reply without transaction\n");
+            LM_ERR("Reply without transaction\n");
             return -1;
         }
 
@@ -162,18 +153,24 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
 
         cb = cscf_parse_contacts(req);
         if (!cb || (!cb->contacts)) {
-            LM_ERR("fill_contact(): No contact headers\n");
+            LM_ERR("Reply No contact headers\n");
+            return -1;
+        }
+
+        vb = cscf_get_ue_via(m);
+        if (!vb) {
+            LM_ERR("Reply No via body headers\n");
             return -1;
         }
 
         // populate CI with bare minimum
         ci->via_host = vb->host;
-        ci->via_port = port;
-        ci->via_prot = proto;
+        ci->via_port = vb->port;
+        ci->via_prot = vb->proto;
         ci->aor = cb->contacts->uri;
     }
     else {
-        LM_ERR("fill_contact(): Unknown first line type: %d\n", m->first_line.type);
+        LM_ERR("Unknown first line type: %d\n", m->first_line.type);
         return -1;
     }
 
@@ -189,6 +186,11 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
     ci->received_port = req->rcv.src_port;
     ci->received_proto = req->rcv.proto;
 
+    LM_DBG("SIP %s fill contact with AOR [%.*s], VIA [%d://%.*s:%d], received_host [%d://%.*s:%d]\n",
+            m->first_line.type == SIP_REQUEST ? "REQUEST" : "REPLY",
+            ci->aor.len, ci->aor.s, ci->via_prot, ci->via_host.len, ci->via_host.s, ci->via_port,
+            ci->received_proto, ci->received_host.len, ci->received_host.s, ci->received_port);
+
     // Set to default, if not set:
     if (ci->received_port == 0)
         ci->received_port = 5060;
@@ -271,49 +273,6 @@ static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m)
     return 0;
 }
 
-static int convert_ip_address(const str ip_addr, const unsigned int af, struct ip_addr* result) {
-    memset(result, 0, sizeof(struct ip_addr));
-    int return_code = -1;
-
-    //Allocate dynamically memory in order to avoid buffer overflows
-    char* ipaddr_str = NULL;
-    if((ipaddr_str = pkg_malloc(ip_addr.len + 1)) == NULL) {
-        LM_CRIT("Error allocating memory for IP address conversion.\n");
-        return -1;
-    }
-    memset(ipaddr_str, 0, ip_addr.len + 1);
-    memcpy(ipaddr_str, ip_addr.s, ip_addr.len);
-
-    int err = 0;
-
-    if((err = inet_pton(af, ipaddr_str, &result->u.addr)) != 1) {
-        if(err == 0) {
-            LM_ERR("Error converting ipsec listen IP address. Bad format %.*s\n", ip_addr.len, ip_addr.s);
-        }
-        else {
-            LM_ERR("Error converting ipsec listen IP address: %s\n", strerror(errno));
-        }
-        goto cleanup;   // return_code = -1 by default
-    }
-
-    //Set len by address family
-    if(af == AF_INET6) {
-        result->len = 16;
-    }
-    else {
-        result->len = 4;
-    }
-
-    result->af = af;
-
-    //Set success return code
-    return_code = 0;
-
-cleanup:
-    pkg_free(ipaddr_str);
-    return return_code;
-}
-
 static int create_ipsec_tunnel(const struct ip_addr *remote_addr, unsigned short proto, ipsec_t* s)
 {
     struct mnl_socket* sock = init_mnl_socket();
@@ -322,10 +281,21 @@ static int create_ipsec_tunnel(const struct ip_addr *remote_addr, unsigned short
     }
 
     //Convert ipsec address from str to struct ip_addr
-    struct ip_addr ipsec_addr;
-    if(convert_ip_address(ipsec_listen_addr, remote_addr->af, &ipsec_addr) != 0) {
-        //there is an error msg in convert_ip_address()
-        return -1;
+	ip_addr_t ipsec_addr;
+
+    if(remote_addr->af == AF_INET){
+        if(str2ipbuf(&ipsec_listen_addr, &ipsec_addr) < 0){
+            LM_ERR("Unable to convert ipsec addr4 [%.*s]\n", ipsec_listen_addr.len, ipsec_listen_addr.s);
+            return 0;
+        }
+    } else if(remote_addr->af == AF_INET6){
+        if(str2ip6buf(&ipsec_listen_addr6, &ipsec_addr) < 0){
+            LM_ERR("Unable to convert ipsec addr6 [%.*s]\n", ipsec_listen_addr6.len, ipsec_listen_addr6.s);
+            return 0;
+        }
+    } else {
+        LM_ERR("Unsupported AF %d\n", remote_addr->af);
+        return 0;
     }
 
     //Convert to char* for logging
@@ -336,17 +306,30 @@ static int create_ipsec_tunnel(const struct ip_addr *remote_addr, unsigned short
         return -1;
     }
 
-    LM_DBG("Creating security associations: Local IP: %.*s client port: %d server port: %d; UE IP: %s; client port %d server port %d\n",
-            ipsec_listen_addr.len, ipsec_listen_addr.s, ipsec_client_port, ipsec_server_port,
-            remote_addr_str, s->port_uc, s->port_us);
+    LM_DBG("Creating security associations: Local IP: %.*s client port: %d server port: %d; UE IP: %s; client port %d server port %d; spi_ps %u, spi_pc %u, spi_us %u, spi_uc %u\n",
+            remote_addr->af == AF_INET ? ipsec_listen_addr.len : ipsec_listen_addr6.len,
+            remote_addr->af == AF_INET ? ipsec_listen_addr.s : ipsec_listen_addr6.s,
+            ipsec_client_port, ipsec_server_port, remote_addr_str, s->port_uc, s->port_us, s->spi_ps, s->spi_pc, s->spi_us, s->spi_uc);
 
-    // P-CSCF 'client' tunnel to UE 'server'
-    add_sa    (sock, proto, &ipsec_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, s->ck, s->ik);
+    // SA1 UE client to P-CSCF server
+    //                      src adrr     dst addr     src port    dst port
+    add_sa    (sock, proto, remote_addr, &ipsec_addr, s->port_uc, ipsec_server_port, s->spi_ps, s->ck, s->ik, s->r_alg);
+    add_policy(sock, proto, remote_addr, &ipsec_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
+
+    // SA2 P-CSCF client to UE server
+    //                      src adrr     dst addr     src port           dst port
+    add_sa    (sock, proto, &ipsec_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, s->ck, s->ik, s->r_alg);
     add_policy(sock, proto, &ipsec_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, proto, remote_addr, &ipsec_addr, s->port_uc, ipsec_server_port, s->spi_ps, s->ck, s->ik);
-    add_policy(sock, proto, remote_addr, &ipsec_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
+    // SA3 P-CSCF server to UE client
+    //                      src adrr     dst addr     src port           dst port
+    add_sa    (sock, proto, &ipsec_addr, remote_addr, ipsec_server_port, s->port_uc, s->spi_uc, s->ck, s->ik, s->r_alg);
+    add_policy(sock, proto, &ipsec_addr, remote_addr, ipsec_server_port, s->port_uc, s->spi_uc, IPSEC_POLICY_DIRECTION_OUT);
+
+    // SA4 UE server to P-CSCF client
+    //                      src adrr     dst addr     src port    dst port
+    add_sa    (sock, proto, remote_addr, &ipsec_addr, s->port_us, ipsec_client_port, s->spi_pc, s->ck, s->ik, s->r_alg);
+    add_policy(sock, proto, remote_addr, &ipsec_addr, s->port_us, ipsec_client_port, s->spi_pc, IPSEC_POLICY_DIRECTION_IN);
 
     close_mnl_socket(sock);
 
@@ -360,23 +343,32 @@ static int destroy_ipsec_tunnel(const str remote_addr, unsigned short proto, ips
         return -1;
     }
 
+    // TODO: pass ipsec listen address v4 or v6 to destroy the tunnel
+
     LM_DBG("Destroying security associations: Local IP: %.*s client port: %d server port: %d; UE IP: %.*s; client port %d server port %d\n",
             ipsec_listen_addr.len, ipsec_listen_addr.s, ipsec_client_port, ipsec_server_port,
             remote_addr.len, remote_addr.s, s->port_uc, s->port_us);
 
-    // P-CSCF 'client' tunnel to UE 'server'
+    // SA1 UE client to P-CSCF server
+    remove_sa    (sock, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps);
+    remove_policy(sock, proto, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
+
+    // SA2 P-CSCF client to UE server
     remove_sa    (sock, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us);
     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, proto, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
+    // SA3 P-CSCF server to UE client
+    remove_sa    (sock, ipsec_listen_addr, remote_addr, ipsec_server_port, s->port_uc, s->spi_uc);
+    remove_policy(sock, proto, ipsec_listen_addr, remote_addr, ipsec_server_port, s->port_uc, s->spi_uc, IPSEC_POLICY_DIRECTION_OUT);
+
+    // SA4 UE server to P-CSCF client
+    remove_sa    (sock, remote_addr, ipsec_listen_addr, s->port_us, ipsec_client_port, s->spi_pc);
+    remove_policy(sock, proto, remote_addr, ipsec_listen_addr, s->port_us, ipsec_client_port, s->spi_pc, IPSEC_POLICY_DIRECTION_IN);
 
     // Release SPIs
     release_spi(s->spi_uc);
     release_spi(s->spi_us);
 
-
     close_mnl_socket(sock);
     return 0;
 }
@@ -532,6 +524,12 @@ int ipsec_create(struct sip_msg* m, udomain_t* d)
         goto cleanup;
     }
 
+    // Update temp security parameters
+    if(ul.update_temp_security(d, pcontact->security_temp->type, pcontact->security_temp, pcontact) != 0)
+    {
+        LM_ERR("Error updating temp security\n");
+    }
+
     // Destroy the tunnel, if the contact expires
     if(ul.register_ulcb(pcontact, PCSCF_CONTACT_EXPIRE|PCSCF_CONTACT_DELETE, on_expire, NULL) != 1) {
         LM_ERR("Error subscribing for contact\n");
@@ -562,6 +560,24 @@ int ipsec_forward(struct sip_msg* m, udomain_t* d)
     struct pcontact_info ci;
     pcontact_t* pcontact = NULL;
     int ret = IPSEC_CMD_FAIL; // FAIL by default
+    unsigned char dst_proto = PROTO_UDP;
+    unsigned short dst_port = 0;
+    unsigned short src_port = 0;
+    ip_addr_t via_host;
+    
+    struct sip_msg* req = NULL;
+    if(m->first_line.type == SIP_REPLY) {
+        // Get request from reply
+        struct cell *t = tmb.t_gett();
+        if (!t) {
+            LM_ERR("Error getting transaction\n");
+            goto cleanup;
+        }
+
+        req = t->uas.request;
+    } else {
+        req = m;
+    }
 
     //
     // Find the contact
@@ -578,6 +594,10 @@ int ipsec_forward(struct sip_msg* m, udomain_t* d)
         goto cleanup;
     }
 
+    if(str2ipxbuf(&ci.via_host, &via_host) < 0){
+        LM_ERR("Error getting AF from ci.via_host\n");
+        goto cleanup;
+    }
 
     if(pcontact->security_temp == NULL) {
         LM_ERR("No security parameters found in contact\n");
@@ -592,7 +612,6 @@ int ipsec_forward(struct sip_msg* m, udomain_t* d)
 
     ipsec_t* s = pcontact->security_temp->data.ipsec;
 
-
     // Update the destination
     //
     //       from sec-agree
@@ -609,7 +628,27 @@ int ipsec_forward(struct sip_msg* m, udomain_t* d)
     }
 
     char buf[1024];
-    int buf_len = snprintf(buf, sizeof(buf) - 1, "sip:%.*s:%d", ci.via_host.len, ci.via_host.s, s->port_us);
+    if(m->first_line.type == SIP_REPLY){
+        // for Reply get the dest proto from the received request
+        dst_proto = req->rcv.proto;
+
+        // for Reply and TCP sends from P-CSCF server port, for Reply and UDP sends from P-CSCF client port
+        src_port = dst_proto == PROTO_TCP ? ipsec_server_port : ipsec_client_port;
+
+        // for Reply and TCP sends to UE client port, for Reply and UDP sends to UE server port
+        dst_port = dst_proto == PROTO_TCP ? s->port_uc : s->port_us;
+    }else{
+        // for Request get the dest proto from the saved contact
+        dst_proto = pcontact->received_proto;
+
+        // for Request sends from P-CSCF client port
+        src_port = ipsec_client_port;
+        
+        // for Request sends to UE server port
+        dst_port = s->port_us;
+    }
+
+    int buf_len = snprintf(buf, sizeof(buf) - 1, "sip:%.*s:%d", ci.via_host.len, ci.via_host.s, dst_port);
 
     if((m->dst_uri.s = pkg_malloc(buf_len)) == NULL) {
         LM_ERR("Error allocating memory for dst_uri\n");
@@ -620,9 +659,9 @@ int ipsec_forward(struct sip_msg* m, udomain_t* d)
     m->dst_uri.len = buf_len;
 
     // Set send socket
-    struct socket_info * client_sock = grep_sock_info(&ipsec_listen_addr, ipsec_client_port, PROTO_UDP);
+    struct socket_info * client_sock = grep_sock_info(via_host.af == AF_INET ? &ipsec_listen_addr : &ipsec_listen_addr6, src_port, dst_proto);
     if(!client_sock) {
-        LM_ERR("Error calling grep_sock_info() for ipsec client port in ipsec_forward\n");
+        LM_ERR("Error calling grep_sock_info() for ipsec client port\n");
         return -1;
     }
     m->force_send_socket = client_sock;
@@ -631,9 +670,9 @@ int ipsec_forward(struct sip_msg* m, udomain_t* d)
     struct dest_info dst_info;
     dst_info.send_sock = client_sock;
 #ifdef USE_DNS_FAILOVER
-    if (!uri2dst(NULL, &dst_info, m, &m->dst_uri, PROTO_UDP)) {
+    if (!uri2dst(NULL, &dst_info, m, &m->dst_uri, dst_proto)) {
 #else
-    if (!uri2dst(&dst_info, m, &m->dst_uri, PROTO_UDP)) {
+    if (!uri2dst(&dst_info, m, &m->dst_uri, dst_proto)) {
 #endif
         LM_ERR("Error converting dst_uri (%.*s) to struct dst_info\n", m->dst_uri.len, m->dst_uri.s);
         goto cleanup;
@@ -649,7 +688,7 @@ int ipsec_forward(struct sip_msg* m, udomain_t* d)
         t->uas.response.dst = dst_info;
     }
 
-    LM_DBG("Destination changed to %.*s\n", m->dst_uri.len, m->dst_uri.s);
+    LM_DBG("Destination changed to [%d://%.*s]\n", dst_info.proto, m->dst_uri.len, m->dst_uri.s);
 
     ret = IPSEC_CMD_SUCCESS; // all good, return SUCCESS
 

+ 19 - 2
src/modules/ims_ipsec_pcscf/doc/ims_ipsec_pcscf_admin.xml

@@ -49,14 +49,31 @@
       <title><varname>ipsec_listen_addr</varname> (string)</title>
 
       <para>IP address which the Proxy-CSCF will use for incoming/outgoing SIP traffic over IPSec.</para>
-      <para><emphasis>Default value is "127.0.0.1"</emphasis></para>
+      <para><emphasis>Default value is empty string (null) - IPv4 listen interface will not be added</emphasis></para>
 
       <example>
         <title><varname>ipsec_listen_addr</varname> parameter usage</title>
 
         <programlisting format="linespecific">
 ...
-modparam("ims_ipsec_pcscf", "ipsec_listen_addr", "127.0.0.1")
+modparam("ims_ipsec_pcscf", "ipsec_listen_addr", "")
+...
+        </programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>ipsec_listen_addr6</varname> (string)</title>
+
+      <para>IPv6 address which the Proxy-CSCF will use for incoming/outgoing SIP traffic over IPSec.</para>
+      <para><emphasis>Default value is empty string (null) - IPv6 listen interface will not be added</emphasis></para>
+
+      <example>
+        <title><varname>ipsec_listen_addr6</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("ims_ipsec_pcscf", "ipsec_listen_addr6", "")
 ...
         </programlisting>
       </example>

+ 65 - 28
src/modules/ims_ipsec_pcscf/ims_ipsec_pcscf_mod.c

@@ -35,7 +35,8 @@ usrloc_api_t ul;						/**!< Structure containing pointers to usrloc functions*/
 struct tm_binds tmb;					/**!< TM API structure */
 
 
-str ipsec_listen_addr = str_init("127.0.0.1");
+str ipsec_listen_addr = STR_NULL;
+str ipsec_listen_addr6 = STR_NULL;
 int ipsec_client_port =  5062;
 int ipsec_server_port =  5063;
 int spi_id_start = 100;
@@ -68,7 +69,8 @@ static cmd_export_t cmds[] = {
  * Exported parameters
  */
 static param_export_t params[] = {
-	{"ipsec_listen_addr",   PARAM_STR, &ipsec_listen_addr   },
+	{"ipsec_listen_addr",  PARAM_STR, &ipsec_listen_addr   },
+	{"ipsec_listen_addr6",  PARAM_STR, &ipsec_listen_addr6   },
 	{"ipsec_client_port",	INT_PARAM, &ipsec_client_port   },
 	{"ipsec_server_port",	INT_PARAM, &ipsec_server_port   },
 	{"ipsec_spi_id_start",	INT_PARAM, &spi_id_start},
@@ -97,13 +99,8 @@ struct module_exports exports = {
  * Initialize parent
  */
 static int mod_init(void) {
-    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);
-        return -1;
-    }
-    memset(addr, 0, sizeof(addr));
-    memcpy(addr, ipsec_listen_addr.s, ipsec_listen_addr.len);
+    char addr4[128];
+	char addr6[128];
 
 	bind_usrloc_t bind_usrloc;
 
@@ -116,36 +113,76 @@ static int mod_init(void) {
 	if (bind_usrloc(&ul) < 0) {
 		return -1;
 	}
-	LM_DBG("Successfully bound to PCSCF Usrloc module\n");
+	LM_INFO("Successfully bound to PCSCF Usrloc module\n");
 
 	/* load the TM API */
 	if (load_tm_api(&tmb) != 0) {
 		LM_ERR("can't load TM API\n");
 		return -1;
 	}
-	LM_DBG("Successfully bound to TM module\n");
+	LM_INFO("Successfully bound to TM module\n");
 
+	if(ipsec_listen_addr.len) {
+		if(ipsec_listen_addr.len > sizeof(addr4)-1) {
+        	LM_ERR("Bad value for ipsec listen address IPv4: %.*s\n", ipsec_listen_addr.len, ipsec_listen_addr.s);
+        	return -1;
+    	}
 
-    //add listen interfaces
-    if(add_listen_iface(addr, NULL, ipsec_client_port, PROTO_TCP, 0) != 0) {
-        LM_ERR("Error adding listen ipsec client interface\n");
-        return -1;
-    }
+	    memset(addr4, 0, sizeof(addr4));
+	    memcpy(addr4, ipsec_listen_addr.s, ipsec_listen_addr.len);
 
-    if(add_listen_iface(addr, NULL, ipsec_server_port, PROTO_TCP, 0) != 0) {
-        LM_ERR("Error adding listen ipsec server interface\n");
-        return -1;
-    }
+		//add listen interfaces for IPv4
+		if(add_listen_iface(addr4, NULL, ipsec_client_port, PROTO_TCP, 0) != 0) {
+			LM_ERR("Error adding listen ipsec client TCP interface for IPv4\n");
+			return -1;
+		}
 
-    if(add_listen_iface(addr, NULL, ipsec_client_port, PROTO_UDP, 0) != 0) {
-        LM_ERR("Error adding listen ipsec client interface\n");
-        return -1;
-    }
+		if(add_listen_iface(addr4, NULL, ipsec_server_port, PROTO_TCP, 0) != 0) {
+			LM_ERR("Error adding listen ipsec server TCP interface for IPv4\n");
+			return -1;
+		}
 
-    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(add_listen_iface(addr4, NULL, ipsec_client_port, PROTO_UDP, 0) != 0) {
+			LM_ERR("Error adding listen ipsec client UDP interface for IPv4\n");
+			return -1;
+		}
+
+		if(add_listen_iface(addr4, NULL, ipsec_server_port, PROTO_UDP, 0) != 0) {
+			LM_ERR("Error adding listen ipsec server UDP interface for IPv4\n");
+			return -1;
+		}
+	}
+
+	if(ipsec_listen_addr6.len) {
+		if(ipsec_listen_addr6.len > sizeof(addr6)-1) {
+			LM_ERR("Bad value for ipsec listen address IPv6: %.*s\n", ipsec_listen_addr6.len, ipsec_listen_addr6.s);
+        	return -1;
+		}
+
+		memset(addr6, 0, sizeof(addr6));
+    	memcpy(addr6, ipsec_listen_addr6.s, ipsec_listen_addr6.len);
+
+		//add listen interfaces for IPv6
+		if(add_listen_iface(addr6, NULL, ipsec_client_port, PROTO_TCP, 0) != 0) {
+			LM_ERR("Error adding listen ipsec client TCP interface for IPv6\n");
+			return -1;
+		}
+
+		if(add_listen_iface(addr6, NULL, ipsec_server_port, PROTO_TCP, 0) != 0) {
+			LM_ERR("Error adding listen ipsec server TCP interface for IPv6\n");
+			return -1;
+		}
+
+		if(add_listen_iface(addr6, NULL, ipsec_client_port, PROTO_UDP, 0) != 0) {
+			LM_ERR("Error adding listen ipsec client UDP interface for IPv6\n");
+			return -1;
+		}
+
+		if(add_listen_iface(addr6, NULL, ipsec_server_port, PROTO_UDP, 0) != 0) {
+			LM_ERR("Error adding listen ipsec server UDP interface for IPv6\n");
+			return -1;
+		}
+	}
 
     if(fix_all_socket_lists() != 0) {
         LM_ERR("Error calling fix_all_socket_lists() during module initialisation\n");

+ 12 - 2
src/modules/ims_ipsec_pcscf/ipsec.c

@@ -109,7 +109,7 @@ unsigned short kamailio_to_linux_proto(const unsigned short kamailio_proto)
     };
 }
 
-int add_sa(struct mnl_socket* nl_sock, unsigned short proto, const struct ip_addr *src_addr_param, const struct ip_addr *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, const struct ip_addr *src_addr_param, const struct ip_addr *dest_addr_param, int s_port, int d_port, int long id, str ck, str ik, str r_alg)
 {
     char l_msg_buf[MNL_SOCKET_BUFFER_SIZE];
     char l_auth_algo_buf[XFRM_TMPLS_BUF_SIZE];
@@ -187,7 +187,17 @@ int add_sa(struct mnl_socket* nl_sock, unsigned short proto, const struct ip_add
     // The point is to provide a continuous chunk of memory with the key in it
     l_auth_algo = (struct xfrm_algo *)l_auth_algo_buf;
 
-    strcpy(l_auth_algo->alg_name,"md5");
+    // Set the proper algorithm by r_alg str
+    if(strncasecmp(r_alg.s, "hmac-md5-96", r_alg.len) == 0) {
+        strcpy(l_auth_algo->alg_name,"md5");
+    }
+    else if(strncasecmp(r_alg.s, "hmac-sha1-96", r_alg.len) == 0) {
+        strcpy(l_auth_algo->alg_name,"sha1");
+    } else {
+        // set default algorithm to sha1
+        strcpy(l_auth_algo->alg_name,"sha1");
+    }
+
     l_auth_algo->alg_key_len = ik.len * 4;
     string_to_key(l_auth_algo->alg_key, ik);
 

+ 1 - 1
src/modules/ims_ipsec_pcscf/ipsec.h

@@ -42,7 +42,7 @@ 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, unsigned short proto, const struct ip_addr *src_addr_param, const struct ip_addr *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, const struct ip_addr *src_addr_param, const struct ip_addr *dest_addr_param, int s_port, int d_port, int long id, str ck, str ik, str r_alg);
 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, unsigned short proto, const struct ip_addr *src_addr_param, const struct ip_addr *dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir);

+ 84 - 44
src/modules/ims_usrloc_pcscf/udomain.c

@@ -507,61 +507,101 @@ int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact**
             LM_DBG("  contact host [%.*s:%d]\n", c->contact_host.len, c->contact_host.s, c->contact_port);
 		LM_DBG("contact received [%d:%.*s:%d]\n", c->received_proto, c->received_host.len, c->received_host.s, c->received_port);
 
-		if ((c->aorhash == aorhash) && 
-				(((c->contact_host.len == contact_info->via_host.len) 
-				&& (memcmp(contact_info->via_host.s, c->contact_host.s, c->contact_host.len) == 0) 
-				&& (c->contact_port == contact_info->via_port)
-				&& !(contact_info->searchflag & SEARCH_RECEIVED)) 
-		|| ((contact_info->searchflag & SEARCH_RECEIVED)
-				&& ((c->received_host.len == contact_info->received_host.len) && (memcmp(c->received_host.s, contact_info->received_host.s, contact_info->received_host.len) == 0))
-				&& ((c->received_port == contact_info->received_port) || (c->contact_port == contact_info->received_port))))) { /*volte comes from a different port.... typically uses 4060*/
-			LM_DBG("found contact with URI [%.*s]\n", c->aor.len, c->aor.s);
-			if (has_rinstance) {
-				LM_DBG("confirming rinstance is the same - search has [%.*s] and proposed found contact has [%.*s]",
-						rinstance.len, rinstance.s,
-						c->rinstance.len, c->rinstance.s);
-				if ((rinstance.len == c->rinstance.len) && memcmp(rinstance.s, c->rinstance.s, rinstance.len) != 0) {
-					LM_DBG("rinstance does not match - no match here...\n");
-					c = c->next;
-					continue;
+		if(c->aorhash == aorhash){
+			int check1_passed = 0;
+			int check2_passed = 0;
+			ip_addr_t c_ip_addr;
+			ip_addr_t ci_ip_addr;
+
+			// convert 'contact->contact host' ip string to ip_addr_t
+			if (str2ipxbuf(&c->contact_host, &c_ip_addr) < 0){
+				LM_ERR("Unable to convert c->contact_host [%.*s]\n", c->contact_host.len, c->contact_host.s);
+				return 1;
+			}
+
+			// convert 'contact info->via host' ip string to ip_addr_t
+			if(str2ipxbuf(&contact_info->via_host, &ci_ip_addr) < 0){
+				LM_ERR("Unable to convert contact_info->via_host [%.*s]\n", contact_info->via_host.len, contact_info->via_host.s);
+				return 1;
+			}
+
+			// compare 'contact->contact host' and 'contact info->via host'
+			if(ip_addr_cmp(&c_ip_addr, &ci_ip_addr) &&
+				(c->contact_port == contact_info->via_port) &&
+				!(contact_info->searchflag & SEARCH_RECEIVED))
+			{
+				check1_passed = 1;
+			}
+
+			if(contact_info->searchflag & SEARCH_RECEIVED){
+				// convert 'contact->received host' ip string to ip_addr_t
+				if (str2ipxbuf(&c->received_host, &c_ip_addr) < 0){
+					LM_ERR("Unable to convert c->received_host [%.*s]\n", c->received_host.len, c->received_host.s);
+					return 1;
+				}
+
+				// convert 'contact info->received host' ip string to ip_addr_t
+				if(str2ipxbuf(&contact_info->received_host, &ci_ip_addr) < 0){
+					LM_ERR("Unable to convert contact_info->received_host [%.*s]\n", contact_info->received_host.len, contact_info->received_host.s);
+					return 1;
+				}
+
+				// compare 'contact->received host' and 'contact info->received host'
+				if(ip_addr_cmp(&c_ip_addr, &ci_ip_addr) &&
+					((c->received_port == contact_info->received_port) ||
+					 (c->contact_port == contact_info->received_port))){ /*volte comes from a different port.... typically uses 4060*/
+					check2_passed = 1;
 				}
 			}
+
+			if(check1_passed || check2_passed){
+				LM_DBG("found contact with URI [%.*s]\n", c->aor.len, c->aor.s);
+				if (has_rinstance) {
+					LM_DBG("confirming rinstance is the same - search has [%.*s] and proposed found contact has [%.*s]",
+							rinstance.len, rinstance.s,
+							c->rinstance.len, c->rinstance.s);
+					if ((rinstance.len == c->rinstance.len) && memcmp(rinstance.s, c->rinstance.s, rinstance.len) != 0) {
+						LM_DBG("rinstance does not match - no match here...\n");
+						c = c->next;
+						continue;
+					}
+				}
 			
-			if ((contact_info->extra_search_criteria & SEARCH_SERVICE_ROUTES) && contact_info->num_service_routes > 0) {
-				LM_DBG("have %d service routes to search for\n", contact_info->num_service_routes);
-				if (contact_info->num_service_routes != c->num_service_routes) {
-					c = c->next;
-					LM_DBG("number of service routes do not match - failing\n");
-					continue;
-				} 
+				if ((contact_info->extra_search_criteria & SEARCH_SERVICE_ROUTES) && contact_info->num_service_routes > 0) {
+					LM_DBG("have %d service routes to search for\n", contact_info->num_service_routes);
+					if (contact_info->num_service_routes != c->num_service_routes) {
+						c = c->next;
+						LM_DBG("number of service routes do not match - failing\n");
+						continue;
+					} 
 				
-				serviceroutematch = 1;
-				for (j=0; j<contact_info->num_service_routes; j++) {
-					if (contact_info->service_routes[j].len != c->service_routes[j].len || memcmp(contact_info->service_routes[j].s, c->service_routes[j].s, c->service_routes[j].len) != 0) {
-						LM_DBG("service route at position %d does not match - looking for [%.*s] and contact has [%.*s]... continuing to next contact check\n", 
-							j,
-							contact_info->service_routes[j].len, contact_info->service_routes[j].s,
-							c->service_routes[j].len, c->service_routes[j].s);
-						serviceroutematch = 0;
-						break;
+					serviceroutematch = 1;
+					for (j=0; j<contact_info->num_service_routes; j++) {
+						if (contact_info->service_routes[j].len != c->service_routes[j].len || memcmp(contact_info->service_routes[j].s, c->service_routes[j].s, c->service_routes[j].len) != 0) {
+							LM_DBG("service route at position %d does not match - looking for [%.*s] and contact has [%.*s]... continuing to next contact check\n", 
+							    j,
+								contact_info->service_routes[j].len, contact_info->service_routes[j].s,
+								c->service_routes[j].len, c->service_routes[j].s);
+							serviceroutematch = 0;
+							break;
+						}
+					}
+					if (serviceroutematch == 0) {
+						c = c->next;
+						continue;
 					}
 				}
-				if (serviceroutematch == 0) {
+			
+				//finally check state being searched for
+				if ( (contact_info->reg_state != PCONTACT_ANY) && ((contact_info->reg_state & c->reg_state) == 0)) {
+					LM_DBG("can't find contact for requested reg state [%d] - (have [%d])\n", contact_info->reg_state, c->reg_state);
 					c = c->next;
 					continue;
 				}
+				*_c = c;
+				return 0;
 			}
-			
-			//finally check state being searched for
-			if ( (contact_info->reg_state != PCONTACT_ANY) && ((contact_info->reg_state & c->reg_state) == 0)) {
-				LM_DBG("can't find contact for requested reg state [%d] - (have [%d])\n", contact_info->reg_state, c->reg_state);
-				c = c->next;
-				continue;
-			}
-			*_c = c;
-			return 0;
 		}
-		
 		c = c->next;
 	}