Răsfoiți Sursa

Merge pull request #2023 from alexyosifov/ipsec_fix_defects

Ipsec fix defects
Tsvetomir Dimitrov 6 ani în urmă
părinte
comite
431e945922

+ 36 - 6
src/modules/ims_ipsec_pcscf/cmd.c

@@ -86,7 +86,8 @@ int bind_ipsec_pcscf(ipsec_pcscf_api_t* api) {
 		return -1;
 	}
 
-	api->ipsec_on_expire = ipsec_on_expire;
+	api->ipsec_on_expire	= ipsec_on_expire;
+	api->ipsec_reconfig		= ipsec_reconfig;
 
 	return 0;
 }
@@ -290,19 +291,34 @@ static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m)
         s->ck.s = NULL; s->ck.len = 0;
         shm_free(s->ik.s);
         s->ik.s = NULL; s->ik.len = 0;
+
+		release_spi(s->spi_pc);
         return -1;
     }
 
-    s->port_pc = acquire_cport();
-    s->port_ps = acquire_sport();
-
-    if(s->port_pc == 0){
+    if((s->port_pc = acquire_cport()) == 0){
         LM_ERR("No free client 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_spi(s->spi_pc);
+		release_spi(s->spi_ps);
         return -1;
     }
 
-    if(s->port_ps == 0){
+    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_spi(s->spi_pc);
+		release_spi(s->spi_ps);
         return -1;
     }
 
@@ -834,6 +850,20 @@ cleanup:
     return ret;
 }
 
+int ipsec_reconfig()
+{
+	if(ul.get_number_of_contacts() != 0){
+		return 0;
+	}
+
+	clean_spi_list();
+	clean_port_lists();
+
+	LM_DBG("Clean all ipsec tunnels\n");
+
+	return ipsec_cleanall();
+}
+
 int ipsec_cleanall()
 {
     struct mnl_socket* nlsock = init_mnl_socket();

+ 4 - 1
src/modules/ims_ipsec_pcscf/cmd.h

@@ -48,10 +48,12 @@
 #define IPSEC_CMD_H
 
 typedef void (*contact_expired_t)(pcontact_t* c, int type, void* param);
+typedef int (*reconfig_tunnels_t)();
 
 /*! ipsec pcscf API export structure */
 typedef struct ipsec_pcscf_api {
-    contact_expired_t ipsec_on_expire;
+    contact_expired_t	ipsec_on_expire;
+	reconfig_tunnels_t	ipsec_reconfig;
 } ipsec_pcscf_api_t;
 
 /*! ipsec pcscf API export bind function */
@@ -64,6 +66,7 @@ int ipsec_create(struct sip_msg* m, udomain_t* d);
 int ipsec_forward(struct sip_msg* m, udomain_t* d);
 int ipsec_destroy(struct sip_msg* m, udomain_t* d);
 int ipsec_cleanall();
+int ipsec_reconfig();
 void ipsec_on_expire(pcontact_t* c, int type, void* param);
 
 #endif /* IPSEC_CMD_H */

+ 113 - 31
src/modules/ims_ipsec_pcscf/port_gen.c

@@ -25,17 +25,22 @@
 #include "spi_gen.h"
 #include "spi_list.h"
 #include <pthread.h>
-
-pthread_mutex_t sport_mut;  // server port mutex
-pthread_mutex_t cport_mut;  // client port mutex
-spi_list_t used_sports;     // list with used server ports
-spi_list_t used_cports;     // list with used client ports
-uint32_t sport_val;         // the last acquired server port
-uint32_t cport_val;         // the last acquired client port
-uint32_t min_sport;
-uint32_t min_cport;
-uint32_t max_sport;
-uint32_t max_cport;
+#include "../../core/mem/shm_mem.h"
+
+typedef struct port_generator{
+	pthread_mutex_t	sport_mut;		// server port mutex
+	pthread_mutex_t	cport_mut;		// client port mutex
+	spi_list_t		used_sports;	// list with used server ports
+	spi_list_t		used_cports;	// list with used client ports
+	uint32_t		sport_val;		// the last acquired server port
+	uint32_t		cport_val;		// the last acquired client port
+	uint32_t		min_sport;
+	uint32_t		min_cport;
+	uint32_t		max_sport;
+	uint32_t		max_cport;
+} port_generator_t;
+
+port_generator_t* port_data = NULL;
 
 int init_port_gen(uint32_t sport_start_val, uint32_t cport_start_val, uint32_t range)
 {
@@ -47,24 +52,40 @@ int init_port_gen(uint32_t sport_start_val, uint32_t cport_start_val, uint32_t r
         return 2;
     }
 
-    if(pthread_mutex_init(&sport_mut, NULL) || pthread_mutex_init(&cport_mut, NULL)){
-        return 3;
-    }
+	if(port_data){
+		return 3;
+	}
+
+	port_data = shm_malloc(sizeof(port_generator_t));
+	if(port_data == NULL){
+		return 4;
+	}
+
+	if(pthread_mutex_init(&port_data->sport_mut, NULL)){
+		shm_free(port_data);
+		return 5;
+	}
 
-    used_sports = create_list();
-    used_cports = create_list();
+	if(pthread_mutex_init(&port_data->cport_mut, NULL)){
+		pthread_mutex_destroy(&port_data->sport_mut);
+		shm_free(port_data);
+		return 6;
+	}
 
-    sport_val = min_sport = sport_start_val;
-    cport_val = min_cport = cport_start_val;
-    max_sport = sport_start_val + range;
-    max_cport = cport_start_val + range;
+	port_data->used_sports = create_list();
+	port_data->used_cports = create_list();
+
+	port_data->sport_val = port_data->min_sport = sport_start_val;
+	port_data->cport_val = port_data->min_cport = cport_start_val;
+	port_data->max_sport = sport_start_val + range;
+	port_data->max_cport = cport_start_val + range;
 
     return 0;
 }
 
 uint32_t acquire_port(spi_list_t* used_ports, pthread_mutex_t* port_mut, uint32_t* port_val, uint32_t min_port, uint32_t max_port)
 {
-    //save the initial value for the highly unlikely case where there are no free server PORTs
+	//save the initial value for the highly unlikely case where there are no free PORTs
     uint32_t initial_val = *port_val;
     uint32_t ret = 0; // by default return invalid port
 
@@ -76,6 +97,11 @@ uint32_t acquire_port(spi_list_t* used_ports, pthread_mutex_t* port_mut, uint32_
         if(spi_in_list(used_ports, *port_val) == 0) {
             ret = *port_val;
             (*port_val)++;
+
+			if(*port_val >= max_port) { //reached the top of the range - reset
+				*port_val = min_port;
+			}
+
             break;
         }
 
@@ -102,44 +128,100 @@ uint32_t acquire_port(spi_list_t* used_ports, pthread_mutex_t* port_mut, uint32_
 
 uint32_t acquire_sport()
 {
-    return acquire_port(&used_sports, &sport_mut, &sport_val, min_sport, max_sport);
+	if(!port_data){
+		return 0;
+	}
+
+	return acquire_port(&port_data->used_sports, &port_data->sport_mut, &port_data->sport_val, port_data->min_sport, port_data->max_sport);
 }
 
 uint32_t acquire_cport()
 {
-    return acquire_port(&used_cports, &cport_mut, &cport_val, min_cport, max_cport);
+	if(!port_data){
+		return 0;
+	}
+
+	return acquire_port(&port_data->used_cports, &port_data->cport_mut, &port_data->cport_val, port_data->min_cport, port_data->max_cport);
 }
 
 int release_sport(uint32_t port)
 {
-    if(pthread_mutex_lock(&sport_mut) != 0){
+	if(!port_data){
+		return 1;
+	}
+
+	if(pthread_mutex_lock(&port_data->sport_mut) != 0){
         return 1;
     }
 
-    spi_remove(&used_sports, port);
+	spi_remove(&port_data->used_sports, port);
 
-    pthread_mutex_unlock(&sport_mut);
+	pthread_mutex_unlock(&port_data->sport_mut);
     return 0;
 }
 
 int release_cport(uint32_t port)
 {
-    if(pthread_mutex_lock(&cport_mut) != 0){
+	if(!port_data){
+		return 1;
+	}
+
+	if(pthread_mutex_lock(&port_data->cport_mut) != 0){
         return 1;
     }
 
-    spi_remove(&used_cports, port);
+	spi_remove(&port_data->used_cports, port);
 
-    pthread_mutex_unlock(&cport_mut);
+	pthread_mutex_unlock(&port_data->cport_mut);
     return 0;
 }
 
+int clean_port_lists()
+{
+	if(!port_data){
+		return 1;
+	}
+
+	if(pthread_mutex_lock(&port_data->sport_mut) != 0){
+		return 1;
+	}
+
+	destroy_list(&port_data->used_sports);
+
+	pthread_mutex_unlock(&port_data->sport_mut);
+
+	if(pthread_mutex_lock(&port_data->cport_mut) != 0){
+		return 1;
+	}
+
+	destroy_list(&port_data->used_cports);
+
+	pthread_mutex_unlock(&port_data->cport_mut);
+
+	return 0;
+}
+
 int destroy_port_gen()
 {
-    int ret = pthread_mutex_destroy(&sport_mut);
+	if(!port_data){
+		return 1;
+	}
+
+	int ret;
+
+	destroy_list(&port_data->used_sports);
+	destroy_list(&port_data->used_cports);
+
+	port_data->sport_val = port_data->min_sport;
+	port_data->cport_val = port_data->min_cport;
+
+	ret = pthread_mutex_destroy(&port_data->sport_mut);
     if(ret != 0){
+		shm_free(port_data);
         return ret;
     }
 
-    return pthread_mutex_destroy(&cport_mut);
+	ret = pthread_mutex_destroy(&port_data->cport_mut);
+	shm_free(port_data);
+	return ret;
 }

+ 1 - 0
src/modules/ims_ipsec_pcscf/port_gen.h

@@ -31,6 +31,7 @@
 // It is used as an unique port generator for the TCP client and server ports.
 
 int init_port_gen(uint32_t sport_start_val, uint32_t cport_start_val, uint32_t range);
+int clean_port_lists();
 int destroy_port_gen();
 uint32_t acquire_sport(); // acquare server port
 uint32_t acquire_cport(); // acquare client port

+ 81 - 27
src/modules/ims_ipsec_pcscf/spi_gen.c

@@ -24,12 +24,17 @@
 #include "spi_gen.h"
 #include "spi_list.h"
 #include <pthread.h>
+#include "../../core/mem/shm_mem.h"
 
-pthread_mutex_t spis_mut;
-spi_list_t used_spis;
-uint32_t spi_val;
-uint32_t min_spi;
-uint32_t max_spi;
+typedef struct spi_generator{
+	pthread_mutex_t	spis_mut;
+	spi_list_t		used_spis;
+	uint32_t		spi_val;
+	uint32_t		min_spi;
+	uint32_t		max_spi;
+} spi_generator_t;
+
+spi_generator_t* spi_data = NULL;
 
 int init_spi_gen(uint32_t start_val, uint32_t range)
 {
@@ -40,72 +45,121 @@ int init_spi_gen(uint32_t start_val, uint32_t range)
     if(UINT32_MAX - range < start_val)
         return 2;
 
-    if(pthread_mutex_init(&spis_mut, NULL))
-        return 3;
+	if(spi_data){
+		return 3;
+	}
+
+	spi_data = shm_malloc(sizeof(spi_generator_t));
+	if(spi_data == NULL){
+		return 4;
+	}
 
-    used_spis = create_list();
+	if(pthread_mutex_init(&spi_data->spis_mut, NULL)){
+		shm_free(spi_data);
+		return 5;
+	}
 
-    spi_val = start_val;
-    min_spi = start_val;
-    max_spi = start_val + range;
+	spi_data->used_spis = create_list();
+
+	spi_data->spi_val = spi_data->min_spi = start_val;
+	spi_data->max_spi = start_val + range;
 
     return 0;
 }
 
 uint32_t acquire_spi()
 {
+	if(!spi_data){
+		return 0;
+	}
+
     //save the initial value for the highly unlikely case where there are no free SPIs
-    uint32_t initial_val = spi_val;
+	uint32_t initial_val = spi_data->spi_val;
     uint32_t ret = 0; // by default return invalid SPI
 
-    if(pthread_mutex_lock(&spis_mut) != 0) {
+	if(pthread_mutex_lock(&spi_data->spis_mut) != 0){
         return ret;
     }
 
     while(1) {
-        if(spi_in_list(&used_spis, spi_val) == 0) {
-            ret = spi_val;
-            spi_val++;
+		if(spi_in_list(&spi_data->used_spis, spi_data->spi_val) == 0){
+			ret = spi_data->spi_val;
+			spi_data->spi_val++;
+
+			if(spi_data->spi_val >= spi_data->max_spi) { //reached the top of the range - reset
+				spi_data->spi_val = spi_data->min_spi;
+			}
+
             break;
         }
 
-        spi_val++; //the current SPI is not available - increment
+		spi_data->spi_val++; //the current SPI is not available - increment
 
-        if(spi_val >= max_spi) { //reached the top of the range - reset
-            spi_val = min_spi;
+		if(spi_data->spi_val >= spi_data->max_spi){ //reached the top of the range - reset
+			spi_data->spi_val = spi_data->min_spi;
         }
 
-        if(spi_val == initial_val) { //there are no free SPIs
-            pthread_mutex_unlock(&spis_mut);
+		if(spi_data->spi_val == initial_val){ //there are no free SPIs
+			pthread_mutex_unlock(&spi_data->spis_mut);
             return ret;
         }
 
     }
 
     //found unused SPI - add it to the used list
-    if(spi_add(&used_spis, ret) != 0) {
+	if(spi_add(&spi_data->used_spis, ret) != 0){
         ret = 0;
     }
 
-    pthread_mutex_unlock(&spis_mut);
+	pthread_mutex_unlock(&spi_data->spis_mut);
 
     return ret;
 }
 
 int release_spi(uint32_t id)
 {
-    if(pthread_mutex_lock(&spis_mut) != 0) {
+	if(!spi_data){
+		return 1;
+	}
+
+	if(pthread_mutex_lock(&spi_data->spis_mut) != 0){
         return 1;
     }
 
-    spi_remove(&used_spis, id);
+	spi_remove(&spi_data->used_spis, id);
 
-    pthread_mutex_unlock(&spis_mut);
+	pthread_mutex_unlock(&spi_data->spis_mut);
 
     return 0;
 }
 
+int clean_spi_list()
+{
+	if(!spi_data){
+		return 1;
+	}
+
+	if(pthread_mutex_lock(&spi_data->spis_mut) != 0){
+		return 1;
+	}
+
+	destroy_list(&spi_data->used_spis);
+	spi_data->spi_val = spi_data->min_spi;
+
+	pthread_mutex_unlock(&spi_data->spis_mut);
+
+	return 0;
+}
+
 int destroy_spi_gen()
 {
-    return pthread_mutex_destroy(&spis_mut);
+	if(!spi_data){
+		return 1;
+	}
+
+	destroy_list(&spi_data->used_spis);
+
+	int ret = pthread_mutex_destroy(&spi_data->spis_mut);
+	shm_free(spi_data);
+	return ret;
 }

+ 1 - 0
src/modules/ims_ipsec_pcscf/spi_gen.h

@@ -32,6 +32,7 @@
 // acquire_spi() and release_spi(uint32_t id) functions.
 
 int init_spi_gen(uint32_t start_val, uint32_t range);
+int clean_spi_list();
 int destroy_spi_gen();
 uint32_t acquire_spi();
 int release_spi(uint32_t id);

+ 28 - 9
src/modules/ims_ipsec_pcscf/spi_list.c

@@ -22,6 +22,7 @@
  */
 
 #include "spi_list.h"
+#include "../../core/mem/shm_mem.h"
 
 
 spi_list_t create_list()
@@ -32,21 +33,31 @@ spi_list_t create_list()
     return lst;
 }
 
-void destroy_list(spi_list_t lst)
+void destroy_list(spi_list_t* lst)
 {
-    spi_node_t* l = lst.head;
+	if(!lst){
+		return;
+	}
+	
+    spi_node_t* l = lst->head;
     while(l) {
         spi_node_t* n = l->next;
-        free(l);
+        shm_free(l);
         l = n;
     }
+
+	lst->head = NULL;
+	lst->tail = NULL;
 }
 
 int spi_add(spi_list_t* list, uint32_t id)
 {
-    // create new node
-    spi_node_t* n = malloc(sizeof(spi_node_t));
+	if(!list){
+		return 1;
+	}
 
+	// create new node
+	spi_node_t* n = shm_malloc(sizeof(spi_node_t));
     if(!n)
         return 1;
 
@@ -74,7 +85,7 @@ int spi_add(spi_list_t* list, uint32_t id)
         list->tail = n;
     }
     else if(n->id == c->id) { //c is not NULL, so check for duplicates
-        free(n);
+        shm_free(n);
         return 1;
     }
     else if(c == list->head) { //at the start of the list?
@@ -92,6 +103,10 @@ int spi_add(spi_list_t* list, uint32_t id)
 
 int spi_remove(spi_list_t* list, uint32_t id)
 {
+	if(!list){
+		return 0;
+	}
+
     //when list is empty
     if(!list->head) {
         return 0;
@@ -107,7 +122,7 @@ int spi_remove(spi_list_t* list, uint32_t id)
             list->tail = list->head;
         }
 
-        free(t);
+		shm_free(t);
         return 0;
     }
 
@@ -127,7 +142,7 @@ int spi_remove(spi_list_t* list, uint32_t id)
                 list->tail = prev;
             }
 
-            free(t);
+			shm_free(t);
             return 0;
         }
 
@@ -135,11 +150,15 @@ int spi_remove(spi_list_t* list, uint32_t id)
         curr = curr->next;
     }
 
-    return 0;
+    return -1; // out of scope
 }
 
 int spi_in_list(spi_list_t* list, uint32_t id)
 {
+	if(!list){
+		return 0;
+	}
+
     if(!list->head)
         return 0;
 

+ 1 - 0
src/modules/ims_ipsec_pcscf/spi_list.h

@@ -45,6 +45,7 @@ typedef struct _spi_list {
 
 
 spi_list_t create_list();
+void destroy_list(spi_list_t* lst);
 int spi_add(spi_list_t* list, uint32_t id);
 int spi_remove(spi_list_t* list, uint32_t id);
 int spi_in_list(spi_list_t* list, uint32_t id);

+ 2 - 0
src/modules/ims_registrar_pcscf/save.c

@@ -363,6 +363,8 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) {
 
 	ul.lock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);
 	if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
+		ipsec_pcscf.ipsec_reconfig(); // try to clean all ipsec SAs/Policies if there is no registered contacts
+
 		LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s);
 		ci.reg_state=PCONTACT_REG_PENDING;
 		if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {

+ 16 - 12
src/modules/ims_usrloc_pcscf/pcontact.c

@@ -122,25 +122,29 @@ void free_security(security_t* _p)
     if (!_p)
         return;
 
-    shm_free(_p->sec_header.s);
+	if(_p->sec_header.s)
+		shm_free(_p->sec_header.s);
 
     switch (_p->type)
     {
         case SECURITY_IPSEC:
-            shm_free(_p->data.ipsec->ealg.s);
-            shm_free(_p->data.ipsec->r_ealg.s);
-            shm_free(_p->data.ipsec->ck.s);
-            shm_free(_p->data.ipsec->alg.s);
-            shm_free(_p->data.ipsec->r_alg.s);
-            shm_free(_p->data.ipsec->ik.s);
-            shm_free(_p->data.ipsec->prot.s);
-            shm_free(_p->data.ipsec->mod.s);
-
-            shm_free(_p->data.ipsec);
+			if(_p->data.ipsec){
+				if(_p->data.ipsec->ealg.s)		shm_free(_p->data.ipsec->ealg.s);
+				if(_p->data.ipsec->r_ealg.s)	shm_free(_p->data.ipsec->r_ealg.s);
+				if(_p->data.ipsec->ck.s)		shm_free(_p->data.ipsec->ck.s);
+				if(_p->data.ipsec->alg.s)		shm_free(_p->data.ipsec->alg.s);
+				if(_p->data.ipsec->r_alg.s)		shm_free(_p->data.ipsec->r_alg.s);
+				if(_p->data.ipsec->ik.s)		shm_free(_p->data.ipsec->ik.s);
+				if(_p->data.ipsec->prot.s)		shm_free(_p->data.ipsec->prot.s);
+				if(_p->data.ipsec->mod.s)		shm_free(_p->data.ipsec->mod.s);
+
+				shm_free(_p->data.ipsec);
+			}
         break;
 
         case SECURITY_TLS:
-            shm_free(_p->data.tls);
+			if(_p->data.tls)
+				shm_free(_p->data.tls);
         break;
         
         case SECURITY_NONE:

+ 1 - 0
src/modules/ims_usrloc_pcscf/usrloc.c

@@ -79,6 +79,7 @@ int bind_usrloc(usrloc_api_t* api) {
 	api->update_security = update_security;
 	api->update_temp_security = update_temp_security;
 	api->register_ulcb = register_ulcb;
+	api->get_number_of_contacts = get_number_of_contacts;
 
 	return 0;
 }

+ 5 - 0
src/modules/ims_usrloc_pcscf/usrloc.h

@@ -257,6 +257,9 @@ typedef int (*get_all_ucontacts_t)(void* buf, int len, unsigned int flags, unsig
 typedef int (*update_security_t)(struct udomain* _d, security_type _t, security_t* _s, struct pcontact* _c);
 typedef int (*update_temp_security_t)(struct udomain* _d, security_type _t, security_t* _s, struct pcontact* _c);
 
+/* statistic APIs */
+typedef unsigned long(*get_number_of_contacts_t)();
+
 /*! usrloc API export structure */
 typedef struct usrloc_api {
     int use_domain; /*! use_domain module parameter */
@@ -281,6 +284,8 @@ typedef struct usrloc_api {
     update_temp_security_t update_temp_security;
 
     register_ulcb_t register_ulcb;
+
+	get_number_of_contacts_t get_number_of_contacts;
 } usrloc_api_t;
 
 /*! usrloc API export bind function */