Browse code

ims_ipsec_pcscf: new config param for ipsec

- 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.

Aleksandar Yosifov authored on 04/12/2019 09:12:21 • Henning Westerholt committed on 13/01/2020 20:14:10
Showing 3 changed files
... ...
@@ -62,8 +62,7 @@
62 62
 
63 63
 extern str ipsec_listen_addr;
64 64
 extern str ipsec_listen_addr6;
65
-extern int ipsec_server_port;
66
-extern int ipsec_client_port;
65
+extern int ipsec_reuse_server_port;
67 66
 
68 67
 extern int spi_id_start;
69 68
 
... ...
@@ -141,6 +140,7 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
141 140
     contact_body_t* cb = NULL;
142 141
     struct via_body* vb = NULL;
143 142
     struct sip_msg* req = NULL;
143
+	char* srcip = NULL;
144 144
 
145 145
     if(!ci) {
146 146
         LM_ERR("called with null ptr\n");
... ...
@@ -150,14 +150,17 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
150 150
     memset(ci, 0, sizeof(struct pcontact_info));
151 151
 
152 152
     if(m->first_line.type == SIP_REQUEST) {
153
-        struct sip_uri uri;
154
-        memset(&uri, 0, sizeof(struct sip_uri));
153
+		char* alias_start;
154
+		struct sip_uri uri;
155
+		memset(&uri, 0, sizeof(struct sip_uri));
155 156
 
156 157
         if(parse_uri(m->first_line.u.request.uri.s, m->first_line.u.request.uri.len, &uri)) {
157 158
             LM_ERR("Can't parse the request URI from first line\n");
158 159
             return -1;
159 160
         }
160 161
 
162
+		req = m;
163
+
161 164
         // populate host,port, aor in CI
162 165
         ci->via_host = uri.host;
163 166
         ci->via_port = uri.port_no ? uri.port_no : 5060;
... ...
@@ -165,8 +168,76 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
165 168
         ci->aor = m->first_line.u.request.uri;
166 169
         ci->searchflag = SEARCH_NORMAL;
167 170
 
168
-        req = m;
169
-    }
171
+		if(ci->via_host.s == NULL || ci->via_host.len == 0){
172
+			// no host included in RURI
173
+			vb = cscf_get_ue_via(m);
174
+			if (!vb) {
175
+				LM_ERR("Reply No via body headers\n");
176
+				return -1;
177
+			}
178
+
179
+			// populate CI with bare minimum
180
+			ci->via_host = vb->host;
181
+			ci->via_port = vb->port;
182
+			ci->via_prot = vb->proto;
183
+		}
184
+
185
+		if (uri.params.len > 6 && (alias_start = _strnistr(uri.params.s, "alias=", uri.params.len)) != NULL) {
186
+			char *p, *port_s, *proto_s;
187
+			char portbuf[5];
188
+			str alias_s;
189
+
190
+			LM_DBG("contact has an alias [%.*s] - we can use that as the received\n", uri.params.len, uri.params.s);
191
+
192
+			alias_s.len = uri.params.len - (alias_start - uri.params.s) - 6;
193
+			alias_s.s = alias_start + 6;
194
+
195
+			p = _strnistr(alias_s.s, "~", alias_s.len);
196
+			if (p!=NULL) {
197
+				ci->received_host.len = p - alias_s.s;
198
+
199
+				if(ci->received_host.len > IP6_MAX_STR_SIZE + 2){
200
+					LM_ERR("Invalid length for source IP address\n");
201
+					return -1;
202
+				}
203
+
204
+				if((srcip = pkg_malloc(50)) == NULL) {
205
+					LM_ERR("Error allocating memory for source IP address\n");
206
+					return -1;
207
+				}
208
+
209
+				memcpy(srcip, alias_s.s, ci->received_host.len);
210
+				ci->received_host.s = srcip;
211
+
212
+				port_s = p+1;
213
+				p = _strnistr(port_s, "~", alias_s.len - ci->received_host.len);
214
+				if (p!=NULL) {
215
+					memset(portbuf, 0, 5);
216
+					memcpy(portbuf, port_s, (p-port_s));
217
+					ci->received_port = atoi(portbuf);
218
+
219
+					proto_s = p + 1;
220
+					memset(portbuf, 0, 5);
221
+					memcpy(portbuf, proto_s, 1);
222
+					ci->received_proto = atoi(portbuf);
223
+
224
+					ci->searchflag = SEARCH_RECEIVED;
225
+				}
226
+
227
+				LM_DBG("parsed alias [%d://%.*s:%d]\n", ci->received_proto, ci->received_host.len, ci->received_host.s, ci->received_port);
228
+			}
229
+		}else{
230
+			if((srcip = pkg_malloc(50)) == NULL) {
231
+				LM_ERR("Error allocating memory for source IP address\n");
232
+				return -1;
233
+			}
234
+
235
+			ci->received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, 50);
236
+			ci->received_host.s = srcip;
237
+			ci->received_port = req->rcv.src_port;
238
+			ci->received_proto = req->rcv.proto;
239
+		}
240
+	}
170 241
     else if(m->first_line.type == SIP_REPLY) {
171 242
         struct cell *t = tmb.t_gett();
172 243
         if (!t || t == (void*) -1) {
... ...
@@ -194,24 +265,22 @@ static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
194 265
         ci->via_prot = vb->proto;
195 266
         ci->aor = cb->contacts->uri;
196 267
         ci->searchflag = SEARCH_RECEIVED;
268
+
269
+		if((srcip = pkg_malloc(50)) == NULL) {
270
+			LM_ERR("Error allocating memory for source IP address\n");
271
+			return -1;
272
+		}
273
+
274
+		ci->received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, 50);
275
+		ci->received_host.s = srcip;
276
+		ci->received_port = req->rcv.src_port;
277
+		ci->received_proto = req->rcv.proto;
197 278
     }
198 279
     else {
199 280
         LM_ERR("Unknown first line type: %d\n", m->first_line.type);
200 281
         return -1;
201 282
     }
202 283
 
203
-
204
-    char* srcip = NULL;
205
-    if((srcip = pkg_malloc(50)) == NULL) {
206
-        LM_ERR("Error allocating memory for source IP address\n");
207
-        return -1;
208
-    }
209
-
210
-    ci->received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, 50);
211
-    ci->received_host.s = srcip;
212
-    ci->received_port = req->rcv.src_port;
213
-    ci->received_proto = req->rcv.proto;
214
-
215 284
     LM_DBG("SIP %s fill contact with AOR [%.*s], VIA [%d://%.*s:%d], received_host [%d://%.*s:%d]\n",
216 285
             m->first_line.type == SIP_REQUEST ? "REQUEST" : "REPLY",
217 286
             ci->aor.len, ci->aor.s, ci->via_prot, ci->via_host.len, ci->via_host.s, ci->via_port,
... ...
@@ -249,7 +318,7 @@ static int get_ck_ik(const struct sip_msg* m, str* ck, str* ik)
249 318
     return 0;
250 319
 }
251 320
 
252
-static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m)
321
+static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m, ipsec_t* s_old)
253 322
 {
254 323
     // Get CK and IK
255 324
     str ck, ik;
... ...
@@ -310,21 +379,26 @@ static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m)
310 379
         return -1;
311 380
     }
312 381
 
313
-    if((s->port_ps = acquire_sport()) == 0){
314
-        LM_ERR("No free server port for IPSEC tunnel creation\n");
315
-		shm_free(s->ck.s);
316
-		s->ck.s = NULL; s->ck.len = 0;
317
-		shm_free(s->ik.s);
318
-		s->ik.s = NULL; s->ik.len = 0;
382
+	// use the same P-CSCF server port if it is present
383
+	if(s_old){
384
+		s->port_ps = s_old->port_ps;
385
+	}else{
386
+		if((s->port_ps = acquire_sport()) == 0){
387
+			LM_ERR("No free server port for IPSEC tunnel creation\n");
388
+			shm_free(s->ck.s);
389
+			s->ck.s = NULL; s->ck.len = 0;
390
+			shm_free(s->ik.s);
391
+			s->ik.s = NULL; s->ik.len = 0;
319 392
 
320
-		release_cport(s->port_pc);
393
+			release_cport(s->port_pc);
321 394
 
322
-		release_spi(s->spi_pc);
323
-		release_spi(s->spi_ps);
324
-        return -1;
325
-    }
395
+			release_spi(s->spi_pc);
396
+			release_spi(s->spi_ps);
397
+			return -1;
398
+		}
399
+	}
326 400
 
327
-    return 0;
401
+	return 0;
328 402
 }
329 403
 
330 404
 static int create_ipsec_tunnel(const struct ip_addr *remote_addr, ipsec_t* s)
... ...
@@ -494,7 +568,7 @@ int add_supported_secagree_header(struct sip_msg* m)
494 568
     if(cscf_add_header(m, supported, HDR_SUPPORTED_T) != 1) {
495 569
 		pkg_free(supported->s);
496 570
 		pkg_free(supported);
497
-        LM_ERR("Error adding security header to reply!\n");
571
+        LM_ERR("Error adding supported header to reply!\n");
498 572
         return -1;
499 573
     }
500 574
     pkg_free(supported);
... ...
@@ -502,6 +576,38 @@ int add_supported_secagree_header(struct sip_msg* m)
502 576
     return 0;
503 577
 }
504 578
 
579
+int add_require_secagree_header(struct sip_msg* m)
580
+{
581
+	// Add require sec-agree header in the reply
582
+	const char* require_sec_agree = "Require: sec-agree\r\n";
583
+	const int require_sec_agree_len = 20;
584
+
585
+	str* require = NULL;
586
+	if((require = pkg_malloc(sizeof(str))) == NULL) {
587
+		LM_ERR("Error allocating pkg memory for require header\n");
588
+		return -1;
589
+	}
590
+
591
+	if((require->s = pkg_malloc(require_sec_agree_len)) == NULL) {
592
+		LM_ERR("Error allcationg pkg memory for require header str\n");
593
+		pkg_free(require);
594
+		return -1;
595
+	}
596
+
597
+	memcpy(require->s, require_sec_agree, require_sec_agree_len);
598
+	require->len = require_sec_agree_len;
599
+
600
+	if(cscf_add_header(m, require, HDR_REQUIRE_T) != 1) {
601
+		pkg_free(require->s);
602
+		pkg_free(require);
603
+		LM_ERR("Error adding require header to reply!\n");
604
+		return -1;
605
+	}
606
+
607
+	pkg_free(require);
608
+	return 0;
609
+}
610
+
505 611
 int add_security_server_header(struct sip_msg* m, ipsec_t* s)
506 612
 {
507 613
     // allocate memory for the header itself
... ...
@@ -590,7 +696,8 @@ int ipsec_create(struct sip_msg* m, udomain_t* d)
590 696
 
591 697
         ipsec_t* s = pcontact->security_temp->data.ipsec;
592 698
 
593
-        if(update_contact_ipsec_params(s, m) != 0) {
699
+		// for initial Registration use a new P-CSCF server port
700
+        if(update_contact_ipsec_params(s, m, NULL) != 0) {
594 701
             goto cleanup;
595 702
         }
596 703
 
... ...
@@ -633,7 +740,8 @@ int ipsec_create(struct sip_msg* m, udomain_t* d)
633 740
             goto cleanup;
634 741
         }
635 742
 
636
-        if(update_contact_ipsec_params(req_sec_params->data.ipsec, m) != 0) {
743
+		// for Re-Registration use the same P-CSCF server port if 'ipsec reuse server port' is enabled
744
+        if(update_contact_ipsec_params(req_sec_params->data.ipsec, m, ipsec_reuse_server_port ? pcontact->security_temp->data.ipsec : NULL) != 0) {
637 745
             goto cleanup;
638 746
         }
639 747
 
... ...
@@ -803,13 +911,15 @@ int ipsec_forward(struct sip_msg* m, udomain_t* d, int _cflags)
803 911
 
804 912
     ret = IPSEC_CMD_SUCCESS; // all good, return SUCCESS
805 913
 
806
-    if(add_supported_secagree_header(m) != 0) {
807
-        goto cleanup;
808
-    }
809
-
810
-    if(add_security_server_header(m, s) != 0) {
811
-        goto cleanup;
812
-    }
914
+	if( m->first_line.type == SIP_REPLY && m->first_line.u.reply.statuscode == 200 &&
915
+		req->first_line.u.request.method_value == METHOD_REGISTER){
916
+		if(add_supported_secagree_header(m) != 0){
917
+			goto cleanup;
918
+		}
919
+		if(add_require_secagree_header(m) != 0){
920
+			goto cleanup;
921
+		}
922
+	}
813 923
 
814 924
     ret = IPSEC_CMD_SUCCESS;    // all good, set ret to SUCCESS, and exit
815 925
 
... ...
@@ -135,6 +135,28 @@ modparam("ims_ipsec_pcscf", "ipsec_max_connections", 10)
135 135
       </example>
136 136
     </section>
137 137
 
138
+    <section>
139
+      <title><varname>ipsec_reuse_server_port</varname> (int)</title>
140
+
141
+      <para>Reuse (1) or not (0) the P-CSCF Server port for Re-registration for one UA.
142
+      When set to 0 - During Re-registration P-CSCF will distribute new P-CSCF client and
143
+      P-CSCF server ports.
144
+      When set to 1 - During Re-registration P-CSCF will reuse the old P-CSCF server port and
145
+      will distribute a new P-CSCF client port.</para>
146
+
147
+      <para><emphasis>Default value is 1.</emphasis></para>
148
+
149
+      <example>
150
+        <title><varname>ipsec_reuse_server_port</varname> parameter usage</title>
151
+
152
+        <programlisting format="linespecific">
153
+...
154
+modparam("ims_ipsec_pcscf", "ipsec_reuse_server_port", 1)
155
+...
156
+        </programlisting>
157
+      </example>
158
+    </section>
159
+
138 160
     <section>
139 161
       <title><varname>ipsec_spi_id_start</varname> (int)</title>
140 162
 
... ...
@@ -41,6 +41,7 @@ str ipsec_listen_addr = STR_NULL;
41 41
 str ipsec_listen_addr6 = STR_NULL;
42 42
 int ipsec_client_port =  5062;
43 43
 int ipsec_server_port =  5063;
44
+int ipsec_reuse_server_port = 1;
44 45
 int ipsec_max_connections = 2;
45 46
 int spi_id_start = 100;
46 47
 int spi_id_range = 1000;
... ...
@@ -83,6 +84,7 @@ static param_export_t params[] = {
83 84
 	{"ipsec_listen_addr6",  	PARAM_STR, &ipsec_listen_addr6		},
84 85
 	{"ipsec_client_port",		INT_PARAM, &ipsec_client_port		},
85 86
 	{"ipsec_server_port",		INT_PARAM, &ipsec_server_port		},
87
+	{"ipsec_reuse_server_port",	INT_PARAM, &ipsec_reuse_server_port	},
86 88
 	{"ipsec_max_connections",	INT_PARAM, &ipsec_max_connections	},
87 89
 	{"ipsec_spi_id_start",		INT_PARAM, &spi_id_start			},
88 90
 	{"ipsec_spi_id_range",		INT_PARAM, &spi_id_range			},