diff --git a/src/modules/ims_ipsec_pcscf/README b/src/modules/ims_ipsec_pcscf/README deleted file mode 100644 index 0d354eebfd9..00000000000 --- a/src/modules/ims_ipsec_pcscf/README +++ /dev/null @@ -1,230 +0,0 @@ -The IMS IPSec-Registrar Module - -Dragos Vingarzan - - FhG Fokus - - -Jason Penton - - Smile Communications - - -Richard Good - - Smile Communications - - -Carsten Bock - - ng-voice GmbH - - -Tsvetomir Dimitrov - - - - 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"); -... diff --git a/src/modules/ims_ipsec_pcscf/cmd.c b/src/modules/ims_ipsec_pcscf/cmd.c index 317948adef5..576bf56ded2 100644 --- a/src/modules/ims_ipsec_pcscf/cmd.c +++ b/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 diff --git a/src/modules/ims_ipsec_pcscf/doc/ims_ipsec_pcscf_admin.xml b/src/modules/ims_ipsec_pcscf/doc/ims_ipsec_pcscf_admin.xml index 5d15d1d64ee..a73bf0ba1ef 100644 --- a/src/modules/ims_ipsec_pcscf/doc/ims_ipsec_pcscf_admin.xml +++ b/src/modules/ims_ipsec_pcscf/doc/ims_ipsec_pcscf_admin.xml @@ -49,14 +49,31 @@ <varname>ipsec_listen_addr</varname> (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 <varname>ipsec_listen_addr</varname> parameter usage ... -modparam("ims_ipsec_pcscf", "ipsec_listen_addr", "127.0.0.1") +modparam("ims_ipsec_pcscf", "ipsec_listen_addr", "") +... + + + + +
+ <varname>ipsec_listen_addr6</varname> (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 + + + <varname>ipsec_listen_addr6</varname> parameter usage + + +... +modparam("ims_ipsec_pcscf", "ipsec_listen_addr6", "") ... diff --git a/src/modules/ims_ipsec_pcscf/ims_ipsec_pcscf_mod.c b/src/modules/ims_ipsec_pcscf/ims_ipsec_pcscf_mod.c index c177c88c92e..4b1d5ec4462 100644 --- a/src/modules/ims_ipsec_pcscf/ims_ipsec_pcscf_mod.c +++ b/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"); diff --git a/src/modules/ims_ipsec_pcscf/ipsec.c b/src/modules/ims_ipsec_pcscf/ipsec.c index 05c8dd88d52..da756e7faff 100644 --- a/src/modules/ims_ipsec_pcscf/ipsec.c +++ b/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); diff --git a/src/modules/ims_ipsec_pcscf/ipsec.h b/src/modules/ims_ipsec_pcscf/ipsec.h index 06e98c50df8..d334bbad789 100644 --- a/src/modules/ims_ipsec_pcscf/ipsec.h +++ b/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); diff --git a/src/modules/ims_usrloc_pcscf/udomain.c b/src/modules/ims_usrloc_pcscf/udomain.c index ae4aac4c42d..0a1b8280c2a 100644 --- a/src/modules/ims_usrloc_pcscf/udomain.c +++ b/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; jnum_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; jnum_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; }