ikev2 traffic selector patch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

I have implemented traffic selector negotiation functionality for ikev2
based on rfc 5996. I am attaching a patch for the same. The current
patch is based on rhel6 openswan version, and I am working on porting it
to latest upstream version. Still I thought to send it to devel mail
list to get some feedback from the developers.

-- 
Thanks and Regards
Avesh

diff -urNp openswan-2.6.32-patched/include/pluto_constants.h openswan-2.6.32-current/include/pluto_constants.h
--- openswan-2.6.32-patched/include/pluto_constants.h	2012-03-27 11:57:45.501034832 -0400
+++ openswan-2.6.32-current/include/pluto_constants.h	2012-04-10 14:06:08.544181078 -0400
@@ -343,7 +343,7 @@ enum ikev2_msgtype {
 #define IS_MODE_CFG_ESTABLISHED(s) ((s) == STATE_MODE_CFG_R2)
 #endif
 
-#define IS_PARENT_SA_ESTABLISHED(s) ((s) == STATE_PARENT_I2 || (s) == STATE_PARENT_R1)
+#define IS_PARENT_SA_ESTABLISHED(s) ((s) == STATE_PARENT_I3 || (s) == STATE_PARENT_R2)
 #define IS_CHILD_SA_ESTABLISHED(st) (((st->st_state) == STATE_PARENT_I3 || (st->st_state) == STATE_PARENT_R2 || (st->st_state) == STATE_CHILDSA_DEL) && (st->st_childsa != NULL))
 
 
diff -urNp openswan-2.6.32-patched/programs/pluto/connections.c openswan-2.6.32-current/programs/pluto/connections.c
--- openswan-2.6.32-patched/programs/pluto/connections.c	2012-02-15 13:36:18.775547490 -0500
+++ openswan-2.6.32-current/programs/pluto/connections.c	2012-04-09 00:45:13.766405636 -0400
@@ -1688,6 +1688,65 @@ instantiate(struct connection *c, const 
 }
 
 struct connection *
+ikev2_narrow_instantiate(struct connection *c)
+{
+    struct connection *d;
+    int wildcards;
+
+    /*if(!(c->policy & POLICY_IKEV2_ALLOW) && !(c->policy & POLICY_IKEV2_PROPOSE)) {
+    passert(c->kind == CK_TEMPLATE);
+    }
+
+    passert(c->spd.next == NULL);*/
+
+    c->instance_serial++;
+    d = clone_thing(*c, "temporary connection");
+
+    /*if (his_id != NULL)
+    {
+	passert(match_id(his_id, &d->spd.that.id, &wildcards));
+	d->spd.that.id = *his_id;
+	d->spd.that.has_id_wildcards = FALSE;
+    }*/
+
+    unshare_connection_strings(d);
+    unshare_ietfAttrList(&d->spd.this.groups);
+    unshare_ietfAttrList(&d->spd.that.groups);
+
+    d->kind = CK_INSTANCE;
+
+    passert(oriented(*d));
+    /*d->spd.that.host_addr = *him;
+    setportof(htons(c->spd.that.port), &d->spd.that.host_addr);
+    default_end(&d->spd.that, &d->spd.this.host_addr);*/
+
+    /* We cannot guess what our next_hop should be, but if it was
+     * explicitly specified as 0.0.0.0, we set it to be him.
+     * (whack will not allow nexthop to be elided in RW case.)
+     */
+    /*default_end(&d->spd.this, &d->spd.that.host_addr);*/
+    d->spd.next = NULL;
+    d->spd.reqid = gen_reqid();
+
+    /* set internal fields */
+    d->ac_next = connections;
+    connections = d;
+    d->spd.routing = RT_UNROUTED;
+    d->newest_isakmp_sa = SOS_NOBODY;
+    d->newest_ipsec_sa = SOS_NOBODY;
+    d->spd.eroute_owner = SOS_NOBODY;
+
+    /* reset log file info */
+    d->log_file_name = NULL;
+    d->log_file = NULL;
+    d->log_file_err = FALSE;
+
+    connect_to_host_pair(d);
+
+    return d;
+}
+
+struct connection *
 rw_instantiate(struct connection *c
 , const ip_address *him
 , const ip_subnet *his_net
diff -urNp openswan-2.6.32-patched/programs/pluto/connections.h openswan-2.6.32-current/programs/pluto/connections.h
--- openswan-2.6.32-patched/programs/pluto/connections.h	2012-02-15 13:36:18.767547492 -0500
+++ openswan-2.6.32-current/programs/pluto/connections.h	2012-04-09 00:44:35.069896402 -0400
@@ -376,6 +376,7 @@ find_connection_for_clients(struct spd_r
  */
 struct gw_info;	/* forward declaration of tag (defined in dnskey.h) */
 struct alg_info;	/* forward declaration of tag (defined in alg_info.h) */
+extern struct connection *ikev2_narrow_instantiate(struct connection *c);
 extern struct connection *rw_instantiate(struct connection *c
 					 , const ip_address *him
 					 , const ip_subnet *his_net
diff -urNp openswan-2.6.32-patched/programs/pluto/ikev2.c openswan-2.6.32-current/programs/pluto/ikev2.c
--- openswan-2.6.32-patched/programs/pluto/ikev2.c	2012-03-27 11:57:45.509034832 -0400
+++ openswan-2.6.32-current/programs/pluto/ikev2.c	2012-04-11 14:14:36.194432610 -0400
@@ -747,7 +747,7 @@ static void success_v2_state_transition(
 	    fmt_isakmp_sa_established(st, sadetails,sizeof(sadetails));
 	}
 	
-	if (IS_CHILD_SA_ESTABLISHED(st))
+	if (IS_CHILD_SA_ESTABLISHED(st) || IS_PARENT_SA_ESTABLISHED(st->st_state))
 	{
 	    /* log our success */
 	    w = RC_SUCCESS;
@@ -910,16 +910,22 @@ void complete_v2_state_transition(struct
     enum state_kind from_state;
     const char *from_state_name;
 
+    /* advance the state */
+    DBG(DBG_CONTROL
+        , DBG_log("complete v2 state transition with %s"
+                  , enum_name(&stfstatus_name, result)));
+
+    /* this occur when IKE SA state is deleted already */
+    if(md->st == NULL) {
+	goto end;
+    }
+
     cur_state = st = md->st;	/* might have changed */
 
     md->result = result;
     TCLCALLOUT("v2AdjustFailure", st, (st ? st->st_connection : NULL), md);
     result = md->result;
 
-    /* advance the state */
-    DBG(DBG_CONTROL
-	, DBG_log("complete v2 state transition with %s"
-		  , enum_name(&stfstatus_name, result)));
 
     switch(result) {
     case STF_IGNORE:
@@ -1009,6 +1015,7 @@ void complete_v2_state_transition(struct
 		    , from_state_name
 		    , enum_name(&ipsec_notification_names, md->note)));
     }
+end:;
 }
 
 notification_t
diff -urNp openswan-2.6.32-patched/programs/pluto/ikev2_child.c openswan-2.6.32-current/programs/pluto/ikev2_child.c
--- openswan-2.6.32-patched/programs/pluto/ikev2_child.c	2012-02-15 13:36:18.770547493 -0500
+++ openswan-2.6.32-current/programs/pluto/ikev2_child.c	2012-04-11 14:55:58.822981271 -0400
@@ -72,7 +72,7 @@ struct traffic_selector ikev2_subnettots
     
     switch(e->client.addr.u.v4.sin_family) {
     case AF_INET:
-	ts.sin_family = AF_INET;
+	ts.sin_family = ID_IPV4_ADDR_RANGE;
 	ts.low   = e->client.addr;
 	ts.low.u.v4.sin_addr.s_addr  &= bitstomask(e->client.maskbits).s_addr;
 	ts.high  = e->client.addr;
@@ -80,7 +80,7 @@ struct traffic_selector ikev2_subnettots
 	break;
 
     case AF_INET6:
-	ts.sin_family = AF_INET6;
+	ts.sin_family = ID_IPV6_ADDR_RANGE;
 	v6mask = bitstomask6(e->client.maskbits);
 
 	ts.low   = e->client.addr;
@@ -113,10 +113,61 @@ struct traffic_selector ikev2_subnettots
     ts.startport = e->port;
     ts.endport = e->port;
     }
+
+    ts.next = NULL;
 	
     return ts;
 }
 
+void 
+ikev2_store_ts_instate(struct traffic_selector *array_tsi
+		,struct traffic_selector * array_tsr
+		, unsigned int tsi_n
+		, unsigned int tsr_n
+		, struct traffic_selector *ts_this
+		, struct traffic_selector *ts_that)
+{
+	unsigned int i;
+	struct traffic_selector *curts, *prevts;
+
+	prevts = NULL;
+	curts = ts_this;
+	for(i=0; i<tsi_n; i++) {
+		if(curts == NULL) {
+		curts = alloc_thing(struct traffic_selector, "struct traffic_selector");
+		}
+
+		*curts = array_tsi[i];
+		curts->next = NULL;
+
+		if(prevts!= NULL) {
+		prevts->next = curts;
+		}
+
+		prevts = curts;
+		curts = curts->next;
+	}
+
+	prevts = NULL;
+	curts = ts_that;   
+
+	for(i=0; i<tsr_n; i++) {
+		if(curts == NULL) {
+		curts = alloc_thing(struct traffic_selector, "struct traffic_selector");
+		}
+
+		*curts = array_tsr[i];
+		curts->next = NULL;
+
+		if(prevts!= NULL) {
+		prevts->next = curts;
+		}
+
+		prevts = curts;
+		curts = curts->next;
+	}
+}
+
 stf_status ikev2_emit_ts(struct msg_digest *md   UNUSED
 			 , pb_stream *outpbs   
 			 , unsigned int np
@@ -127,20 +178,28 @@ stf_status ikev2_emit_ts(struct msg_dige
     struct ikev2_ts1 its1;
     pb_stream ts_pbs;
     pb_stream ts_pbs2;
+    struct traffic_selector *tmp=ts;
 
     its.isat_np = np;
     its.isat_critical = ISAKMP_PAYLOAD_NONCRITICAL;
-    its.isat_num = 1;
+
+    its.isat_num = 0;
+    while(tmp!=NULL) {
+	its.isat_num++;
+	tmp = tmp->next;
+    }
 
     if(!out_struct(&its, &ikev2_ts_desc, outpbs, &ts_pbs))
 	return STF_INTERNAL_ERROR;
 
+   while(ts!=NULL) {
+
     switch(ts->sin_family) {
-    case AF_INET:
+    case ID_IPV4_ADDR_RANGE:
 	its1.isat1_type = ID_IPV4_ADDR_RANGE;
 	its1.isat1_sellen = 16;
 	break;
-    case AF_INET6:
+    case ID_IPV6_ADDR_RANGE:
 	its1.isat1_type = ID_IPV6_ADDR_RANGE;
 	its1.isat1_sellen = 40;
 	break;
@@ -160,12 +219,12 @@ stf_status ikev2_emit_ts(struct msg_dige
     
     /* now do IP addresses */
     switch(ts->sin_family) {
-    case AF_INET:
+    case ID_IPV4_ADDR_RANGE:
 	if(!out_raw(&ts->low.u.v4.sin_addr.s_addr, 4, &ts_pbs2, "ipv4 low")
 	   ||!out_raw(&ts->high.u.v4.sin_addr.s_addr, 4,&ts_pbs2,"ipv4 high"))
 	    return STF_INTERNAL_ERROR;
 	break;
-    case AF_INET6:
+    case ID_IPV6_ADDR_RANGE:
 	if(!out_raw(&ts->low.u.v6.sin6_addr.s6_addr, 16, &ts_pbs2, "ipv6 low")
 	   ||!out_raw(&ts->high.u.v6.sin6_addr.s6_addr,16,&ts_pbs2,"ipv6 high"))
 	    return STF_INTERNAL_ERROR;
@@ -173,11 +232,56 @@ stf_status ikev2_emit_ts(struct msg_dige
     }
 
     close_output_pbs(&ts_pbs2);
+    ts = ts->next;	
+    }
+
     close_output_pbs(&ts_pbs);
     
     return STF_OK;
 }
 
+bool
+ikev2_perfect_match_ts(struct traffic_selector *tsi
+		,struct traffic_selector *tsr
+		, unsigned int tsi_n
+		, unsigned int tsr_n
+		, struct connection *c
+		, enum phase1_role role)
+{
+	struct end *ei, *er;
+	struct traffic_selector tmpi, tmpr;
+
+	if(tsi_n > 1 ||  tsi_n > 1) {
+		return FALSE;
+	}
+
+	if(role == INITIATOR) {
+		ei = &c->spd.this;
+		er = &c->spd.that;
+	} else {
+		ei = &c->spd.that;
+		er = &c->spd.this;
+	}
+
+	tmpi = ikev2_subnettots(ei);
+	tmpr = ikev2_subnettots(er);
+
+	if(addrcmp(&tmpi.low, &tsi[0].low) == 0
+		&& addrcmp(&tmpi.high, &tsi[0].high) == 0
+		&& tmpi.startport == tsi[0].startport
+		&& tmpi.endport == tsi[0].endport
+		&& tmpi.ipprotoid == tsi[0].ipprotoid
+		&& addrcmp(&tmpr.low, &tsr[0].low) == 0
+		&& addrcmp(&tmpr.high, &tsr[0].high) == 0
+		&& tmpr.startport == tsr[0].startport
+		&& tmpr.endport == tsr[0].endport
+		&& tmpr.ipprotoid == tsr[0].ipprotoid)
+	{
+		return TRUE;
+	}
+
+	return FALSE;
+}
 
 stf_status ikev2_calc_emit_ts(struct msg_digest *md
 			      , pb_stream *outpbs
@@ -187,10 +291,8 @@ stf_status ikev2_calc_emit_ts(struct msg
 {
     struct state *st = md->st;
     struct traffic_selector *ts_i, *ts_r;
-    struct spd_route *sr;
     stf_status ret;
     
-    st->st_childsa = c0;
 
     if(role == INITIATOR) {
 	ts_i = &st->st_ts_this;
@@ -200,7 +302,6 @@ stf_status ikev2_calc_emit_ts(struct msg
 	ts_r = &st->st_ts_this;
     }
 
-    for(sr=&c0->spd; sr != NULL; sr = sr->next) {
 	ret = ikev2_emit_ts(md, outpbs, ISAKMP_NEXT_v2TSr
 			    , ts_i, INITIATOR);
 	if(ret!=STF_OK) return ret;
@@ -227,13 +328,85 @@ stf_status ikev2_calc_emit_ts(struct msg
 	}
 
 	if(ret!=STF_OK) return ret;
-    }
 
     return STF_OK;
 }
 
+bool 
+ikev2_verify_ts(struct traffic_selector *tsi
+		, struct traffic_selector *tsr
+		, unsigned int ntsi
+		, unsigned int ntsr
+		, struct traffic_selector *this_ts
+		, struct traffic_selector *that_ts
+		, enum phase1_role role)
+{
+	unsigned int i;	
+	struct traffic_selector *tmptsi, *tmptsr;
+
+
+	if(role == INITIATOR) {
+		tmptsi = this_ts;
+		tmptsr = that_ts;	
+	}
+	else {
+		tmptsi = that_ts;
+		tmptsr = this_ts;
+	}
+	
+	for(i = 0; i < ntsi; i++ ) {
+
+		/* verify addresses*/ 
+		if(addrcmp(&tmptsi->low, &tsi[i].low) > 0
+			|| addrcmp(&tmptsi->high, &tsi[i].high) < 0) 
+		{
+			return FALSE;
+		}
+
+		/* verify port */ 
+		if(tmptsi->startport > tsi[i].startport 
+			|| tmptsi->endport < tsi[i].endport)
+		{
+			return FALSE;
+		}
+
+		/* verify protocol */
+		if( tmptsi->ipprotoid !=0 
+			&& tmptsi->ipprotoid != tsi[i].ipprotoid) 
+		{
+			return FALSE;
+		}
+	} 
+
+	for(i = 0; i < ntsr; i++ ) {
+
+		/* verify addresses*/ 
+		if(addrcmp(&tmptsr->low, &tsr[i].low) > 0
+			|| addrcmp(&tmptsr->high, &tsr[i].high) < 0) 
+		{
+			return FALSE;
+		}
+
+		/* verify port */
+		if(tmptsr->startport > tsr[i].startport
+			|| tmptsr->endport < tsr[i].endport)
+		{
+			return FALSE;
+		}
+
+		/* verify protocol */
+
+		if( tmptsr->ipprotoid !=0
+			&& tmptsr->ipprotoid != tsr[i].ipprotoid)
+		{
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
 /* return number of traffic selectors found */
-static int 
+int 
 ikev2_parse_ts(struct payload_digest *const ts_pd
 	       , struct traffic_selector *array
 	       , unsigned int array_max)
@@ -250,7 +423,7 @@ ikev2_parse_ts(struct payload_digest *co
 	    memset(&array[i], 0, sizeof(*array));
 	    switch(ts1.isat1_type) {
 	    case ID_IPV4_ADDR_RANGE:
-		array[i].sin_family = AF_INET;
+		array[i].sin_family = ID_IPV4_ADDR_RANGE;
 
 		array[i].low.u.v4.sin_family  = AF_INET;
 #ifdef NEED_SIN_LEN
@@ -269,7 +442,7 @@ ikev2_parse_ts(struct payload_digest *co
 		break;
 
 	    case ID_IPV6_ADDR_RANGE:
-		array[i].sin_family = AF_INET;
+		array[i].sin_family = ID_IPV6_ADDR_RANGE;
 		array[i].low.u.v6.sin6_family  = AF_INET6;
 #ifdef NEED_SIN_LEN
 		array[i].low.u.v6.sin6_len = sizeof( struct sockaddr_in6);
@@ -301,117 +474,679 @@ ikev2_parse_ts(struct payload_digest *co
     return i;
 }
 
-
-static int ikev2_evaluate_connection_fit(struct connection *d
-				  , struct spd_route *sr
-				  , enum phase1_role role
-				  , struct traffic_selector *tsi
-				  , struct traffic_selector *tsr
-				  , unsigned int tsi_n
-				  , unsigned int tsr_n)
+static bool 
+ikev2_narrowing(struct connection *c
+		  , enum phase1_role role
+		  , struct traffic_selector *tsi
+		  , struct traffic_selector *tsr
+		  , unsigned int tsi_n
+		  , unsigned int tsr_n
+		  , struct traffic_selector **narrowed_tsi
+		  , struct traffic_selector **narrowed_tsr
+		  , struct connection **result) 
 {
-    unsigned int tsi_ni, tsr_ni;
-    int bestfit = -1;
-    int best_tsr, best_tsi; 
-    struct end *ei, *er;
-    
-    if(role == INITIATOR) {
-	ei = &sr->this;
-	er = &sr->that;
-    } else {
-	ei = &sr->that;
-	er = &sr->this;
-    }
-	
-    DBG(DBG_CONTROLMORE,
-    {
-	char ei3[SUBNETTOT_BUF];
-	char er3[SUBNETTOT_BUF];
-	subnettot(&ei->client,  0, ei3, sizeof(ei3));
-	subnettot(&er->client,  0, er3, sizeof(er3));
-	DBG_log("  ikev2_eval_conn evaluating "
-		"I=%s:%s:%d/%d R=%s:%d/%d %s"
-		, d->name, ei3, ei->protocol, ei->port
-		, er3, er->protocol, er->port
-		, is_virtual_connection(d) ? "(virt)" : "");
-    }
-    );
-   
-    /* compare tsi/r array to this/that, evaluating how well it fits */
-    for(tsi_ni = 0; tsi_ni < tsi_n; tsi_ni++) {
-	for(tsr_ni=0; tsr_ni<tsr_n; tsr_ni++) {
-	    /* does it fit at all? */
+struct host_pair *hp = NULL;
+struct connection *d;
+unsigned int i; 
+struct end *ei, *er;
+int  bests=0;
+struct connection *bestc=NULL;
+bool specific_first_ts = FALSE;
+
+
+	hp = find_host_pair(&c->spd.this.host_addr
+				, c->spd.this.host_port
+				, &c->spd.that.host_addr
+				, c->spd.that.host_port);
+
+#ifdef DEBUG
+	if (DBGP(DBG_CONTROLMORE))
+	{
+		char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
+
+		subnettot(&c->spd.this.client, 0, s2, sizeof(s2));
+		subnettot(&c->spd.that.client, 0, d2, sizeof(d2));
+
+		DBG_log("  checking hostpair %s -> %s is %s"
+			, s2, d2
+			, (hp ? "found" : "not found"));
+	}
+#endif /* DEBUG */
+
+	if(!hp) {
+		return FALSE;
+	}
+
+	/* check if there is any specific first traffic selector */
+	if( addrcmp(&tsi[0].low, &tsi[0].high)==0 && tsi[0].startport == tsi[0].endport &&  tsi[0].ipprotoid!=0 
+		&& addrcmp(&tsr[0].low, &tsr[0].high)==0 && tsr[0].startport ==  tsr[0].endport &&  tsr[0].ipprotoid!=0) {
+		specific_first_ts = TRUE;
+	}
+
+	/*if(!specific_first_ts && (tsi_n >= 2 || tsr_n >= 2) )
+	{
+		return FALSE;
+	}*/
+
+	for (d = hp->connections; d != NULL; d = d->hp_next)
+	{
+		int wildcards, pathlen;  /* XXX */
+		struct traffic_selector tmp,  tmp2;
+		int curs=0;
+		bool found_one_match_tsi = FALSE, found_one_match_tsr = FALSE;
+		
+		if (d->policy & POLICY_GROUP)
+			continue;
+		
+		if (!(same_id(&c->spd.this.id, &d->spd.this.id)
+		      && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
+		      && trusted_ca(c->spd.that.ca, d->spd.that.ca, &pathlen)))
+		    continue;
+
+
+		if(ikev2_perfect_match_ts(tsi, tsr, tsi_n, tsr_n, d, role)) {
+			*result = d;
+			return TRUE;
+		}
+
+		if(role == INITIATOR) {
+			ei = &d->spd.this;
+			er = &d->spd.that;
+		} else {
+			ei = &d->spd.that;
+			er = &d->spd.this;
+		}
+
+		tmp = ikev2_subnettots(ei);
+
+
+		for(i=0; i<tsi_n; i++) {
+			
+			/* ip address */
+			if(addrcmp(&tmp.low, &tsi[i].low) >= 0) 
+			{
+				tmp2.low = tmp.low;
+			}
+			else
+			{
+				tmp2.low = tsi[i].low;
+			}
+
+			if(addrcmp(&tmp.high, &tsi[i].high) >= 0) 
+			{
+				tmp2.high = tsi[i].high;
+			}			
+			else
+			{
+				tmp2.high = tmp.high;
+			}
+
+			if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
+				continue;
+			}
+
+			if(addrtypeof(&tmp2.low) != addrtypeof(&tmp2.high)) {
+				continue;
+			}
+
+			/* port */
+			if(tmp.startport >= tsi[i].startport ) 
+			{
+				tmp2.startport=tmp.startport;
+			}
+			else 
+			{
+				tmp2.startport=tsi[i].startport;
+			}
+
+			if(tmp.endport >= tsi[i].endport )
+			{
+				tmp2.endport=tsi[i].endport;
+			}
+			else
+			{
+				tmp2.endport=tmp.endport;
+			}
+		
+			if(tmp2.startport >  tmp2.endport) 
+			{
+				continue;
+			}
+
+			/* protocol */
+			if( !tmp.ipprotoid && !tsi[i].ipprotoid && tmp.ipprotoid!=tsi[i].ipprotoid ) 
+			{
+				continue;
+			}
+
+			curs++;
+			found_one_match_tsi = TRUE;
+		}
+
+		tmp = ikev2_subnettots(er);
+		for(i=0; i<tsr_n; i++) {
+		
+			/* ip address */
+			if(addrcmp(&tmp.low, &tsr[i].low) >= 0) 
+			{
+				tmp2.low = tmp.low;
+			}
+			else
+			{
+				tmp2.low = tsr[i].low;
+			}
+
+			if(addrcmp(&tmp.high, &tsr[i].high) >= 0) 
+			{
+				tmp2.high = tsr[i].high;
+			}			
+			else
+			{
+				tmp2.high = tmp.high;
+			}
+
+			if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
+				continue;
+			}
+
+			if(addrtypeof(&tmp2.low) != addrtypeof(&tmp2.high)) {
+				continue;
+			}
+
+			/* port */
+			if(tmp.startport >= tsr[i].startport ) 
+			{
+				tmp2.startport=tmp.startport;
+			}
+			else 
+			{
+				tmp2.startport=tsr[i].startport;
+			}
+
+			if(tmp.endport >= tsr[i].endport )
+			{
+				tmp2.endport=tsr[i].endport;
+			}
+			else
+			{
+				tmp2.endport=tmp.endport;
+			}
+		
+			if(tmp2.startport >  tmp2.endport) 
+			{
+				continue;
+			}
+
+			/* protocol */
+			if( !tmp.ipprotoid && !tsr[i].ipprotoid && tmp.ipprotoid!=tsr[i].ipprotoid ) 
+			{
+				continue;
+			}
+
+			curs++;
+			found_one_match_tsr = TRUE;
 
+		}
+
+		if(curs > bests && found_one_match_tsi && found_one_match_tsr) 
+		{
+		bests = curs;
+		bestc = d;
+
+		}
+	}
+
+	if(bestc == NULL) {
+		return FALSE;
+	}
+
+	/* creating narrowed traffic selector */
+	{
+		struct traffic_selector tmp,  tmp2, *tmp3;
+
+		*result = bestc;
+
+		if(role == INITIATOR) {
+			ei = &bestc->spd.this;
+			er = &bestc->spd.that;
+		} else {
+			ei = &bestc->spd.that;
+			er = &bestc->spd.this;
+		}
+
+
+		tmp = ikev2_subnettots(ei);
+		for(i=0; i<tsi_n; i++) {
+		
+			/* ip address */
+			if(addrcmp(&tmp.low, &tsi[i].low) >= 0) 
+			{
+				tmp2.low = tmp.low;
+			}
+			else
+			{
+				tmp2.low = tsi[i].low;
+			}
+
+			if(addrcmp(&tmp.high, &tsi[i].high) >= 0) 
+			{
+				tmp2.high = tsi[i].high;
+			}			
+			else
+			{
+				tmp2.high = tmp.high;
+			}
+
+			if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
+				continue;
+			}
+
+			/* port */
+			if(tmp.startport >= tsi[i].startport ) 
+			{
+				tmp2.startport=tmp.startport;
+			}
+			else 
+			{
+				tmp2.startport=tsi[i].startport;
+			}
+
+			if(tmp.endport >= tsi[i].endport )
+			{
+				tmp2.endport=tsi[i].endport;
+			}
+			else
+			{
+				tmp2.endport=tmp.endport;
+			}
+		
+			if(tmp2.startport >  tmp2.endport) 
+			{
+				continue;
+			}
+
+			/* as openswan supports only single port, so picking one port*/
+			if( tmp2.startport > 0){
+				tmp2.endport = tmp2.startport;
+			}
+			else if (tmp2.endport < 65535 ){
+				tmp2.startport = tmp2.endport;
+			}
+
+			/* protocol */
+			if( tmp.ipprotoid > 0 && tsi[i].ipprotoid > 0 && tmp.ipprotoid!=tsi[i].ipprotoid) 
+			{
+				continue;
+			}
+			else if(tmp.ipprotoid == 0)
+			{			
+				tmp2.ipprotoid = tsi[i].ipprotoid;
+			} 
+			else 
+			{
+				tmp2.ipprotoid = tmp.ipprotoid;
+			}
+
+			/*setting type */
+			switch(tmp2.low.u.v4.sin_family) {
+			case AF_INET:
+				tmp2.sin_family = ID_IPV4_ADDR_RANGE;
+				break;
+			case AF_INET6:
+				tmp2.sin_family = ID_IPV6_ADDR_RANGE;
+				break;
+			}		
+
+			tmp3 = alloc_thing(struct traffic_selector, "struct traffic_selector");
+			*tmp3 = tmp2;
+			tmp3->next = NULL;
+			
+			if(*narrowed_tsi == NULL)
+			{
+				*narrowed_tsi = tmp3;
+			}
+			else
+			{
+				struct traffic_selector *tmp4 = *narrowed_tsi;
+				while(tmp4->next!=NULL){
+				tmp4 = tmp4->next;
+				}
+				tmp4->next = tmp3;
+				
+			}
+		}
+
+		tmp = ikev2_subnettots(er);
+		for(i=0; i<tsr_n; i++) {
+			
+			/* ip address */
+			if(addrcmp(&tmp.low, &tsr[i].low) >= 0) 
+			{
+				tmp2.low = tmp.low;
+			}
+			else
+			{
+				tmp2.low = tsr[i].low;
+			}
+
+			if(addrcmp(&tmp.high, &tsr[i].high) >= 0) 
+			{
+				tmp2.high = tsr[i].high;
+			}			
+			else
+			{
+				tmp2.high = tmp.high;
+			}
+
+			if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
+				continue;
+			}
+
+			/* port */
+			if(tmp.startport >= tsr[i].startport ) 
+			{
+				tmp2.startport=tmp.startport;
+			}
+			else 
+			{
+				tmp2.startport=tsr[i].startport;
+			}
+
+			if(tmp.endport >= tsr[i].endport )
+			{
+				tmp2.endport=tsr[i].endport;
+			}
+			else
+			{
+				tmp2.endport=tmp.endport;
+			}
+		
+			if(tmp2.startport >  tmp2.endport) 
+			{
+				continue;
+			}
+
+			/* as openswan supports only single port, so picking one port*/
+			if( tmp2.startport > 0){
+				tmp2.endport = tmp2.startport;
+			}
+			else if (tmp2.endport < 65535 ){
+				tmp2.startport = tmp2.endport;
+			}
+
+			/* protocol */
+			if( !tmp.ipprotoid && !tsr[i].ipprotoid && tmp.ipprotoid!=tsr[i].ipprotoid ) 
+			{
+				continue;
+			}
+			else if(tmp.ipprotoid == 0)
+			{			
+				tmp2.ipprotoid = tsr[i].ipprotoid;
+			} 
+			else 
+			{
+				tmp2.ipprotoid = tmp.ipprotoid;
+			}
+
+			/*setting type */
+			switch(tmp2.low.u.v4.sin_family) {
+			case AF_INET:
+				tmp2.sin_family = ID_IPV4_ADDR_RANGE;
+				break;
+			case AF_INET6:
+				tmp2.sin_family = ID_IPV6_ADDR_RANGE;
+				break;
+			}
+
+			tmp3 = alloc_thing(struct traffic_selector, "struct traffic_selector");
+			*tmp3 = tmp2;
+			tmp3->next = NULL;
+			
+			if(*narrowed_tsr == NULL)
+			{
+				*narrowed_tsr = tmp3;
+			}
+			else
+			{
+				struct traffic_selector *tmp4 = *narrowed_tsr;
+				while(tmp4->next!=NULL){
+				tmp4 = tmp4->next;
+				}
+				
+				tmp4->next = tmp3;		
+			}
+
+		}
+	}
+
+	struct traffic_selector *tmp;
+	tmp = *narrowed_tsi;
+	while(tmp!= NULL) {
+		
 	    DBG(DBG_CONTROLMORE,
 	    {
 		char lbi[ADDRTOT_BUF];
 		char hbi[ADDRTOT_BUF];
-		char lbr[ADDRTOT_BUF];
-		char hbr[ADDRTOT_BUF];
-		addrtot(&tsi[tsi_ni].low,  0, lbi, sizeof(lbi));
-		addrtot(&tsi[tsi_ni].high, 0, hbi, sizeof(hbi));
-		addrtot(&tsr[tsr_ni].low,  0, lbr, sizeof(lbr));
-		addrtot(&tsr[tsr_ni].high, 0, hbr, sizeof(hbr));
-		
-		DBG_log("    tsi[%u]=%s/%s tsr[%u]=%s/%s "
-			, tsi_ni, lbi, hbi
-			, tsr_ni, lbr, hbr);
+		addrtot(&tmp->low,  0, lbi, sizeof(lbi));
+		addrtot(&tmp->high, 0, hbi, sizeof(hbi));
+		
+		DBG_log("    tsi=%s/%s, port=%d/%d, protocol=%d"
+			,  lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
 	    }
 	    );
-	    /* do addresses fit into the policy? */
-	    if(addrinsubnet(&tsi[tsi_ni].low, &ei->client)
-	       && addrinsubnet(&tsi[tsi_ni].high, &ei->client)
-	       && addrinsubnet(&tsr[tsr_ni].low,  &er->client)
-	       && addrinsubnet(&tsr[tsr_ni].high, &er->client))
+
+	tmp=tmp->next;
+	}
+
+	tmp = *narrowed_tsr;
+	while(tmp!= NULL) {
+		
+	    DBG(DBG_CONTROLMORE,
 	    {
-		/*
-		 * now, how good a fit is it? --- sum of bits gives
-		 * how good a fit this is.
-		 */
-		int ts_range1 = ikev2_calc_iprangediff(tsi[tsi_ni].low
-						      , tsi[tsi_ni].high);
-		int maskbits1 = ei->client.maskbits;
-		int fitbits1  = maskbits1 + ts_range1;
-
-		int ts_range2 = ikev2_calc_iprangediff(tsr[tsr_ni].low
-						      , tsr[tsr_ni].high);
-		int maskbits2 = er->client.maskbits;
-		int fitbits2  = maskbits2 + ts_range2;
-		int fitbits = (fitbits1 << 8) + fitbits2;
-
-		/*
-		 * comparing for ports
-		 * for finding better local polcy
-		 */
-
-		if( ei->port && (tsi[tsi_ni].startport == ei->port && tsi[tsi_ni].endport == ei->port)) {
-		fitbits = fitbits << 1;
-		}
+		char lbi[ADDRTOT_BUF];
+		char hbi[ADDRTOT_BUF];
+		addrtot(&tmp->low,  0, lbi, sizeof(lbi));
+		addrtot(&tmp->high, 0, hbi, sizeof(hbi));
+		
+		DBG_log("    tsr=%s/%s, port=%d/%d, protocol=%d"
+			,  lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
+	    }
+	    );
 
-		if( er->port && (tsr[tsr_ni].startport == er->port && tsr[tsr_ni].endport == er->port)) {
-		fitbits = fitbits << 1;
-		}
+	tmp=tmp->next;
+	}
+	return TRUE;
+}
 
-		DBG(DBG_CONTROLMORE,
-		{
-		    DBG_log("      has ts_range1=%u maskbits1=%u ts_range2=%u maskbits2=%u fitbits=%d <> %d"
-			    , ts_range1, maskbits1, ts_range2, maskbits2
-			    , fitbits, bestfit);
-		}
-		);
-
-		if(fitbits > bestfit) {
-		    best_tsi = tsi_ni;
-		    best_tsr = tsr_ni;
-		    bestfit = fitbits;
+struct connection *
+ikev2_create_narrowed_con(struct connection *c
+			, struct traffic_selector *narrowed_tsi
+			, struct traffic_selector *narrowed_tsr
+			, enum phase1_role role)
+{
+	struct connection *narrowed_con=NULL;
+	struct spd_route *tmp_spd=NULL, *tmp_spd1=NULL;
+	struct traffic_selector *tmptsi=NULL, *tmptsr=NULL;
+
+	narrowed_con = ikev2_narrow_instantiate(c);
+	
+	/* setup spds for narrowed connection*/
+	tmp_spd1 = NULL;
+	tmp_spd = &narrowed_con->spd;
+	tmptsi = narrowed_tsi;
+	
+	while(tmptsi != NULL) {
+		ip_subnet tmpsubneti;
+		rangetosubnet(&tmptsi->low, &tmptsi->high, &tmpsubneti);
+		tmptsr = narrowed_tsr;
+
+		while(tmptsr != NULL ) {
+			ip_subnet tmpsubnetr;
+			rangetosubnet(&tmptsr->low, &tmptsr->high, &tmpsubnetr);		
+
+			if(tmp_spd == NULL) {
+				struct spd_route *tmp_spd2 = clone_thing(narrowed_con->spd, "spds from narrowed ts");
+				tmp_spd = tmp_spd2;
+				tmp_spd->next = NULL;
+
+				if(tmp_spd1!= NULL){
+					tmp_spd1->next = tmp_spd;
+				}
+
+				if(tmp_spd != &narrowed_con->spd) {
+				tmp_spd->this.id.name.ptr = NULL;
+				tmp_spd->this.id.name.len = 0;
+                    		tmp_spd->that.id.name.ptr = NULL;
+                    		tmp_spd->that.id.name.len = 0;			
+
+				tmp_spd->this.host_addr_name = NULL;
+				tmp_spd->that.host_addr_name = NULL;
+
+				tmp_spd->this.updown = clone_str(tmp_spd->this.updown, "updown");
+				tmp_spd->that.updown = clone_str(tmp_spd->that.updown, "updown");
+
+				tmp_spd->this.cert_filename = NULL;
+				tmp_spd->that.cert_filename = NULL;
+
+				tmp_spd->this.cert.type = 0;
+				tmp_spd->that.cert.type = 0;
+
+				tmp_spd->this.ca.ptr = NULL;
+				tmp_spd->that.ca.ptr = NULL;
+
+				tmp_spd->this.groups = NULL;
+				tmp_spd->that.groups = NULL;
+
+				tmp_spd->this.virt = NULL;
+				tmp_spd->that.virt = NULL;
+				}
+			}
+
+			if(role == INITIATOR) {
+				tmp_spd->this.client = tmpsubneti;
+				tmp_spd->this.port = tmptsi->startport;
+				tmp_spd->this.protocol = tmptsi->ipprotoid;
+				if( subnetishost(&tmp_spd->this.client) && addrinsubnet(&tmp_spd->this.host_addr, &tmp_spd->this.client)) {
+				tmp_spd->this.has_client = FALSE;
+				}
+				else {
+				tmp_spd->this.has_client = TRUE;
+				}
+				tmp_spd->this.has_client_wildcard =  FALSE;
+				tmp_spd->this.has_port_wildcard = FALSE;
+				setportof(htons(tmp_spd->this.port), &tmp_spd->this.host_addr);
+				setportof(htons(tmp_spd->this.port), &tmp_spd->this.client.addr);
+
+				tmp_spd->that.client = tmpsubnetr;
+				tmp_spd->that.port = tmptsr->startport;
+				tmp_spd->that.protocol = tmptsr->ipprotoid;
+				if( subnetishost(&tmp_spd->that.client) && addrinsubnet(&tmp_spd->that.host_addr, &tmp_spd->that.client)) {
+				tmp_spd->that.has_client = FALSE;
+				}
+				else {
+				tmp_spd->that.has_client = TRUE;
+				}
+				tmp_spd->that.has_client_wildcard =  FALSE;
+				tmp_spd->that.has_port_wildcard = FALSE;
+				setportof(htons(tmp_spd->that.port), &tmp_spd->that.host_addr);
+				setportof(htons(tmp_spd->that.port), &tmp_spd->that.client.addr);		
+			}
+			else {
+				tmp_spd->this.client = tmpsubnetr;
+				tmp_spd->this.port = tmptsr->startport;
+				tmp_spd->this.protocol = tmptsr->ipprotoid;
+				if( subnetishost(&tmp_spd->this.client) && addrinsubnet(&tmp_spd->this.host_addr, &tmp_spd->this.client)) {
+				tmp_spd->this.has_client = FALSE;
+				}
+				else {
+				tmp_spd->this.has_client = TRUE;
+				}
+				tmp_spd->this.has_client_wildcard =  FALSE;
+				tmp_spd->this.has_port_wildcard = FALSE;
+				setportof(htons(tmp_spd->this.port), &tmp_spd->this.host_addr);
+				setportof(htons(tmp_spd->this.port), &tmp_spd->this.client.addr);
+
+				tmp_spd->that.client = tmpsubneti;
+				tmp_spd->that.port = tmptsi->startport;
+				tmp_spd->that.protocol = tmptsi->ipprotoid;
+				if( subnetishost(&tmp_spd->that.client) && addrinsubnet(&tmp_spd->that.host_addr, &tmp_spd->that.client)) {
+				tmp_spd->that.has_client = FALSE;
+				}
+				else {
+				tmp_spd->that.has_client = TRUE;
+				}
+				tmp_spd->that.has_client_wildcard =  FALSE;
+				tmp_spd->that.has_port_wildcard = FALSE;
+				setportof(htons(tmp_spd->that.port), &tmp_spd->that.host_addr);
+				setportof(htons(tmp_spd->that.port), &tmp_spd->that.client.addr);
+			}
+
+		tmp_spd1 = tmp_spd;
+		tmp_spd = tmp_spd1->next;
+		tmptsr = tmptsr->next;	
 		}
-	    }
+	tmptsi = tmptsi->next;
 	}
-    }
 
-    return bestfit;
+                    char buftest[ADDRTOT_BUF];
+                    tmp_spd = &narrowed_con->spd;
+                    int count_spd=0;
+                    do {
+                        DBG(DBG_CONTROLMORE, DBG_log("spd route number: %d", ++count_spd));
+
+                        /**that info**/
+                	DBG(DBG_CONTROLMORE, DBG_log("that id kind: %d",tmp_spd->that.id.kind));
+                	DBG(DBG_CONTROLMORE, 
+				DBG_log("that id ipaddr: %s", (addrtot(&tmp_spd->that.id.ip_addr, 0, buftest, sizeof(buftest)), buftest)));
+
+                	if (tmp_spd->that.id.name.ptr != NULL) {
+                	DBG(DBG_CONTROLMORE, DBG_dump_chunk("that id name",tmp_spd->that.id.name));
+                	}
+
+                	DBG(DBG_CONTROLMORE, 
+                            DBG_log("that host_addr: %s", (addrtot(&tmp_spd->that.host_addr, 0, buftest, sizeof(buftest)), buftest)));
+                	DBG(DBG_CONTROLMORE, 
+                            DBG_log("that nexthop: %s", (addrtot(&tmp_spd->that.host_nexthop, 0, buftest, sizeof(buftest)), buftest)));
+                        DBG(DBG_CONTROLMORE,
+                	    DBG_log("that srcip: %s", (addrtot(&tmp_spd->that.host_srcip, 0, buftest, sizeof(buftest)), buftest)));
+                        DBG(DBG_CONTROLMORE,
+                	    DBG_log("that client_addr: %s, maskbits:%d", (addrtot(&tmp_spd->that.client.addr, 0, 
+							buftest, sizeof(buftest)), buftest),tmp_spd->that.client.maskbits));
+                	DBG(DBG_CONTROLMORE, DBG_log("that has_client: %d", tmp_spd->that.has_client));
+                	DBG(DBG_CONTROLMORE, DBG_log("that has_client_wildcard: %d", tmp_spd->that.has_client_wildcard));
+                	DBG(DBG_CONTROLMORE, DBG_log("that has_port_wildcard: %d", tmp_spd->that.has_port_wildcard));
+                	DBG(DBG_CONTROLMORE, DBG_log("that has_id_wildcards: %d", tmp_spd->that.has_id_wildcards));
+
+                	/**this info**/
+                	DBG(DBG_CONTROLMORE, DBG_log("this id kind: %d",tmp_spd->this.id.kind));
+                	DBG(DBG_CONTROLMORE, 
+                            DBG_log("this id ipaddr: %s", (addrtot(&tmp_spd->this.id.ip_addr, 0, buftest, sizeof(buftest)), buftest)));
+
+                	if (tmp_spd->this.id.name.ptr != NULL) {
+                	DBG_dump_chunk("this id name",tmp_spd->this.id.name);
+                	}
+
+                	DBG(DBG_CONTROLMORE, 
+                            DBG_log("this host_addr: %s", (addrtot(&tmp_spd->this.host_addr, 0, buftest, sizeof(buftest)), buftest)));
+                	DBG(DBG_CONTROLMORE, 
+                            DBG_log("this nexthop: %s", (addrtot(&tmp_spd->this.host_nexthop, 0, buftest, sizeof(buftest)), buftest)));
+                	DBG(DBG_CONTROLMORE, 
+                            DBG_log("this srcip: %s", (addrtot(&tmp_spd->this.host_srcip, 0, buftest, sizeof(buftest)), buftest)));
+                	DBG(DBG_CONTROLMORE, DBG_log("this client_addr: %s, maskbits:%d", (addrtot(&tmp_spd->this.client.addr, 
+								0, buftest, sizeof(buftest)), buftest),tmp_spd->this.client.maskbits));
+                	DBG(DBG_CONTROLMORE, DBG_log("this has_client: %d", tmp_spd->this.has_client));
+                	DBG(DBG_CONTROLMORE, DBG_log("this has_client_wildcard: %d", tmp_spd->this.has_client_wildcard));
+                	DBG(DBG_CONTROLMORE, DBG_log("this has_port_wildcard: %d", tmp_spd->this.has_port_wildcard));
+                	DBG(DBG_CONTROLMORE, DBG_log("this has_id_wildcards: %d", tmp_spd->this.has_id_wildcards));
+
+                        tmp_spd = tmp_spd->next;
+		    } while(tmp_spd!=NULL);
+
+	return narrowed_con;
 }
 
+
+
 stf_status ikev2_child_sa_respond(struct msg_digest *md
 				  , enum phase1_role role
 				  , pb_stream *outpbs)
@@ -424,8 +1159,11 @@ stf_status ikev2_child_sa_respond(struct
     stf_status ret;
     struct payload_digest *const tsi_pd = md->chain[ISAKMP_NEXT_v2TSi];
     struct payload_digest *const tsr_pd = md->chain[ISAKMP_NEXT_v2TSr];
-    struct traffic_selector tsi[16], tsr[16];
+    struct traffic_selector tsi[16], tsr[16], *narrowed_tsi=NULL, *narrowed_tsr=NULL;
+    struct connection *narrowed_con=NULL, *result=NULL;
     unsigned int tsi_n, tsr_n;
+    bool ts_negotiation_failed = FALSE;
+
 
     st1 = duplicate_state(st);
 
@@ -436,101 +1174,44 @@ stf_status ikev2_child_sa_respond(struct
     tsi_n = ikev2_parse_ts(tsi_pd, tsi, 16);
     tsr_n = ikev2_parse_ts(tsr_pd, tsr, 16);
 
-    /*
-     * now walk through all connections and see if this connection
-     * was in fact the best.
-     *
-     * similar to find_client_connection/fc_try.
-     */
-    {
-	struct connection *b = c;
-	struct connection *d;
-	int bestfit, newfit;
-	struct spd_route *sra, *bsr;
-	struct host_pair *hp = NULL;
-
-	bsr = NULL;
-	bestfit = -1;
-	for (sra = &c->spd; sra != NULL; sra = sra->next)
-	{
-	    int bfit=ikev2_evaluate_connection_fit(c,sra,role
-						   ,tsi,tsr,tsi_n,tsr_n);
-	    if(bfit > bestfit) {
-		bestfit = bfit;
-		b = c;
-		bsr = sra;
-	    }
-	}
-
-	for (sra = &c->spd; hp==NULL && sra != NULL; sra = sra->next)
-	{
-	    hp = find_host_pair(&sra->this.host_addr
-				, sra->this.host_port
-				, &sra->that.host_addr
-				, sra->that.host_port);
-
-#ifdef DEBUG
-	    if (DBGP(DBG_CONTROLMORE))
-	    {
-		char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
-
-		subnettot(&sra->this.client, 0, s2, sizeof(s2));
-		subnettot(&sra->that.client, 0, d2, sizeof(d2));
+    if(ikev2_narrowing(c, role, tsi, tsr, tsi_n, tsr_n, &narrowed_tsi , &narrowed_tsr, &result)){
 
-		DBG_log("  checking hostpair %s -> %s is %s"
-			, s2, d2
-			, (hp ? "found" : "not found"));
-	    }
-#endif /* DEBUG */
-
-	    if(!hp) continue;
-
-	    for (d = hp->connections; d != NULL; d = d->hp_next)
-	    {
-		struct spd_route *sr;
-		int wildcards, pathlen;  /* XXX */
-		
-		if (d->policy & POLICY_GROUP)
-		    continue;
-		
-		if (!(same_id(&c->spd.this.id, &d->spd.this.id)
-		      && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
-		      && trusted_ca(c->spd.that.ca, d->spd.that.ca, &pathlen)))
-		    continue;
+	if(narrowed_tsi == NULL && narrowed_tsr == NULL && result!= NULL) {
+	/*found exact match */
+		narrowed_con = result;
+
+		/*preparing traffic selectors (need to do: free first narrowed_ts here) */
+		st1->st_ts_this= ikev2_subnettots(&result->spd.this);
+		st1->st_ts_that= ikev2_subnettots(&result->spd.that);
+	}
+	else {
+		narrowed_con = ikev2_create_narrowed_con(result, narrowed_tsi, narrowed_tsr, role);
 
-		
-		for (sr = &d->spd; sr != NULL; sr = sr->next) {
-		    newfit=ikev2_evaluate_connection_fit(d,sr,role
-							 ,tsi,tsr,tsi_n,tsr_n);
-		    if(newfit > bestfit) {
-			bestfit = newfit;
-			b=d;
-			bsr = sr;
-		    }
+		/*preparing traffic selectors (need to do: free first narrowed_ts here) */
+		if(role == INITIATOR) {
+		st1->st_ts_this= *narrowed_tsi;
+		st1->st_ts_that= *narrowed_tsr;
 		}
-	    }
-	}
-	
-	/*
-	 * now that we have found the best connection, copy the data into
-	 * the state structure as the tsi/tsr
-	 *
-	 */
-
-	/*better connection*/
-	c=b;
-
-	/* Paul: should we STF_FAIL here instead of checking for NULL */
-	if (bsr != NULL) {
-		st1->st_ts_this = ikev2_subnettots(&bsr->this);
-		st1->st_ts_that = ikev2_subnettots(&bsr->that);
+		else {
+		st1->st_ts_this= *narrowed_tsr;
+		st1->st_ts_that= *narrowed_tsi;
+		}
+
+		pfreeany(narrowed_tsi);
+		pfreeany(narrowed_tsr);
 	}
     }
+    else {
+	ts_negotiation_failed = TRUE;
+    }
+
+    if(narrowed_con!= NULL && !ts_negotiation_failed) {	
+    c = narrowed_con; 
+    }
 
     st1->st_connection = c;
+    st1->st_childsa = NULL;
     insert_state(st1);
-    md->st = st1;
-    md->pst= st;
 
     /* start of SA out */
     {
@@ -538,7 +1219,13 @@ stf_status ikev2_child_sa_respond(struct
 	notification_t rn;
 	pb_stream r_sa_pbs;
 
-	r_sa.isasa_np = ISAKMP_NEXT_v2TSi;  
+	if(ts_negotiation_failed) {
+	r_sa.isasa_np = ISAKMP_NEXT_v2N;
+	}
+	else {
+	r_sa.isasa_np = ISAKMP_NEXT_v2TSi;
+	}
+  
 	if (!out_struct(&r_sa, &ikev2_sa_desc, outpbs, &r_sa_pbs))
 	    return STF_INTERNAL_ERROR;
 
@@ -550,6 +1237,21 @@ stf_status ikev2_child_sa_respond(struct
 	    return STF_FAIL + rn;
     }
 
+    if(ts_negotiation_failed) {
+	chunk_t child_spi, notifiy_data;
+	memset(&child_spi, 0, sizeof(child_spi));
+	memset(&notifiy_data, 0, sizeof(notifiy_data));
+	ship_v2N (ISAKMP_NEXT_NONE, ISAKMP_PAYLOAD_NONCRITICAL, /*PROTO_ISAKMP*/ 0,
+			&child_spi,
+			TS_UNACCEPTABLE, &notifiy_data, outpbs);
+	change_state(st1, STATE_CHILDSA_DEL);
+	delete_state(st1);
+	return STF_OK;
+    }
+
+    md->st = st1;
+    md->pst= st;
+
     ret = ikev2_calc_emit_ts(md, outpbs, role
 			     , c, c->policy);
     if(ret != STF_OK) return ret;
@@ -590,6 +1292,8 @@ stf_status ikev2_child_sa_respond(struct
     if(!install_ipsec_sa(st1, TRUE))
 	return STF_FATAL;
 
+    st1->st_childsa = c;
+
     /* mark the connection as now having an IPsec SA associated with it. */
     st1->st_connection->newest_ipsec_sa = st1->st_serialno;
 
diff -urNp openswan-2.6.32-patched/programs/pluto/ikev2.h openswan-2.6.32-current/programs/pluto/ikev2.h
--- openswan-2.6.32-patched/programs/pluto/ikev2.h	2012-03-27 11:57:45.510034832 -0400
+++ openswan-2.6.32-current/programs/pluto/ikev2.h	2012-04-11 14:54:06.491048277 -0400
@@ -119,20 +119,44 @@ extern stf_status ikev2_verify_psk_auth(
 				   , unsigned char *idhash
 				   , pb_stream *sig_pbs);
 
+extern int ikev2_parse_ts(struct payload_digest *const ts_pd
+			, struct traffic_selector *array
+			, unsigned int array_max);
+
 extern stf_status ikev2_emit_ipsec_sa(struct msg_digest *md
 				      , pb_stream *outpbs
 				      , unsigned int np
 				      , struct connection *c
 				      , lset_t policy);
 
+extern struct connection *ikev2_create_narrowed_con(struct connection *c
+					, struct traffic_selector *narrowed_tsi
+					, struct traffic_selector *narrowed_tsr
+					, enum phase1_role role);
+
 extern void ikev2_derive_child_keys(struct state *st
 				    , enum phase1_role role);
 
+extern bool
+ikev2_perfect_match_ts(struct traffic_selector *tsi
+		,struct traffic_selector *tsr
+		, unsigned int tsi_n
+		, unsigned int tsr_n
+		, struct connection *c
+		, enum phase1_role role);
+
 extern stf_status ikev2_emit_ts(struct msg_digest *md 
 				, pb_stream *outpbs   
 				, unsigned int np
 				, struct traffic_selector *ts
 				, enum phase1_role role);
+extern void 
+ikev2_store_ts_instate(struct traffic_selector *array_tsi
+		,struct traffic_selector * array_tsr
+		, unsigned int tsi_n
+		, unsigned int tsr_n
+		, struct traffic_selector *ts_this 
+		, struct traffic_selector *ts_that);
 
 extern stf_status ikev2_calc_emit_ts(struct msg_digest *md
 				     , pb_stream *outpbs
@@ -140,6 +164,14 @@ extern stf_status ikev2_calc_emit_ts(str
 				     , struct connection *c0
 				     , lset_t policy);
 
+extern bool ikev2_verify_ts(struct traffic_selector *tsi
+			, struct traffic_selector *tsr
+			, unsigned int tsi_n
+			, unsigned int tsr_n
+			, struct traffic_selector *this_ts
+			, struct traffic_selector *that_ts
+			, enum phase1_role role);
+
 extern stf_status ikev2_child_sa_respond(struct msg_digest *md
 					 , enum phase1_role role
 					 , pb_stream *outpbs);
diff -urNp openswan-2.6.32-patched/programs/pluto/ikev2_parent.c openswan-2.6.32-current/programs/pluto/ikev2_parent.c
--- openswan-2.6.32-patched/programs/pluto/ikev2_parent.c	2012-03-27 11:57:45.523034832 -0400
+++ openswan-2.6.32-current/programs/pluto/ikev2_parent.c	2012-04-11 14:59:59.578837143 -0400
@@ -768,7 +768,7 @@ ikev2_parent_inI1outR1_tail(struct pluto
 	rn=accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs);
 	if(rn != NOTHING_WRONG) {
 	u_int16_t group_number = htons(st->st_oakley.group->group);
-	dc.ptr = (char *)&group_number;
+	dc.ptr = (u_char *)&group_number;
 	dc.len = 2;
 	SEND_NOTIFICATION_AA(INVALID_KE_PAYLOAD, &dc);
 	delete_state(st);
@@ -1417,7 +1417,7 @@ ikev2_parent_inR1outI2_tail(struct pluto
 	 * SA2i, TSi and TSr and (USE_TRANSPORT_MODE notification in transport mode) for it .
 	 */
 	if(c0) {
-		chunk_t child_spi, notifiy_data;
+	    chunk_t child_spi, notifiy_data;
 	    st->st_connection = c0;
 
 	    ikev2_emit_ipsec_sa(md,&e_pbs_cipher,ISAKMP_NEXT_v2TSi,c0, policy);
@@ -1908,6 +1908,8 @@ stf_status ikev2parent_inR2(struct msg_d
     struct connection *c = st->st_connection;
     unsigned char *idhash_in;
     struct state *pst = st;
+    struct traffic_selector tsi[16], tsr[16];
+    unsigned int tsi_n=0, tsr_n=0;
 
     if(st->st_clonedfrom != 0) {
 	pst = state_with_serialno(st->st_clonedfrom);
@@ -2015,6 +2017,28 @@ stf_status ikev2parent_inR2(struct msg_d
      */
     change_state(pst, STATE_PARENT_I3);
     c->newest_isakmp_sa = pst->st_serialno;
+
+    {
+	/*check for child sa related errors */
+	/* check for TS_UNACCEPTABLE */
+	struct payload_digest *p;
+
+	for(p = md->chain[ISAKMP_NEXT_v2N]; p != NULL; p = p->next)
+	{
+		if ( p->payload.v2n.isan_type == TS_UNACCEPTABLE ) {
+			/* we can proceed with successful parent SA */
+			if(st->st_clonedfrom != 0) {
+				delete_event(st);
+				pst = state_with_serialno(st->st_clonedfrom);
+				md->st = pst;
+				md->pst = pst;
+				delete_event(st);
+				delete_state(st);
+			}
+			return STF_OK;
+		}  
+	}
+    }
     
     /* authentication good, see if there is a child SA available */
     if(md->chain[ISAKMP_NEXT_v2SA] == NULL
@@ -2025,8 +2049,37 @@ stf_status ikev2parent_inR2(struct msg_d
 	/*
 	 * Delete previous retransmission event.
 	 */
+	if(st->st_clonedfrom != 0) {
+		pst = state_with_serialno(st->st_clonedfrom);
+		md->st = pst;
+		md->pst = pst;
+		delete_event(st);
+		delete_state(st);
+	}
+	return STF_OK;
+    }
+
+    {
+	struct payload_digest *const tsi_pd = md->chain[ISAKMP_NEXT_v2TSi];
+	struct payload_digest *const tsr_pd = md->chain[ISAKMP_NEXT_v2TSr];
+
+	/* parse traffic selector */
+
+	tsi_n = ikev2_parse_ts(tsi_pd, tsi, 16);
+	tsr_n = ikev2_parse_ts(tsr_pd, tsr, 16);
+
+	/* verify if the received traffic selectors are 
+	 * really same/or a subset of what we sent 
+	 */
+	if(ikev2_verify_ts(tsi, tsr, tsi_n, tsr_n
+			, &st->st_ts_this, &st->st_ts_that
+			, md->role) == FALSE) {
+	/* mistmatch in received selectors */
+	/*only proceeding with parent SA*/
 	delete_event(st);
 	return STF_OK;
+	}
+
     }
 
     {
@@ -2078,15 +2131,100 @@ stf_status ikev2parent_inR2(struct msg_d
 
     } /*notification block */
 
-	
-    ikev2_derive_child_keys(st, md->role);
+    {
+	/*storing received traffic selectors */
 
-    c->newest_ipsec_sa = st->st_serialno;
+	struct traffic_selector *tmp;
+	unsigned int i=0;
+
+
+	ikev2_store_ts_instate(tsi, tsr, tsi_n, tsr_n, &st->st_ts_this, &st->st_ts_that);
+
+	for(i=0; i< tsi_n; i++) {
+
+            DBG(DBG_CONTROLMORE,
+            {
+                char lbi[ADDRTOT_BUF];
+                char hbi[ADDRTOT_BUF];
+                addrtot(&tsi[i].low,  0, lbi, sizeof(lbi));
+                addrtot(&tsi[i].high, 0, hbi, sizeof(hbi));
+
+                DBG_log("tsi=%s/%s, port=%d/%d, protocol=%d"
+                        ,  lbi, hbi, tsi[i].startport, tsi[i].endport, tsi[i].ipprotoid);
+            }
+            );
+
+	}
+       
+	for(i=0; i< tsr_n; i++) {
+
+            DBG(DBG_CONTROLMORE,
+            {
+                char lbi[ADDRTOT_BUF];
+                char hbi[ADDRTOT_BUF];
+                addrtot(&tsr[i].low,  0, lbi, sizeof(lbi));
+                addrtot(&tsr[i].high, 0, hbi, sizeof(hbi));
+    
+                DBG_log("tsr=%s/%s, port=%d/%d, protocol=%d"
+                        ,  lbi, hbi, tsr[i].startport, tsr[i].endport, tsr[i].ipprotoid);
+            }
+            );
+
+	}
+
+
+	tmp = &st->st_ts_this;
+
+        while(tmp!= NULL) {
+
+            DBG(DBG_CONTROLMORE,
+            {
+                char lbi[ADDRTOT_BUF];
+                char hbi[ADDRTOT_BUF];
+                addrtot(&tmp->low,  0, lbi, sizeof(lbi));
+                addrtot(&tmp->high, 0, hbi, sizeof(hbi));
+
+                DBG_log(" R2  this  tsr=%s/%s, port=%d/%d, protocol=%d"
+                        ,  lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
+            }
+            );
+
+        tmp=tmp->next;
+        }
+
+        tmp = &st->st_ts_that;
+        while(tmp!= NULL) {
+
+            DBG(DBG_CONTROLMORE,
+            {
+                char lbi[ADDRTOT_BUF];
+                char hbi[ADDRTOT_BUF];
+                addrtot(&tmp->low,  0, lbi, sizeof(lbi));
+                addrtot(&tmp->high, 0, hbi, sizeof(hbi));
+
+                DBG_log(" R2  that  tsr=%s/%s, port=%d/%d, protocol=%d"
+                        ,  lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
+            }
+            );
+
+        tmp=tmp->next;
+        }
+
+	if(!ikev2_perfect_match_ts(tsi, tsr, tsi_n, tsr_n, c, md->role)) {
+		c = ikev2_create_narrowed_con(c, &st->st_ts_this, &st->st_ts_that, md->role);
+		st->st_connection = c;
+	}
+
+    }
+
+    ikev2_derive_child_keys(st, md->role);
 
     /* now install child SAs */
     if(!install_ipsec_sa(st, TRUE))
 	return STF_FATAL;
 
+    st->st_childsa = c;
+    c->newest_ipsec_sa = st->st_serialno;
     /*
      * Delete previous retransmission event.
      */
@@ -2408,7 +2546,6 @@ stf_status process_informational_ikev2(s
 				pb_stream del_pbs;
 				struct ikev2_delete v2del_tmp;
 				u_int16_t i, j=0;
-				bool bogus;
 				u_char *spi;
 
 				for(i = 0; i < v2del->isad_nospi; i++ ) 
@@ -2577,6 +2714,8 @@ stf_status process_informational_ikev2(s
 					else
 					{
 						change_state(current_st, STATE_IKESA_DEL);
+						md->st = NULL;
+						md->pst = NULL;
 					}
         			delete_state(current_st);
 				current_st = next_st;
@@ -2587,11 +2726,7 @@ stf_status process_informational_ikev2(s
 			case PROTO_IPSEC_AH:
 			case PROTO_IPSEC_ESP:
 				{				
-				char spi_buf[1024];
-				//pb_stream del_pbs;
-				struct ikev2_delete v2del_tmp;
 				u_int16_t i;
-				bool bogus;
 				u_char *spi;
 
 				for(i = 0; i < v2del->isad_nospi; i++ ) 
@@ -2671,6 +2806,8 @@ stf_status process_informational_ikev2(s
 					else
 					{
 						change_state(current_st, STATE_IKESA_DEL);
+						md->st = NULL;
+						md->pst = NULL;
 					}
         			delete_state(current_st);
 				current_st = next_st;
@@ -2756,8 +2893,6 @@ void ikev2_delete_out(struct state *st)
 		role = RESPONDER;
 		}
 
-		//r_hdr.isa_flags  |=  ISAKMP_FLAGS_R;
-
 		if (!out_struct(&r_hdr, &isakmp_hdr_desc, &reply_stream, &rbody))
 		{
 			openswan_log("error initializing hdr for informational message");
diff -urNp openswan-2.6.32-patched/programs/pluto/kernel.c openswan-2.6.32-current/programs/pluto/kernel.c
--- openswan-2.6.32-patched/programs/pluto/kernel.c	2012-02-15 13:36:18.922547577 -0500
+++ openswan-2.6.32-current/programs/pluto/kernel.c	2012-04-11 12:59:13.437176813 -0400
@@ -2021,6 +2021,31 @@ setup_half_ipsec_sa(struct state *st, bo
 			      , st->st_connection->policy_label
 #endif
 			      );
+
+	if(st->st_ikev2) {
+	   struct spd_route *sr = &c->spd;
+	   for(sr = sr->next; sr != NULL; sr = sr->next) {
+
+            /* MCR - should be passed a spd_eroute structure here */
+            (void) raw_eroute(&sr->that.host_addr   /* this_host */
+			      , &sr->that.client    /* this_client */
+                              , &sr->this.host_addr /* that_host */
+			      , &sr->this.client    /* that_client */
+                              , inner_spi              /* spi */
+			      , proto                  /* proto */
+                              , sr->this.protocol   /* transport_proto */
+                              , esatype                /* esatype */
+                              , proto_info             /* " */
+			      , 0                      /* lifetime */
+                              , ERO_ADD_INBOUND        /* op */
+			      , "add inbound"        /* opname */
+#ifdef HAVE_LABELED_IPSEC
+			      , st->st_connection->policy_label
+#endif
+			      );
+	   }
+	}
+
         }
     }
 
@@ -2095,6 +2120,7 @@ teardown_half_ipsec_sa(struct state *st,
      * first one found.  It may or may not be the only one.
      */
     struct connection *c = st->st_connection;
+    struct spd_route *sr;
     struct {
         unsigned proto;
         struct ipsec_proto_info *info;
@@ -2103,6 +2129,7 @@ teardown_half_ipsec_sa(struct state *st,
     bool result;
 
     i = 0;
+
     if (kernel_ops->inbound_eroute && inbound
         && c->spd.eroute_owner == SOS_NOBODY)
     {
@@ -2120,6 +2147,30 @@ teardown_half_ipsec_sa(struct state *st,
 			  );
     }
 
+    if(st->st_ikev2) {
+    for(sr = &c->spd.next; sr; sr =sr->next) {
+    if (kernel_ops->inbound_eroute && inbound
+        && sr->eroute_owner == SOS_NOBODY)
+    {
+        (void) raw_eroute(&sr->that.host_addr, &sr->that.client
+                          , &sr->this.host_addr, &sr->this.client
+                          , 256
+			  , IPSEC_PROTO_ANY
+                          , sr->this.protocol
+                          , ET_UNSPEC
+                          , null_proto_info, 0
+                          , ERO_DEL_INBOUND, "delete inbound"
+#ifdef HAVE_LABELED_IPSEC
+			  , c->policy_label
+#endif
+			  );
+    }
+    }
+    }
+
+
+
+
     if (!kernel_ops->grp_sa)
     {
         if (st->st_ah.present)
diff -urNp openswan-2.6.32-patched/programs/pluto/state.c openswan-2.6.32-current/programs/pluto/state.c
--- openswan-2.6.32-patched/programs/pluto/state.c	2012-03-27 11:57:45.531034831 -0400
+++ openswan-2.6.32-current/programs/pluto/state.c	2012-04-11 15:01:27.527784330 -0400
@@ -351,6 +351,19 @@ release_whack(struct state *st)
     close_any(st->st_whack_sock);
 }
 
+/* freeing allocated traffic selectors */
+static void delete_ts(struct traffic_selector *ts) {
+	struct traffic_selector *tmp;
+
+	/*first one is not malloced so skiping that*/
+	ts = ts-> next;
+	while(ts!=NULL) {
+		tmp = ts->next;
+		pfreeany(ts);
+		ts = tmp;
+	}
+}
+
 /* delete a state object */
 void
 delete_state(struct state *st)
@@ -511,6 +524,10 @@ delete_state(struct state *st)
 	pfreeany(st->st_sec_chunk.ptr);
     }
 
+    /*free selectors if any */
+    delete_ts(&st->st_ts_this);
+    delete_ts(&st->st_ts_that);
+
     freeanychunk(st->st_firstpacket_me);
     freeanychunk(st->st_firstpacket_him);
     freeanychunk(st->st_tpacket);
diff -urNp openswan-2.6.32-patched/programs/pluto/state.h openswan-2.6.32-current/programs/pluto/state.h
--- openswan-2.6.32-patched/programs/pluto/state.h	2012-03-27 11:57:45.532034831 -0400
+++ openswan-2.6.32-current/programs/pluto/state.h	2012-04-10 17:00:05.840320943 -0400
@@ -164,6 +164,7 @@ struct traffic_selector {
     u_int16_t endport;
     ip_address low;
     ip_address high;
+    struct traffic_selector *next;
 };
 
 #ifdef HAVE_LABELED_IPSEC
-- 
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxxx
https://admin.fedoraproject.org/mailman/listinfo/devel

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Fedora Announce]     [Fedora Kernel]     [Fedora Testing]     [Fedora Formulas]     [Fedora PHP Devel]     [Kernel Development]     [Fedora Legacy]     [Fedora Maintainers]     [Fedora Desktop]     [PAM]     [Red Hat Development]     [Gimp]     [Yosemite News]
  Powered by Linux