ims_ipsec_pcscf: IPv6 support
[sip-router] / src / modules / ims_ipsec_pcscf / cmd.c
1 /*
2  * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
3  * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
4  *
5  * The initial version of this code was written by Dragos Vingarzan
6  * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
7  * Fruanhofer Institute. It was and still is maintained in a separate
8  * branch of the original SER. We are therefore migrating it to
9  * Kamailio/SR and look forward to maintaining it from here on out.
10  * 2011/2012 Smile Communications, Pty. Ltd.
11  * ported/maintained/improved by
12  * Jason Penton (jason(dot)penton(at)smilecoms.com and
13  * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
14  * effort to add full IMS support to Kamailio/SR using a new and
15  * improved architecture
16  *
17  * NB: Alot of this code was originally part of OpenIMSCore,
18  * FhG Fokus.
19  * Copyright (C) 2004-2006 FhG Fokus
20  * Thanks for great work! This is an effort to
21  * break apart the various CSCF functions into logically separate
22  * components. We hope this will drive wider use. We also feel
23  * that in this way the architecture is more complete and thereby easier
24  * to manage in the Kamailio/SR environment
25  *
26  * This file is part of Kamailio, a free SIP server.
27  *
28  * Kamailio is free software; you can redistribute it and/or modify
29  * it under the terms of the GNU General Public License as published by
30  * the Free Software Foundation; either version 2 of the License, or
31  * (at your option) any later version
32  *
33  * Kamailio is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
41  *
42  */
43
44 #include "../../core/parser/msg_parser.h"
45 #include "../../core/socket_info.h"
46 #include "../../lib/ims/ims_getters.h"
47 #include "../../modules/tm/tm_load.h"
48 #include "../ims_usrloc_pcscf/usrloc.h"
49
50 #include "ipsec.h"
51 #include "spi_gen.h"
52
53 #include <stdlib.h>
54 #include <string.h>
55
56 #include <arpa/inet.h>
57
58
59 extern str ipsec_listen_addr;
60 extern short ipsec_listen_port;
61 extern short ipsec_server_port;
62 extern short ipsec_client_port;
63
64 // check http://www.asipto.com/pub/kamailio-devel-guide/#c16return_values
65 const int IPSEC_CMD_FAIL = -1;
66 const int IPSEC_CMD_SUCCESS = 1;
67
68 extern usrloc_api_t ul;
69 extern struct tm_binds tmb;
70
71
72 static str get_www_auth_param(const char* param_name, str www_auth)
73 {
74     str val = {0,0};
75     int i = 0;
76     int param_len = strlen(param_name);
77     int start = 0;
78     int end = 0;
79
80     for(i = 0; i < www_auth.len; i++) {
81         if (www_auth.s[i] == ' ') continue;
82
83         if(strncasecmp(www_auth.s+i, param_name, param_len) == 0) {
84             i += param_len;
85
86             //find first double quote
87             while(www_auth.s[i] != '"' && i < www_auth.len) i++;
88             i++; //and skip it
89
90             if (i == www_auth.len)
91                 return val; //error
92             start = i;
93             i++;
94
95             //find second double quote
96             while(www_auth.s[i] != '"' && i < www_auth.len) i++;
97             if (i == www_auth.len)
98                 return val; //error
99             end = i;
100             i++;
101
102             val.s = www_auth.s + start;
103             val.len = end - start;
104             break;
105         }
106
107         //parameter not relevant - fast forward
108         do { i++; } while (www_auth.s[i] != ',' && i < www_auth.len);
109     }
110
111     return val;
112 }
113
114
115 static int fill_contact(struct pcontact_info* ci, struct sip_msg* m)
116 {
117     contact_body_t* cb = NULL;
118     struct via_body* vb = NULL;
119     unsigned short port, proto = 0;
120     struct sip_msg* req = NULL;
121
122
123     if(!ci) {
124         LM_ERR("fill_contact() called with null ptr\n");
125         return -1;
126     }
127
128     memset(ci, 0, sizeof(struct pcontact_info));
129
130
131     if(m->first_line.type == SIP_REQUEST) {
132         struct sip_uri uri;
133         memset(&uri, 0, sizeof(struct sip_uri));
134
135         if(parse_uri(m->first_line.u.request.uri.s, m->first_line.u.request.uri.len, &uri)) {
136             LM_ERR("Can't parse the request URI from first line\n");
137             return -1;
138         }
139
140         // populate host,port, aor in CI
141         ci->via_host = uri.host;
142         ci->via_port = uri.port_no ? uri.port_no : 5060;
143         ci->via_prot = proto;
144         ci->aor = m->first_line.u.request.uri;
145
146         req = m;
147     }
148     else if(m->first_line.type == SIP_REPLY) {
149
150         cb = cscf_parse_contacts(m);
151         vb = cscf_get_ue_via(m);
152         port = vb->port?vb->port:5060;
153         proto = vb->proto;
154
155         struct cell *t = tmb.t_gett();
156         if (!t || t == (void*) -1) {
157             LM_ERR("fill_contact(): Reply without transaction\n");
158             return -1;
159         }
160
161         req = t->uas.request;
162
163         cb = cscf_parse_contacts(req);
164         if (!cb || (!cb->contacts)) {
165             LM_ERR("fill_contact(): No contact headers\n");
166             return -1;
167         }
168
169         // populate CI with bare minimum
170         ci->via_host = vb->host;
171         ci->via_port = port;
172         ci->via_prot = proto;
173         ci->aor = cb->contacts->uri;
174     }
175     else {
176         LM_ERR("fill_contact(): Unknown first line type: %d\n", m->first_line.type);
177         return -1;
178     }
179
180
181     char* srcip = NULL;
182     if((srcip = pkg_malloc(50)) == NULL) {
183         LM_ERR("Error allocating memory for source IP address\n");
184         return -1;
185     }
186
187     ci->received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, 50);
188     ci->received_host.s = srcip;
189     ci->received_port = req->rcv.src_port;
190     ci->received_proto = req->rcv.proto;
191
192     // Set to default, if not set:
193     if (ci->received_port == 0)
194         ci->received_port = 5060;
195
196
197     return 0;
198 }
199
200 // Get CK and IK from WWW-Authenticate
201 static int get_ck_ik(const struct sip_msg* m, str* ck, str* ik)
202 {
203     struct hdr_field *www_auth_hdr = NULL;
204     str www_auth;
205     memset(&www_auth, 0, sizeof(str));
206
207     www_auth = cscf_get_authenticate((sip_msg_t*)m, &www_auth_hdr);
208
209     *ck = get_www_auth_param("ck", www_auth);
210     if (ck->len == 0) {
211         LM_ERR("Error getting CK\n");
212         return -1;
213     }
214
215     *ik = get_www_auth_param("ik", www_auth);
216     if (ck->len == 0) {
217         LM_ERR("Error getting IK\n");
218         return -1;
219     }
220
221     return 0;
222 }
223
224 static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m)
225 {
226     // Get CK and IK
227     str ck, ik;
228     if(get_ck_ik(m, &ck, &ik) != 0) {
229         return -1;
230     }
231
232     // Save CK and IK in the contact
233     s->ck.s = shm_malloc(ck.len);
234     if(s->ck.s == NULL) {
235         LM_ERR("Error allocating memory for CK\n");
236         return -1;
237     }
238     memcpy(s->ck.s, ck.s, ck.len);
239     s->ck.len = ck.len;
240
241     s->ik.s = shm_malloc(ik.len);
242     if(s->ik.s == NULL) {
243         LM_ERR("Error allocating memory for IK\n");
244         shm_free(s->ck.s);
245         s->ck.s = NULL; s->ck.len = 0;
246         s->ik.s = NULL; s->ik.len = 0;
247         return -1;
248     }
249     memcpy(s->ik.s, ik.s, ik.len);
250     s->ik.len = ik.len;
251
252     // Generate SPI
253     if((s->spi_pc = acquire_spi()) == 0) {
254         LM_ERR("Error generating client SPI for IPSEC tunnel creation\n");
255         shm_free(s->ck.s);
256         s->ck.s = NULL; s->ck.len = 0;
257         shm_free(s->ik.s);
258         s->ik.s = NULL; s->ik.len = 0;
259         return -1;
260     }
261
262     if((s->spi_ps = acquire_spi()) == 0) {
263         LM_ERR("Error generating server SPI for IPSEC tunnel creation\n");
264         shm_free(s->ck.s);
265         s->ck.s = NULL; s->ck.len = 0;
266         shm_free(s->ik.s);
267         s->ik.s = NULL; s->ik.len = 0;
268         return -1;
269     }
270
271     return 0;
272 }
273
274 static int convert_ip_address(const str ip_addr, const unsigned int af, struct ip_addr* result) {
275     memset(result, 0, sizeof(struct ip_addr));
276     int return_code = -1;
277
278     //Allocate dynamically memory in order to avoid buffer overflows
279     char* ipaddr_str = NULL;
280     if((ipaddr_str = pkg_malloc(ip_addr.len + 1)) == NULL) {
281         LM_CRIT("Error allocating memory for IP address conversion.\n");
282         return -1;
283     }
284     memset(ipaddr_str, 0, ip_addr.len + 1);
285     memcpy(ipaddr_str, ip_addr.s, ip_addr.len);
286
287     int err = 0;
288
289     if((err = inet_pton(af, ipaddr_str, &result->u.addr)) != 1) {
290         if(err == 0) {
291             LM_ERR("Error converting ipsec listen IP address. Bad format %.*s\n", ip_addr.len, ip_addr.s);
292         }
293         else {
294             LM_ERR("Error converting ipsec listen IP address: %s\n", strerror(errno));
295         }
296         goto cleanup;   // return_code = -1 by default
297     }
298
299     //Set len by address family
300     if(af == AF_INET6) {
301         result->len = 16;
302     }
303     else {
304         result->len = 4;
305     }
306
307     result->af = af;
308
309     //Set success return code
310     return_code = 0;
311
312 cleanup:
313     pkg_free(ipaddr_str);
314     return return_code;
315 }
316
317 static int create_ipsec_tunnel(const struct ip_addr *remote_addr, unsigned short proto, ipsec_t* s)
318 {
319     struct mnl_socket* sock = init_mnl_socket();
320     if (sock == NULL) {
321         return -1;
322     }
323
324     //Convert ipsec address from str to struct ip_addr
325     struct ip_addr ipsec_addr;
326     if(convert_ip_address(ipsec_listen_addr, remote_addr->af, &ipsec_addr) != 0) {
327         //there is an error msg in convert_ip_address()
328         return -1;
329     }
330
331     //Convert to char* for logging
332     char remote_addr_str[128];
333     memset(remote_addr_str, 0, sizeof(remote_addr_str));
334     if(inet_ntop(remote_addr->af, remote_addr->u.addr, remote_addr_str, sizeof(remote_addr_str)) == NULL) {
335         LM_CRIT("Error converting remote IP address: %s\n", strerror(errno));
336         return -1;
337     }
338
339     LM_DBG("Creating security associations: Local IP: %.*s client port: %d server port: %d; UE IP: %s; client port %d server port %d\n",
340             ipsec_listen_addr.len, ipsec_listen_addr.s, ipsec_client_port, ipsec_server_port,
341             remote_addr_str, s->port_uc, s->port_us);
342
343     // P-CSCF 'client' tunnel to UE 'server'
344     add_sa    (sock, proto, &ipsec_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, s->ck, s->ik);
345     add_policy(sock, proto, &ipsec_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, IPSEC_POLICY_DIRECTION_OUT);
346
347     // UE 'client' to P-CSCF 'server' tunnel
348     add_sa    (sock, proto, remote_addr, &ipsec_addr, s->port_uc, ipsec_server_port, s->spi_ps, s->ck, s->ik);
349     add_policy(sock, proto, remote_addr, &ipsec_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
350
351     close_mnl_socket(sock);
352
353     return 0;
354 }
355
356 static int destroy_ipsec_tunnel(const str remote_addr, unsigned short proto, ipsec_t* s)
357 {
358     struct mnl_socket* sock = init_mnl_socket();
359     if (sock == NULL) {
360         return -1;
361     }
362
363     LM_DBG("Destroying security associations: Local IP: %.*s client port: %d server port: %d; UE IP: %.*s; client port %d server port %d\n",
364             ipsec_listen_addr.len, ipsec_listen_addr.s, ipsec_client_port, ipsec_server_port,
365             remote_addr.len, remote_addr.s, s->port_uc, s->port_us);
366
367     // P-CSCF 'client' tunnel to UE 'server'
368     remove_sa    (sock, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us);
369     remove_policy(sock, proto, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, IPSEC_POLICY_DIRECTION_OUT);
370
371     // UE 'client' to P-CSCF 'server' tunnel
372     remove_sa    (sock, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps);
373     remove_policy(sock, proto, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN);
374
375     // Release SPIs
376     release_spi(s->spi_uc);
377     release_spi(s->spi_us);
378
379
380     close_mnl_socket(sock);
381     return 0;
382 }
383
384 static void on_expire(struct pcontact *c, int type, void *param)
385 {
386     if(type != PCSCF_CONTACT_EXPIRE && type != PCSCF_CONTACT_DELETE) {
387         LM_ERR("Unexpected event type %d\n", type);
388         return;
389     }
390
391
392     if(c->security_temp == NULL) {
393         LM_ERR("No security parameters found in contact\n");
394         return;
395     }
396
397     //get security parameters
398     if(c->security_temp->type != SECURITY_IPSEC ) {
399         LM_ERR("Unsupported security type: %d\n", c->security_temp->type);
400         return;
401     }
402
403     destroy_ipsec_tunnel(c->received_host, c->received_proto, c->security_temp->data.ipsec);
404 }
405
406 int add_supported_secagree_header(struct sip_msg* m)
407 {
408     // Add sec-agree header in the reply
409     const char* supported_sec_agree = "Supported: sec-agree\r\n";
410     const int supported_sec_agree_len = 22;
411
412     str* supported = NULL;
413     if((supported = pkg_malloc(sizeof(str))) == NULL) {
414         LM_ERR("Error allocating pkg memory for supported header\n");
415         return -1;
416     }
417
418     if((supported->s = pkg_malloc(supported_sec_agree_len)) == NULL) {
419         LM_ERR("Error allcationg pkg memory for supported header str\n");
420         pkg_free(supported);
421         return -1;
422     }
423     memcpy(supported->s, supported_sec_agree, supported_sec_agree_len);
424     supported->len = supported_sec_agree_len;
425
426     if(cscf_add_header(m, supported, HDR_SUPPORTED_T) != 1) {
427                 pkg_free(supported->s);
428                 pkg_free(supported);
429         LM_ERR("Error adding security header to reply!\n");
430         return -1;
431     }
432     pkg_free(supported);
433
434     return 0;
435 }
436
437 int add_security_server_header(struct sip_msg* m, ipsec_t* s)
438 {
439     // allocate memory for the header itself
440     str* sec_header = NULL;
441     if((sec_header = pkg_malloc(sizeof(str))) == NULL) {
442         LM_ERR("Error allocating pkg memory for security header\n");
443         return -1;
444     }
445     memset(sec_header, 0, sizeof(str));
446
447     // create a temporary buffer and set the value in it
448     char sec_hdr_buf[1024];
449     memset(sec_hdr_buf, 0, sizeof(sec_hdr_buf));
450     sec_header->len = snprintf(sec_hdr_buf, sizeof(sec_hdr_buf) - 1,
451                                 "Security-Server: ipsec-3gpp;prot=esp;mod=trans;spi-c=%d;spi-s=%d;port-c=%d;port-s=%d;alg=%.*s;ealg=%.*s\r\n",
452                                 s->spi_pc, s->spi_ps, ipsec_client_port, ipsec_server_port,
453                                 s->r_alg.len, s->r_alg.s,
454                                 s->r_ealg.len, s->r_ealg.s
455                               );
456
457     // copy to the header and add
458     if((sec_header->s = pkg_malloc(sec_header->len)) == NULL) {
459         LM_ERR("Error allocating pkg memory for security header payload\n");
460         pkg_free(sec_header);
461         return -1;
462     }
463     memcpy(sec_header->s, sec_hdr_buf, sec_header->len);
464
465     // add security-server header in reply
466     if(cscf_add_header(m, sec_header, HDR_OTHER_T) != 1) {
467         LM_ERR("Error adding security header to reply!\n");
468         pkg_free(sec_header->s);
469         pkg_free(sec_header);
470         return -1;
471     }
472
473     pkg_free(sec_header);
474
475     return 0;
476 }
477
478 int ipsec_create(struct sip_msg* m, udomain_t* d)
479 {
480     pcontact_t* pcontact = NULL;
481     struct pcontact_info ci;
482     int ret = IPSEC_CMD_FAIL;   // FAIL by default
483
484     // Find the contact
485     if(fill_contact(&ci, m) != 0) {
486         LM_ERR("Error filling in contact data\n");
487         return ret;
488     }
489
490     ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);
491
492     if (ul.get_pcontact(d, &ci, &pcontact) != 0) {
493         LM_ERR("Contact doesn't exist\n");
494         goto cleanup;
495     }
496
497     // Get security parameters
498     if(pcontact->security_temp == NULL) {
499         LM_ERR("No security parameters found in contact\n");
500         goto cleanup;
501     }
502
503     if(pcontact->security_temp->type != SECURITY_IPSEC ) {
504         LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type);
505         goto cleanup;
506     }
507
508     ipsec_t* s = pcontact->security_temp->data.ipsec;
509
510     if(update_contact_ipsec_params(s, m) != 0) {
511         goto cleanup;
512     }
513
514     // Get request from reply
515     struct cell *t = tmb.t_gett();
516     if (!t || t == (void*) -1) {
517         LM_ERR("fill_contact(): Reply without transaction\n");
518         return -1;
519     }
520
521     struct sip_msg* req = t->uas.request;
522     ////
523
524     if(create_ipsec_tunnel(&req->rcv.src_ip, ci.received_proto, s) != 0) {
525         goto cleanup;
526     }
527
528     // TODO: Save security_tmp to security!!!!!
529
530     if (ul.update_pcontact(d, &ci, pcontact) != 0) {
531         LM_ERR("Error updating contact\n");
532         goto cleanup;
533     }
534
535     // Destroy the tunnel, if the contact expires
536     if(ul.register_ulcb(pcontact, PCSCF_CONTACT_EXPIRE|PCSCF_CONTACT_DELETE, on_expire, NULL) != 1) {
537         LM_ERR("Error subscribing for contact\n");
538         goto cleanup;
539     }
540
541
542     if(add_supported_secagree_header(m) != 0) {
543         goto cleanup;
544     }
545
546     if(add_security_server_header(m, s) != 0) {
547         goto cleanup;
548     }
549
550     ret = IPSEC_CMD_SUCCESS;    // all good, set ret to SUCCESS, and exit
551
552 cleanup:
553     // Do not free str* sec_header! It will be freed in data_lump.c -> free_lump()
554     ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);
555     pkg_free(ci.received_host.s);
556     return ret;
557 }
558
559
560 int ipsec_forward(struct sip_msg* m, udomain_t* d)
561 {
562     struct pcontact_info ci;
563     pcontact_t* pcontact = NULL;
564     int ret = IPSEC_CMD_FAIL; // FAIL by default
565
566     //
567     // Find the contact
568     //
569     if(fill_contact(&ci, m) != 0) {
570         LM_ERR("Error filling in contact data\n");
571         return ret;
572     }
573
574     ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);
575
576     if (ul.get_pcontact(d, &ci, &pcontact) != 0) {
577         LM_ERR("Contact doesn't exist\n");
578         goto cleanup;
579     }
580
581
582     if(pcontact->security_temp == NULL) {
583         LM_ERR("No security parameters found in contact\n");
584         goto cleanup;
585     }
586
587     //get security parameters
588     if(pcontact->security_temp->type != SECURITY_IPSEC ) {
589         LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type);
590         goto cleanup;
591     }
592
593     ipsec_t* s = pcontact->security_temp->data.ipsec;
594
595
596     // Update the destination
597     //
598     //       from sec-agree
599     //            v
600     // sip:host:port
601     //       ^
602     //    from URI
603     //int uri_len = 4 /* strlen("sip:") */ + ci.via_host.len + 5 /* max len of port number */ ;
604
605     if(m->dst_uri.s) {
606         pkg_free(m->dst_uri.s);
607         m->dst_uri.s = NULL;
608         m->dst_uri.len = 0;
609     }
610
611     char buf[1024];
612     int buf_len = snprintf(buf, sizeof(buf) - 1, "sip:%.*s:%d", ci.via_host.len, ci.via_host.s, s->port_us);
613
614     if((m->dst_uri.s = pkg_malloc(buf_len)) == NULL) {
615         LM_ERR("Error allocating memory for dst_uri\n");
616         goto cleanup;
617     }
618
619     memcpy(m->dst_uri.s, buf, buf_len);
620     m->dst_uri.len = buf_len;
621
622     // Set send socket
623     struct socket_info * client_sock = grep_sock_info(&ipsec_listen_addr, ipsec_client_port, PROTO_UDP);
624     if(!client_sock) {
625         LM_ERR("Error calling grep_sock_info() for ipsec client port in ipsec_forward\n");
626         return -1;
627     }
628     m->force_send_socket = client_sock;
629
630    // Set destination info
631     struct dest_info dst_info;
632     dst_info.send_sock = client_sock;
633 #ifdef USE_DNS_FAILOVER
634     if (!uri2dst(NULL, &dst_info, m, &m->dst_uri, PROTO_UDP)) {
635 #else
636     if (!uri2dst(&dst_info, m, &m->dst_uri, PROTO_UDP)) {
637 #endif
638         LM_ERR("Error converting dst_uri (%.*s) to struct dst_info\n", m->dst_uri.len, m->dst_uri.s);
639         goto cleanup;
640     }
641
642     // Update dst_info in message
643     if(m->first_line.type == SIP_REPLY) {
644         struct cell *t = tmb.t_gett();
645         if (!t) {
646             LM_ERR("Error getting transaction\n");
647             goto cleanup;
648         }
649         t->uas.response.dst = dst_info;
650     }
651
652     LM_DBG("Destination changed to %.*s\n", m->dst_uri.len, m->dst_uri.s);
653
654     ret = IPSEC_CMD_SUCCESS; // all good, return SUCCESS
655
656     if(add_supported_secagree_header(m) != 0) {
657         goto cleanup;
658     }
659
660     if(add_security_server_header(m, s) != 0) {
661         goto cleanup;
662     }
663
664     ret = IPSEC_CMD_SUCCESS;    // all good, set ret to SUCCESS, and exit
665
666 cleanup:
667     ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);
668     pkg_free(ci.received_host.s);
669     return ret;
670 }
671
672
673 int ipsec_destroy(struct sip_msg* m, udomain_t* d)
674 {
675     struct pcontact_info ci;
676     pcontact_t* pcontact = NULL;
677     int ret = IPSEC_CMD_FAIL; // FAIL by default
678
679     //
680     // Find the contact
681     //
682     if(fill_contact(&ci, m) != 0) {
683         LM_ERR("Error filling in contact data\n");
684         return ret;
685     }
686
687     ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);
688
689     if (ul.get_pcontact(d, &ci, &pcontact) != 0) {
690         LM_ERR("Contact doesn't exist\n");
691         goto cleanup;
692     }
693
694
695     if(pcontact->security_temp == NULL) {
696         LM_ERR("No security parameters found in contact\n");
697         goto cleanup;
698     }
699
700     //get security parameters
701     if(pcontact->security_temp->type != SECURITY_IPSEC ) {
702         LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type);
703         goto cleanup;
704     }
705
706     destroy_ipsec_tunnel(ci.received_host, ci.received_proto, pcontact->security_temp->data.ipsec);
707
708     ret = IPSEC_CMD_SUCCESS;    // all good, set ret to SUCCESS, and exit
709
710 cleanup:
711     ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot);
712     pkg_free(ci.received_host.s);
713     return ret;
714 }
715
716 int ipsec_cleanall()
717 {
718     struct mnl_socket* nlsock = init_mnl_socket();
719     if(!nlsock) {
720         return -1;
721     }
722
723     if(clean_sa(nlsock) != 0) {
724         LM_WARN("Error cleaning IPSec Security associations during startup.\n");
725     }
726
727     if(clean_policy(nlsock) != 0) {
728         LM_WARN("Error cleaning IPSec Policies during startup.\n");
729     }
730
731     close_mnl_socket(nlsock);
732
733     return 0;
734 }