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(¬ifiy_data, 0, sizeof(notifiy_data));
+ ship_v2N (ISAKMP_NEXT_NONE, ISAKMP_PAYLOAD_NONCRITICAL, /*PROTO_ISAKMP*/ 0,
+ &child_spi,
+ TS_UNACCEPTABLE, ¬ifiy_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
[email protected]
https://admin.fedoraproject.org/mailman/listinfo/devel