1 /*
2 * $Id$
3 *
4 * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
5 * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
6 * Copyright (C) 2019 Aleksandar Yosifov
7 *
8 * The initial version of this code was written by Dragos Vingarzan
9 * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
10 * Fruanhofer Institute. It was and still is maintained in a separate
11 * branch of the original SER. We are therefore migrating it to
12 * Kamailio/SR and look forward to maintaining it from here on out.
13 * 2011/2012 Smile Communications, Pty. Ltd.
14 * ported/maintained/improved by
15 * Jason Penton (jason(dot)penton(at)smilecoms.com and
16 * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
17 * effort to add full IMS support to Kamailio/SR using a new and
18 * improved architecture
19 *
20 * NB: Alot of this code was originally part of OpenIMSCore,
21 * FhG Fokus.
22 * Copyright (C) 2004-2006 FhG Fokus
23 * Thanks for great work! This is an effort to
24 * break apart the various CSCF functions into logically separate
25 * components. We hope this will drive wider use. We also feel
26 * that in this way the architecture is more complete and thereby easier
27 * to manage in the Kamailio/SR environment
28 *
29 * This file is part of Kamailio, a free SIP server.
30 *
31 * Kamailio is free software; you can redistribute it and/or modify
32 * it under the terms of the GNU General Public License as published by
33 * the Free Software Foundation; either version 2 of the License, or
34 * (at your option) any later version
35 *
36 * Kamailio is distributed in the hope that it will be useful,
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 * GNU General Public License for more details.
40 *
41 * You should have received a copy of the GNU General Public License
42 * along with this program; if not, write to the Free Software
43 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
44 *
45 */
46
47 #include "../../core/parser/contact/contact.h"
48 #include "save.h"
49 #include "ims_registrar_pcscf_mod.h"
50 #include "ul_callback.h"
51 #include "subscribe.h"
52
53 #include "../pua/pua_bind.h"
54 #include "../ims_ipsec_pcscf/cmd.h"
55 #include "sec_agree.h"
56
57 extern struct tm_binds tmb;
58 extern usrloc_api_t ul;
59 extern time_t time_now;
60 extern unsigned int pending_reg_expires;
61 extern int subscribe_to_reginfo;
62 extern int subscription_expires;
63 extern pua_api_t pua;
64 extern ipsec_pcscf_api_t ipsec_pcscf;
65
get_request_from_reply(struct sip_msg * reply)66 struct sip_msg* get_request_from_reply(struct sip_msg* reply)
67 {
68 struct cell *t;
69 t = tmb.t_gett();
70 if (!t || t == (void*) -1) {
71 LM_ERR("Reply without transaction\n");
72 return 0;
73 }
74 if (t)
75 return t->uas.request;
76 else
77 return 0;
78
79 }
80
81 /**
82 * Calculates the expiration time for one contact.
83 * Tries to use the Expiration header, if not present then use the
84 * expires parameter of the contact, if param not present it defaults
85 * to the default value.
86 * Also checks
87 * @param c - the contact to calculate for
88 * @param expires_hdr - value of expires hdr if present, if not -1
89 * @param local_time_now - the local time
90 * @returns the time of expiration
91 */
calc_contact_expires(contact_t * c,int expires_hdr,int local_time_now)92 static inline int calc_contact_expires(contact_t *c,int expires_hdr, int local_time_now)
93 {
94 unsigned int r = 0;
95 if (expires_hdr >= 0)
96 r = expires_hdr;
97
98 if (c && c->expires && c->expires->body.len) {
99 str2int(&(c->expires->body), (unsigned int*) &r);
100 }
101 return local_time_now + r;
102 }
103
104
105 /**
106 * Updates the registrar with the new values
107 * @param req - the REGISTER request - to extract NAT info
108 * @param rpl - the REGISTER reply - to extract contact info
109 * @param is_star - whether this was a STAR contact header
110 * @param expires_hdr - value of the Expires header
111 * @param public_id - array of public identities attached to this contact
112 * @param public_id_cnt - size of the public_id array
113 * @param service_route - array of Service-Routes
114 * @param service_route_cnt - size of the service_route array
115 * @param requires_nat - if to create pinholes
116 * @returns the maximum expiration time, -1 on error
117 */
update_contacts(struct sip_msg * req,struct sip_msg * rpl,udomain_t * _d,unsigned char is_star,int expires_hdr,str * public_id,int public_id_cnt,str * service_route,int service_route_cnt,int requires_nat)118 static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udomain_t* _d, unsigned char is_star,int expires_hdr,
119 str *public_id,int public_id_cnt,str *service_route,int service_route_cnt, int requires_nat)
120 {
121 int local_time_now, expires=0;
122 struct hdr_field* h;
123 contact_t* c;
124 struct sip_uri puri;
125 struct pcontact_info ci;
126 pcontact_t* pcontact;
127 unsigned short port, proto;
128 char *alias_start, *p, *port_s, *proto_s;
129 char portbuf[5];
130 str alias_s;
131
132 pcscf_act_time();
133 local_time_now = time_now;
134 if (is_star) {
135 /* first of all, we shouldn't get here...
136 * then, we will update on NOTIFY */
137 return 0;
138 }
139
140 // Set the structure to "0", to make sure it's properly initialized
141 memset(&ci, 0, sizeof(struct pcontact_info));
142
143 for (h = rpl->contact; h; h = h->next) {
144 if (h->type == HDR_CONTACT_T && h->parsed) {
145 for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) {
146 expires = calc_contact_expires(c, expires_hdr, local_time_now);
147 if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) {
148 LM_DBG("Error parsing Contact URI <%.*s>\n", c->uri.len, c->uri.s);
149 continue;
150 }
151 //build contact info
152 ci.aor = c->uri;
153 ci.expires = expires;
154 ci.public_ids = public_id;
155 ci.num_public_ids = public_id_cnt;
156 ci.service_routes = service_route;
157 ci.num_service_routes = service_route_cnt;
158 ci.reg_state = PCONTACT_REGISTERED|PCONTACT_REG_PENDING|PCONTACT_REG_PENDING_AAR; //we don't want to add contacts that did not come through us (pcscf)
159
160 ci.received_host.len = 0;
161 ci.received_host.s = 0;
162 ci.received_port = 0;
163 ci.received_proto = 0;
164 port = puri.port_no ? puri.port_no : 5060;
165 ci.via_host = puri.host;
166 ci.via_port = port;
167 ci.via_prot = puri.proto;
168 ci.searchflag = SEARCH_NORMAL; /* this must be reset for each contact iteration */
169
170 if (puri.params.len > 6 && (alias_start = _strnistr(puri.params.s, "alias=", puri.params.len)) != NULL) {
171 LM_DBG("contact has an alias [%.*s] - we can use that as the received\n", puri.params.len, puri.params.s);
172 alias_s.len = puri.params.len - (alias_start - puri.params.s) - 6;
173 alias_s.s = alias_start + 6;
174 LM_DBG("alias [%.*s]\n", alias_s.len, alias_s.s);
175 p = _strnistr(alias_s.s, "~", alias_s.len);
176 if (p!=NULL) {
177 ci.received_host.s = alias_s.s;
178 ci.received_host.len = p - alias_s.s;
179 LM_DBG("alias(host) [%.*s]\n", ci.received_host.len, ci.received_host.s);
180 port_s = p+1;
181 p = _strnistr(port_s, "~", alias_s.len - ci.received_host.len);
182 if (p!=NULL) {
183 LM_DBG("alias(port) [%.*s]\n", (int)(p - port_s) , port_s);
184 memset(portbuf, 0, 5);
185 memcpy(portbuf, port_s, (p-port_s));
186 port = atoi(portbuf);
187 LM_DBG("alias(port) [%d]\n", port);
188
189 proto_s = p + 1;
190 memset(portbuf, 0, 5);
191 memcpy(portbuf, proto_s, 1);
192 proto = atoi(portbuf);
193 LM_DBG("alias(proto) [%d]\n", proto);
194 ci.received_port = port;
195 ci.received_proto = proto;
196 ci.searchflag = SEARCH_RECEIVED;
197 }
198 }
199 }
200
201 ul.lock_udomain(_d, &puri.host, port, puri.proto);
202 if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
203 if ((expires-local_time_now)<=0) { //remove contact - de-register
204 LM_DBG("This is a de-registration for contact <%.*s> but contact is not in usrloc - ignore\n", c->uri.len, c->uri.s);
205 goto next_contact;
206 }
207 LM_DBG("We don't add contact from the 200OK that did not go through us (ie, not present in explicit REGISTER that went through us\n");
208 } else { //contact already exists - update
209 LM_DBG("contact already exists and is in state (%d) : [%s]\n",pcontact->reg_state, reg_state_to_string(pcontact->reg_state));
210 if ((expires-local_time_now)<=0) { //remove contact - de-register
211 LM_DBG("This is a de-registration for contact <%.*s>\n", c->uri.len, c->uri.s);
212 if (ul.delete_pcontact(_d, pcontact) != 0) {
213 LM_ERR("failed to delete pcscf contact <%.*s>\n", c->uri.len, c->uri.s);
214 }
215 //TODO_LATEST replace above
216 } else { //update contact
217 LM_DBG("Updating contact: <%.*s>, old expires: %li, new expires: %i which is in %i seconds\n", c->uri.len, c->uri.s,
218 pcontact->expires-local_time_now,
219 expires,
220 expires-local_time_now);
221 ci.reg_state = PCONTACT_REGISTERED;
222 if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
223 LM_DBG("failed to update pcscf contact\n");
224 }else{
225 // Register callback to destroy related tunnels to this contact.
226 // The registration should be exact here, after the successfuly registration of the UE
227 LM_DBG("ul.register_ulcb(pcontact, PCSCF_CONTACT_EXPIRE|PCSCF_CONTACT_DELETE...)\n");
228 if(ul.register_ulcb(pcontact, PCSCF_CONTACT_EXPIRE|PCSCF_CONTACT_DELETE, ipsec_pcscf.ipsec_on_expire, NULL) != 1){
229 LM_DBG("Error subscribing for contact\n");
230 }
231
232 // After successful registration try to unregister all callbacks for pending contacts ralated to this contact.
233 ul.unreg_pending_contacts_cb(_d, pcontact, PCSCF_CONTACT_EXPIRE);
234 }
235 pcontact->expires = expires;
236 }
237 }
238 next_contact:
239 ul.unlock_udomain(_d, &puri.host, port, puri.proto);
240 }
241 }
242 }
243 return 1;
244 }
245
246 /**
247 * Save contact based on REGISTER request. this will be a pending save, until we receive response
248 * from SCSCF. If no response after pending_timeout seconds, the contacts is removed. Can only be used from REQUEST ROUTE
249 */
save_pending(struct sip_msg * _m,udomain_t * _d)250 int save_pending(struct sip_msg* _m, udomain_t* _d) {
251 contact_body_t* cb = 0;
252 int cexpires = 0;
253 pcontact_t* pcontact;
254 contact_t* c;
255 struct pcontact_info ci;
256 struct via_body* vb;
257 unsigned short port, proto;
258 int_str val;
259 struct sip_uri parsed_received;
260 char srcip[50];
261
262 memset(&ci, 0, sizeof(struct pcontact_info));
263
264 vb = cscf_get_ue_via(_m);
265 port = vb->port?vb->port:5060;
266 proto = vb->proto;
267
268 cb = cscf_parse_contacts(_m);
269 if (!cb || (!cb->contacts)) {
270 LM_ERR("No contact headers\n");
271 goto error;
272 }
273
274 c = cb->contacts;
275 //TODO: need support for multiple contacts - currently assume one contact
276 //make sure this is not a de-registration
277 int expires_hdr = cscf_get_expires_hdr(_m, 0);
278 if (expires_hdr < 0) {
279 //no global header we have to check the contact expiry
280 if (c && c->expires && c->expires->body.len) {
281 str2int(&(c->expires->body), (unsigned int*) &cexpires);
282 }
283 if (!cexpires){ //assume de-registration
284 LM_DBG("not doing pending reg on de-registration\n");
285 return 1;
286 }
287 }
288
289 pcscf_act_time();
290 int local_time_now = time_now;
291 int expires = calc_contact_expires(c, expires_hdr, local_time_now);
292 if (expires <= 0) {
293 LM_DBG("not doing pending reg on de-registration\n");
294 return 1;
295 }
296
297 LM_DBG("Save pending contact with AOR [%.*s], proto %d, port %d\n", c->uri.len, c->uri.s, proto, port);
298 LM_DBG("contact requesting to expire in %d seconds\n", expires-local_time_now);
299
300 /*populate CI with bare minimum*/
301 ci.via_host = vb->host;
302 ci.via_port = port;
303 ci.via_prot = proto;
304 ci.aor = c->uri;
305 ci.num_public_ids=0;
306 ci.num_service_routes=0;
307 ci.expires=local_time_now + pending_reg_expires;
308 ci.reg_state=PCONTACT_ANY;
309 ci.searchflag=SEARCH_RECEIVED; //we want to make sure we are very specific with this search to make sure we get the correct contact to put into reg_pending.
310
311 // Received Info: First try AVP, otherwise simply take the source of the request:
312 memset(&val, 0, sizeof(int_str));
313 if (rcv_avp_name.n != 0
314 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0)
315 && val.s.len > 0) {
316 if (val.s.len > RECEIVED_MAX_SIZE) {
317 LM_ERR("received too long\n");
318 goto error;
319 }
320 if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) {
321 LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s);
322 goto error;
323 }
324 ci.received_host = parsed_received.host;
325 ci.received_port = parsed_received.port_no;
326 ci.received_proto = parsed_received.proto;
327 } else {
328 ci.received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip,
329 sizeof(srcip));
330 ci.received_host.s = srcip;
331 ci.received_port = _m->rcv.src_port;
332 ci.received_proto = _m->rcv.proto;
333
334 }
335 // Set to default, if not set:
336 if (ci.received_port == 0)
337 ci.received_port = 5060;
338
339 // Parse security parameters
340 security_t* sec_params = NULL;
341 if((sec_params = cscf_get_security(_m)) == NULL) {
342 LM_DBG("Will save pending contact without security parameters\n");
343 }
344
345 // Parse security-verify parameters
346 security_t* sec_verify_params = NULL;
347 if((sec_verify_params = cscf_get_security_verify(_m)) == NULL){
348 LM_DBG("Will save pending contact without security-verify parameters\n");
349 }else{
350 if(sec_params){
351 // for REGISTER request try to set spi pc and spi ps from security-verify header
352 sec_params->data.ipsec->spi_ps = sec_verify_params->data.ipsec->spi_us;
353 sec_params->data.ipsec->spi_pc = sec_verify_params->data.ipsec->spi_uc;
354
355 // Get from verify header pcscf server and client ports
356 sec_params->data.ipsec->port_ps = sec_verify_params->data.ipsec->port_us;
357 sec_params->data.ipsec->port_pc = sec_verify_params->data.ipsec->port_uc;
358
359 LM_DBG("Will save pending contact with security-verify parameters, spc_ps %u, spi_pc %u, port_ps %u, port_pc %u\n",
360 sec_params->data.ipsec->spi_ps, sec_params->data.ipsec->spi_pc, sec_params->data.ipsec->port_ps, sec_params->data.ipsec->port_pc);
361 }
362 }
363
364 ul.lock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);
365 if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
366 ipsec_pcscf.ipsec_reconfig(); // try to clean all ipsec SAs/Policies if there is no registered contacts
367
368 LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s);
369 ci.reg_state=PCONTACT_REG_PENDING;
370 if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {
371 LM_ERR("Failed inserting new pcontact\n");
372 } else {
373 LM_DBG("registering for UL callback\n");
374 ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE | PCSCF_CONTACT_UPDATE, callback_pcscf_contact_cb, NULL);
375
376 // Update security parameters only for the pending contacts
377 if(sec_params){
378 if(ul.update_temp_security(_d, sec_params->type, sec_params, pcontact) != 0){
379 LM_ERR("Error updating temp security\n");
380 }
381 }
382 }
383 } else { //contact already exists - update
384 LM_DBG("Contact already exists - not doing anything for now\n");
385 }
386
387 ul.unlock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);
388
389
390 return 1;
391
392 error:
393 LM_DBG("Error saving pending contact\n");
394 return -1;
395 }
396
397 /**
398 * Save the contacts and their associated public ids.
399 * @param rpl - the SIP Register 200 OK response that contains the Expire and Contact and P-associated-uri headers
400 * @param _d - domain
401 * @param _cflags - flags
402 * @returns #CSCF_RETURN_TRUE if OK, #CSCF_RETURN_ERROR on error
403 */
save(struct sip_msg * _m,udomain_t * _d,int _cflags)404 int save(struct sip_msg* _m, udomain_t* _d, int _cflags) {
405 struct sip_msg* req;
406 int expires_hdr = 0;
407 contact_body_t* cb = 0;
408 str *public_ids=0;
409 int num_public_ids = 0;
410 str *service_routes=0;
411 int num_service_routes = 0;
412 pv_elem_t *presentity_uri_pv;
413 int contact_has_sos=-1;
414 contact_t* chi; //contact header information
415 struct hdr_field* h;
416 //get request from reply
417 req = get_request_from_reply(_m);
418 if (!req) {
419 LM_ERR("Unable to get request from reply for REGISTER. No transaction\n");
420 goto error;
421 }
422 expires_hdr = cscf_get_expires_hdr(_m, 0);
423
424 if((parse_headers(_m, HDR_CONTACT_F, 0) == -1) || !_m->contact) {
425 LM_ERR("cannot get the Contact header from the SIP message in saving action in PCSCF\n");
426 goto error;
427 }
428
429 if(!_m->contact->parsed && parse_contact(_m->contact) < 0) {
430 LM_ERR("Couldn t parse Contact Header \n");
431 goto error;
432 }
433
434 cb = ((contact_body_t *)_m->contact->parsed);
435 if (!cb || (!cb->contacts && !cb->star)) {
436 LM_DBG("No contact headers and not *\n");
437 goto error;
438 }
439
440 for (h = _m->contact; h; h = h->next) {
441 if (h->type == HDR_CONTACT_T && h->parsed) {
442 for (chi = ((contact_body_t*) h->parsed)->contacts; chi; chi = chi->next) {
443 contact_has_sos = cscf_get_sos_uri_param(chi->uri);
444 if(contact_has_sos!=-1){
445 break;
446 }
447 }
448 }
449 }
450
451 cscf_get_p_associated_uri(_m, &public_ids, &num_public_ids, 1);
452 service_routes = cscf_get_service_route(_m, &num_service_routes, 1);
453
454 //update contacts
455 if (!update_contacts(req, _m, _d, cb->star, expires_hdr, public_ids, num_public_ids, service_routes, num_service_routes, 0)) {
456 LM_ERR("failed to update pcontact\n");
457 goto error;
458 }
459
460 if(subscribe_to_reginfo == 1 && contact_has_sos < 1){
461
462 //use the first p_associated_uri - i.e. the default IMPU
463 LM_DBG("Subscribe to reg event for primary p_associated_uri");
464 if(num_public_ids > 0){
465 //find the first routable (not a tel: URI and use that that presentity)
466 //if you can not find one then exit
467 int i = 0;
468 int found_presentity_uri=0;
469 while (i < num_public_ids && found_presentity_uri == 0)
470 {
471 //check if public_id[i] is NOT a tel URI - if it isn't then concert to pv format and set found presentity_uri to 1
472 if (strncasecmp(public_ids[i].s,"tel:",4)==0) {
473 LM_DBG("This is a tel URI - it is not routable so we don't use it to subscribe");
474 i++;
475 }
476 else {
477 //convert primary p_associated_uri to pv_elem_t
478 if(pv_parse_format(&public_ids[i], &presentity_uri_pv)<0) {
479 LM_ERR("wrong format[%.*s]\n",public_ids[i].len, public_ids[i].s);
480 goto error;
481 }
482 found_presentity_uri=1;
483 }
484 }
485 if(found_presentity_uri!=1){
486 LM_ERR("Could not find routable URI in p_assoiated_uri list - failed to subscribe");
487 goto error;
488 }
489 }else{
490 //Now some how check if there is a pua record and what the presentity uri is from there - if nothing there
491 LM_DBG("No p_associated_uri in 200 OK this must be a de-register - we ignore this - will unsubscribe when the notify is received");
492 goto done;
493
494 }
495 reginfo_subscribe_real(_m, presentity_uri_pv, service_routes, subscription_expires);
496 pv_elem_free_all(presentity_uri_pv);
497 }
498
499 done:
500 if (public_ids && public_ids->s) pkg_free(public_ids);
501 if (service_routes && service_routes->s) pkg_free(service_routes);
502 return 1;
503
504 error:
505 if (public_ids && public_ids->s) pkg_free(public_ids);
506 if (service_routes && service_routes->s) pkg_free(service_routes);
507 return -1;
508
509 }
510