Skip to content

Commit

Permalink
ims_ipsec_pcscf: new config param for ipsec
Browse files Browse the repository at this point in the history
- added a new config param - ipsec_reuse_server_port - reuse or not
  PCSCF server port for UA Re-registration.
- added description for the new parameter in ims_ipsec_pcscf_admin.xml.
  parameter ipsec_reuse_server_port.
- in ipsec_forward() add supported and require secagree headers only
  for Register reply with code 200.
- in fill_contact() for Request messages set received host, port and
  proto from request uri if alias is presented.
  • Loading branch information
alexyosifov authored and henningw committed Jan 13, 2020
1 parent 674852e commit 1fb8c88
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 41 deletions.
192 changes: 151 additions & 41 deletions src/modules/ims_ipsec_pcscf/cmd.c
Expand Up @@ -62,8 +62,7 @@

extern str ipsec_listen_addr;
extern str ipsec_listen_addr6;
extern int ipsec_server_port;
extern int ipsec_client_port;
extern int ipsec_reuse_server_port;

extern int spi_id_start;

Expand Down Expand Up @@ -141,6 +140,7 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
contact_body_t* cb = NULL;
struct via_body* vb = NULL;
struct sip_msg* req = NULL;
char* srcip = NULL;

if(!ci) {
LM_ERR("called with null ptr\n");
Expand All @@ -150,23 +150,94 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
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));
char* alias_start;
struct sip_uri uri;
memset(&uri, 0, sizeof(struct sip_uri));

if(parse_uri(m->first_line.u.request.uri.s, m->first_line.u.request.uri.len, &uri)) {
LM_ERR("Can't parse the request URI from first line\n");
return -1;
}

req = 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 = 0;
ci->aor = m->first_line.u.request.uri;
ci->searchflag = SEARCH_NORMAL;

req = m;
}
if(ci->via_host.s == NULL || ci->via_host.len == 0){
// no host included in RURI
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 = vb->port;
ci->via_prot = vb->proto;
}

if (uri.params.len > 6 && (alias_start = _strnistr(uri.params.s, "alias=", uri.params.len)) != NULL) {
char *p, *port_s, *proto_s;
char portbuf[5];
str alias_s;

LM_DBG("contact has an alias [%.*s] - we can use that as the received\n", uri.params.len, uri.params.s);

alias_s.len = uri.params.len - (alias_start - uri.params.s) - 6;
alias_s.s = alias_start + 6;

p = _strnistr(alias_s.s, "~", alias_s.len);
if (p!=NULL) {
ci->received_host.len = p - alias_s.s;

if(ci->received_host.len > IP6_MAX_STR_SIZE + 2){
LM_ERR("Invalid length for source IP address\n");
return -1;
}

if((srcip = pkg_malloc(50)) == NULL) {
LM_ERR("Error allocating memory for source IP address\n");
return -1;
}

memcpy(srcip, alias_s.s, ci->received_host.len);
ci->received_host.s = srcip;

port_s = p+1;
p = _strnistr(port_s, "~", alias_s.len - ci->received_host.len);
if (p!=NULL) {
memset(portbuf, 0, 5);
memcpy(portbuf, port_s, (p-port_s));
ci->received_port = atoi(portbuf);

proto_s = p + 1;
memset(portbuf, 0, 5);
memcpy(portbuf, proto_s, 1);
ci->received_proto = atoi(portbuf);

ci->searchflag = SEARCH_RECEIVED;
}

LM_DBG("parsed alias [%d://%.*s:%d]\n", ci->received_proto, ci->received_host.len, ci->received_host.s, ci->received_port);
}
}else{
if((srcip = pkg_malloc(50)) == NULL) {
LM_ERR("Error allocating memory for source IP address\n");
return -1;
}

ci->received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, 50);
ci->received_host.s = srcip;
ci->received_port = req->rcv.src_port;
ci->received_proto = req->rcv.proto;
}
}
else if(m->first_line.type == SIP_REPLY) {
struct cell *t = tmb.t_gett();
if (!t || t == (void*) -1) {
Expand Down Expand Up @@ -194,24 +265,22 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
ci->via_prot = vb->proto;
ci->aor = cb->contacts->uri;
ci->searchflag = SEARCH_RECEIVED;

if((srcip = pkg_malloc(50)) == NULL) {
LM_ERR("Error allocating memory for source IP address\n");
return -1;
}

ci->received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, 50);
ci->received_host.s = srcip;
ci->received_port = req->rcv.src_port;
ci->received_proto = req->rcv.proto;
}
else {
LM_ERR("Unknown first line type: %d\n", m->first_line.type);
return -1;
}


char* srcip = NULL;
if((srcip = pkg_malloc(50)) == NULL) {
LM_ERR("Error allocating memory for source IP address\n");
return -1;
}

ci->received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, 50);
ci->received_host.s = srcip;
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,
Expand Down Expand Up @@ -249,7 +318,7 @@ static int get_ck_ik(const struct sip_msg* m, str* ck, str* ik)
return 0;
}

static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m)
static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m, ipsec_t* s_old)
{
// Get CK and IK
str ck, ik;
Expand Down Expand Up @@ -310,21 +379,26 @@ static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m)
return -1;
}

if((s->port_ps = acquire_sport()) == 0){
LM_ERR("No free server port for IPSEC tunnel creation\n");
shm_free(s->ck.s);
s->ck.s = NULL; s->ck.len = 0;
shm_free(s->ik.s);
s->ik.s = NULL; s->ik.len = 0;
// use the same P-CSCF server port if it is present
if(s_old){
s->port_ps = s_old->port_ps;
}else{
if((s->port_ps = acquire_sport()) == 0){
LM_ERR("No free server port for IPSEC tunnel creation\n");
shm_free(s->ck.s);
s->ck.s = NULL; s->ck.len = 0;
shm_free(s->ik.s);
s->ik.s = NULL; s->ik.len = 0;

release_cport(s->port_pc);
release_cport(s->port_pc);

release_spi(s->spi_pc);
release_spi(s->spi_ps);
return -1;
}
release_spi(s->spi_pc);
release_spi(s->spi_ps);
return -1;
}
}

return 0;
return 0;
}

static int create_ipsec_tunnel(const struct ip_addr *remote_addr, ipsec_t* s)
Expand Down Expand Up @@ -494,14 +568,46 @@ int add_supported_secagree_header(struct sip_msg* m)
if(cscf_add_header(m, supported, HDR_SUPPORTED_T) != 1) {
pkg_free(supported->s);
pkg_free(supported);
LM_ERR("Error adding security header to reply!\n");
LM_ERR("Error adding supported header to reply!\n");
return -1;
}
pkg_free(supported);

return 0;
}

int add_require_secagree_header(struct sip_msg* m)
{
// Add require sec-agree header in the reply
const char* require_sec_agree = "Require: sec-agree\r\n";
const int require_sec_agree_len = 20;

str* require = NULL;
if((require = pkg_malloc(sizeof(str))) == NULL) {
LM_ERR("Error allocating pkg memory for require header\n");
return -1;
}

if((require->s = pkg_malloc(require_sec_agree_len)) == NULL) {
LM_ERR("Error allcationg pkg memory for require header str\n");
pkg_free(require);
return -1;
}

memcpy(require->s, require_sec_agree, require_sec_agree_len);
require->len = require_sec_agree_len;

if(cscf_add_header(m, require, HDR_REQUIRE_T) != 1) {
pkg_free(require->s);
pkg_free(require);
LM_ERR("Error adding require header to reply!\n");
return -1;
}

pkg_free(require);
return 0;
}

int add_security_server_header(struct sip_msg* m, ipsec_t* s)
{
// allocate memory for the header itself
Expand Down Expand Up @@ -590,7 +696,8 @@ int ipsec_create(struct sip_msg* m, udomain_t* d)

ipsec_t* s = pcontact->security_temp->data.ipsec;

if(update_contact_ipsec_params(s, m) != 0) {
// for initial Registration use a new P-CSCF server port
if(update_contact_ipsec_params(s, m, NULL) != 0) {
goto cleanup;
}

Expand Down Expand Up @@ -633,7 +740,8 @@ int ipsec_create(struct sip_msg* m, udomain_t* d)
goto cleanup;
}

if(update_contact_ipsec_params(req_sec_params->data.ipsec, m) != 0) {
// for Re-Registration use the same P-CSCF server port if 'ipsec reuse server port' is enabled
if(update_contact_ipsec_params(req_sec_params->data.ipsec, m, ipsec_reuse_server_port ? pcontact->security_temp->data.ipsec : NULL) != 0) {
goto cleanup;
}

Expand Down Expand Up @@ -803,13 +911,15 @@ int ipsec_forward(struct sip_msg* m, udomain_t* d, int _cflags)

ret = IPSEC_CMD_SUCCESS; // all good, return SUCCESS

if(add_supported_secagree_header(m) != 0) {
goto cleanup;
}

if(add_security_server_header(m, s) != 0) {
goto cleanup;
}
if( m->first_line.type == SIP_REPLY && m->first_line.u.reply.statuscode == 200 &&
req->first_line.u.request.method_value == METHOD_REGISTER){
if(add_supported_secagree_header(m) != 0){
goto cleanup;
}
if(add_require_secagree_header(m) != 0){
goto cleanup;
}
}

ret = IPSEC_CMD_SUCCESS; // all good, set ret to SUCCESS, and exit

Expand Down
22 changes: 22 additions & 0 deletions src/modules/ims_ipsec_pcscf/doc/ims_ipsec_pcscf_admin.xml
Expand Up @@ -135,6 +135,28 @@ modparam("ims_ipsec_pcscf", "ipsec_max_connections", 10)
</example>
</section>

<section>
<title><varname>ipsec_reuse_server_port</varname> (int)</title>

<para>Reuse (1) or not (0) the P-CSCF Server port for Re-registration for one UA.
When set to 0 - During Re-registration P-CSCF will distribute new P-CSCF client and
P-CSCF server ports.
When set to 1 - During Re-registration P-CSCF will reuse the old P-CSCF server port and
will distribute a new P-CSCF client port.</para>

<para><emphasis>Default value is 1.</emphasis></para>

<example>
<title><varname>ipsec_reuse_server_port</varname> parameter usage</title>

<programlisting format="linespecific">
...
modparam("ims_ipsec_pcscf", "ipsec_reuse_server_port", 1)
...
</programlisting>
</example>
</section>

<section>
<title><varname>ipsec_spi_id_start</varname> (int)</title>

Expand Down
2 changes: 2 additions & 0 deletions src/modules/ims_ipsec_pcscf/ims_ipsec_pcscf_mod.c
Expand Up @@ -41,6 +41,7 @@ str ipsec_listen_addr = STR_NULL;
str ipsec_listen_addr6 = STR_NULL;
int ipsec_client_port = 5062;
int ipsec_server_port = 5063;
int ipsec_reuse_server_port = 1;
int ipsec_max_connections = 2;
int spi_id_start = 100;
int spi_id_range = 1000;
Expand Down Expand Up @@ -83,6 +84,7 @@ static param_export_t params[] = {
{"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_reuse_server_port", INT_PARAM, &ipsec_reuse_server_port },
{"ipsec_max_connections", INT_PARAM, &ipsec_max_connections },
{"ipsec_spi_id_start", INT_PARAM, &spi_id_start },
{"ipsec_spi_id_range", INT_PARAM, &spi_id_range },
Expand Down

0 comments on commit 1fb8c88

Please sign in to comment.