ims_ipsec_pcscf: IPv6 support
authorAleksandar Yosifov <alexyosifov@gmail.com>
Thu, 23 May 2019 09:06:45 +0000 (12:06 +0300)
committerAleksandar Yosifov <alexyosifov@gmail.com>
Tue, 4 Jun 2019 06:37:38 +0000 (09:37 +0300)
- Set authentication algorithm for SA depending of
  parsed security-client info from REGISTER request msg.
  For now, the supported algorithms are md5 and sha1,
  the default algorithm is sha1.

- fill_contact() changes:
  No significant changes, but added a debug message
  and code is more readable.

- Added support for IPv6.
  A new parameter IPSEC_LISTEN_ADDR6 is added in pcscf.cfg
  file that describe IPv6 listen address.
  A new module parameter ipsec_listen_addr6 is added in
  kamailio.cfg to pass IPv6 listen address into the ipsec module.

- mode_init() changes:
  Add ipv4 and/or ipv6 listen interfaces depending of configured
  parameters in pcscf/kamailio config files.

- create_ipsec_tunnel() changes:
  Update temp security parameters for contact.
  Add 4 SAs and polisies (UE client->Proxy server, Proxy client->
  UE server, Proxy server->UE client and UE server->Proxy client).
  Server->client SAs are used for TCP connections.

- destroy_ipsec_tunnel() changes:
  Remove all SAs and policies.

- ipsec_forward() changes:
  Refactored to use both UDP and TCP protocols. Selects the protocol
  type, sourse and destination ports based on message type.

- Removed unused method convert_ip_address(). Replaced by core methods
  str2ipbuf() and str2ip6buf().

- changes in README
  README regenerated via ims_ipsec_pscscf_admin.xml.
  Added a new parameter for listen IPv6 address.

src/modules/ims_ipsec_pcscf/README
src/modules/ims_ipsec_pcscf/cmd.c
src/modules/ims_ipsec_pcscf/doc/ims_ipsec_pcscf_admin.xml
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 0d354ee..2009df7 100644 (file)
@@ -44,10 +44,11 @@ Tsvetomir Dimitrov
         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.2. ipsec_listen_addr6 (string)
+              3.3. ipsec_client_port (int)
+              3.4. ipsec_server_port (int)
+              3.5. ipsec_spi_id_start (int)
+              3.6. ipsec_spi_id_range (int)
 
         4. Functions
 
@@ -58,13 +59,14 @@ Tsvetomir Dimitrov
    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.2. ipsec_listen_addr6 parameter usage
+   1.3. ipsec_client_port parameter usage
+   1.4. ipsec_server_port parameter usage
+   1.5. ipsec_spi_id_start parameter usage
+   1.6. ipsec_spi_id_range parameter usage
+   1.7. ipsec_create
    1.8. ipsec_forward
+   1.9. ipsec_forward
 
 Chapter 1. Admin Guide
 
@@ -79,10 +81,11 @@ Chapter 1. Admin Guide
    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.2. ipsec_listen_addr6 (string)
+        3.3. ipsec_client_port (int)
+        3.4. ipsec_server_port (int)
+        3.5. ipsec_spi_id_start (int)
+        3.6. ipsec_spi_id_range (int)
 
    4. Functions
 
@@ -114,46 +117,61 @@ Chapter 1. Admin Guide
 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.2. ipsec_listen_addr6 (string)
+   3.3. ipsec_client_port (int)
+   3.4. ipsec_server_port (int)
+   3.5. ipsec_spi_id_start (int)
+   3.6. 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"
+   Default value is empty string (null) - IPv4 listen interface will not
+   be added
 
    Example 1.1. ipsec_listen_addr parameter usage
 ...
-modparam("ims_ipsec_pcscf", "ipsec_listen_addr", "127.0.0.1")
+modparam("ims_ipsec_pcscf", "ipsec_listen_addr", "")
 ...
 
-3.2. ipsec_client_port (int)
+3.2. ipsec_listen_addr6 (string)
+
+   IPv6 address which the Proxy-CSCF will use for incoming/outgoing SIP
+   traffic over IPSec.
+
+   Default value is empty string (null) - IPv6 listen interface will not
+   be added
+
+   Example 1.2. ipsec_listen_addr6 parameter usage
+...
+modparam("ims_ipsec_pcscf", "ipsec_listen_addr6", "")
+...
+
+3.3. 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
+   Example 1.3. ipsec_client_port parameter usage
 ...
 modparam("ims_ipsec_pcscf", "ipsec_client_port", 5062)
 ...
 
-3.3. ipsec_server_port (int)
+3.4. 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
+   Example 1.4. ipsec_server_port parameter usage
 ...
 modparam("ims_ipsec_pcscf", "ipsec_server_port", 5063)
 ...
 
-3.4. ipsec_spi_id_start (int)
+3.5. 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
@@ -162,12 +180,12 @@ modparam("ims_ipsec_pcscf", "ipsec_server_port", 5063)
 
    Default value is 100.
 
-   Example 1.4. ipsec_spi_id_start parameter usage
+   Example 1.5. ipsec_spi_id_start parameter usage
 ...
 modparam("ims_ipsec_pcscf", "ipsec_spi_id_start", 100)
 ...
 
-3.5. ipsec_spi_id_range (int)
+3.6. 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
@@ -175,7 +193,7 @@ modparam("ims_ipsec_pcscf", "ipsec_spi_id_start", 100)
 
    Default value is 1000.
 
-   Example 1.5. ipsec_spi_id_range parameter usage
+   Example 1.6. ipsec_spi_id_range parameter usage
 ...
 modparam("ims_ipsec_pcscf", "ipsec_spi_id_range", 1000)
 ...
@@ -197,7 +215,7 @@ modparam("ims_ipsec_pcscf", "ipsec_spi_id_range", 1000)
      * 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
+   Example 1.7. ipsec_create
 ...
 ipsec_create("location");
 ...
@@ -211,7 +229,7 @@ ipsec_create("location");
      * 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
+   Example 1.8. ipsec_forward
 ...
 ipsec_forward("location");
 ...
@@ -224,7 +242,7 @@ ipsec_forward("location");
      * 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
+   Example 1.9. ipsec_forward
 ...
 ipsec_destroy("location");
 ...
index 317948a..576bf56 100644 (file)
@@ -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
 
index 5d15d1d..a73bf0b 100644 (file)
       <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>
index c177c88..4b1d5ec 100644 (file)
@@ -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");
index 05c8dd8..da756e7 100644 (file)
@@ -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);
 
index 06e98c5..d334bba 100644 (file)
@@ -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);