File: | programs/pluto/ikev2_ts.c |
Warning: | line 1036, column 10 Null pointer passed as an argument to a 'nonnull' parameter |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* IKEv2 Traffic Selectors, for libreswan | |||
2 | * | |||
3 | * Copyright (C) 2007-2008 Michael Richardson <mcr@xelerance.com> | |||
4 | * Copyright (C) 2009-2010 Paul Wouters <paul@xelerance.com> | |||
5 | * Copyright (C) 2010 Tuomo Soini <tis@foobar.fi> | |||
6 | * Copyright (C) 2011-2012 Avesh Agarwal <avagarwa@redhat.com> | |||
7 | * Copyright (C) 2012-2018 Paul Wouters <pwouters@redhat.com> | |||
8 | * Copyright (C) 2012,2016-2017 Antony Antony <appu@phenome.org> | |||
9 | * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com> | |||
10 | * Copyright (C) 2014-2015, 2018 Andrew cagney <cagney@gnu.org> | |||
11 | * Copyright (C) 2017 Antony Antony <antony@phenome.org> | |||
12 | * Copyright (C) 2019 Andrew Cagney <cagney@gnu.org> | |||
13 | * | |||
14 | * This program is free software; you can redistribute it and/or modify it | |||
15 | * under the terms of the GNU General Public License as published by the | |||
16 | * Free Software Foundation; either version 2 of the License, or (at your | |||
17 | * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>. | |||
18 | * | |||
19 | * This program is distributed in the hope that it will be useful, but | |||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |||
21 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
22 | * for more details. | |||
23 | * | |||
24 | */ | |||
25 | ||||
26 | #include "defs.h" | |||
27 | ||||
28 | #include "log.h" | |||
29 | #include "ikev2_ts.h" | |||
30 | #include "connections.h" /* for struct end */ | |||
31 | #include "demux.h" | |||
32 | #include "virtual.h" | |||
33 | #include "hostpair.h" | |||
34 | #include "ip_info.h" | |||
35 | #include "ip_selector.h" | |||
36 | ||||
37 | /* | |||
38 | * While the RFC seems to suggest that the traffic selectors come in | |||
39 | * pairs, strongswan, at least, doesn't. | |||
40 | */ | |||
41 | struct traffic_selectors { | |||
42 | unsigned nr; | |||
43 | /* ??? is 16 an undocumented limit - IKEv2 has no limit */ | |||
44 | struct traffic_selector ts[16]; | |||
45 | }; | |||
46 | ||||
47 | struct ends { | |||
48 | const struct end *i; | |||
49 | const struct end *r; | |||
50 | }; | |||
51 | ||||
52 | enum fit { | |||
53 | END_EQUALS_TS = 1, | |||
54 | END_NARROWER_THAN_TS, | |||
55 | END_WIDER_THAN_TS, | |||
56 | }; | |||
57 | ||||
58 | ||||
59 | static bool_Bool ts_in_tslist(struct traffic_selectors *haystack, | |||
60 | struct traffic_selector *needle) | |||
61 | { | |||
62 | for (unsigned int i = 0; i < haystack->nr; i++) { | |||
63 | struct traffic_selector hay = haystack->ts[i]; | |||
64 | ||||
65 | if (needle->ts_type == hay.ts_type && | |||
66 | needle->ipprotoid == hay.ipprotoid && | |||
67 | needle->startport == hay.startport && | |||
68 | needle->endport == hay.endport && | |||
69 | sameaddr(&needle->net.start, &hay.net.start) && | |||
70 | sameaddr(&needle->net.end, &hay.net.end)) | |||
71 | { | |||
72 | return TRUE1; | |||
73 | } | |||
74 | } | |||
75 | return FALSE0; | |||
76 | } | |||
77 | ||||
78 | static const char *fit_string(enum fit fit) | |||
79 | { | |||
80 | switch (fit) { | |||
81 | case END_EQUALS_TS: return "=="; | |||
82 | case END_NARROWER_THAN_TS: return "<="; | |||
83 | case END_WIDER_THAN_TS: return ">="; | |||
84 | default: bad_case(fit)libreswan_bad_case("fit", (fit), (where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 84}); | |||
85 | } | |||
86 | } | |||
87 | ||||
88 | void ikev2_print_ts(const struct traffic_selector *ts) | |||
89 | { | |||
90 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
91 | DBG_log("printing contents struct traffic_selector"); | |||
92 | DBG_log(" ts_type: %s", enum_name(&ikev2_ts_type_names, ts->ts_type)); | |||
93 | DBG_log(" ipprotoid: %d", ts->ipprotoid); | |||
94 | DBG_log(" port range: %d-%d", ts->startport, ts->endport); | |||
95 | range_buf b; | |||
96 | DBG_log(" ip range: %s", str_range(&ts->net, &b)); | |||
97 | } | |||
98 | } | |||
99 | ||||
100 | /* rewrite me with address_as_{chunk,shunk}()? */ | |||
101 | struct traffic_selector ikev2_end_to_ts(const struct end *e) | |||
102 | { | |||
103 | struct traffic_selector ts; | |||
104 | ||||
105 | zero(&ts)memset((&ts), '\0', sizeof(*(&ts))); /* OK: no pointer fields */ | |||
106 | ||||
107 | switch (subnet_type(&e->client)->af) { | |||
108 | case AF_INET2: | |||
109 | ts.ts_type = IKEv2_TS_IPV4_ADDR_RANGE; | |||
110 | break; | |||
111 | case AF_INET610: | |||
112 | ts.ts_type = IKEv2_TS_IPV6_ADDR_RANGE; | |||
113 | break; | |||
114 | } | |||
115 | ||||
116 | /* subnet => range */ | |||
117 | ts.net = range_from_subnet(&e->client); | |||
118 | /* Setting ts_type IKEv2_TS_FC_ADDR_RANGE (RFC-4595) not yet supported */ | |||
119 | ||||
120 | ts.ipprotoid = e->protocol; | |||
121 | ||||
122 | /* | |||
123 | * if port is %any or 0 we mean all ports (or all iccmp/icmpv6) | |||
124 | * See RFC-5996 Section 3.13.1 handling for ICMP(1) and ICMPv6(58) | |||
125 | * we only support providing Type, not Code, eg protoport=1/1 | |||
126 | */ | |||
127 | if (e->port == 0 || e->has_port_wildcard) { | |||
128 | ts.startport = 0; | |||
129 | ts.endport = 65535; | |||
130 | } else { | |||
131 | ts.startport = e->port; | |||
132 | ts.endport = e->port; | |||
133 | } | |||
134 | ||||
135 | return ts; | |||
136 | } | |||
137 | ||||
138 | static stf_status ikev2_emit_ts(pb_stream *outpbs, | |||
139 | const struct_desc *ts_desc, | |||
140 | const struct traffic_selector *ts) | |||
141 | { | |||
142 | pb_stream ts_pbs; | |||
143 | ||||
144 | { | |||
145 | struct ikev2_ts its = { | |||
146 | .isat_critical = ISAKMP_PAYLOAD_NONCRITICAL0x00, | |||
147 | .isat_num = 1, | |||
148 | }; | |||
149 | ||||
150 | if (!out_struct(&its, ts_desc, outpbs, &ts_pbs)) | |||
151 | return STF_INTERNAL_ERROR; | |||
152 | } | |||
153 | ||||
154 | pb_stream ts_pbs2; | |||
155 | ||||
156 | { | |||
157 | struct ikev2_ts1 its1 = { | |||
158 | .isat1_ipprotoid = ts->ipprotoid, /* protocol as per local policy */ | |||
159 | .isat1_startport = ts->startport, /* ports as per local policy */ | |||
160 | .isat1_endport = ts->endport, | |||
161 | }; | |||
162 | switch (ts->ts_type) { | |||
163 | case IKEv2_TS_IPV4_ADDR_RANGE: | |||
164 | its1.isat1_type = IKEv2_TS_IPV4_ADDR_RANGE; | |||
165 | break; | |||
166 | case IKEv2_TS_IPV6_ADDR_RANGE: | |||
167 | its1.isat1_type = IKEv2_TS_IPV6_ADDR_RANGE; | |||
168 | break; | |||
169 | case IKEv2_TS_FC_ADDR_RANGE: | |||
170 | DBG_log("IKEv2 Traffic Selector IKEv2_TS_FC_ADDR_RANGE not yet supported"); | |||
171 | return STF_INTERNAL_ERROR; | |||
172 | ||||
173 | default: | |||
174 | DBG_log("IKEv2 Traffic Selector type '%d' not supported", | |||
175 | ts->ts_type); | |||
176 | return STF_INTERNAL_ERROR; /* ??? should be bad_case()? */ | |||
177 | } | |||
178 | ||||
179 | if (!out_struct(&its1, &ikev2_ts1_desc, &ts_pbs, &ts_pbs2)) | |||
180 | return STF_INTERNAL_ERROR; | |||
181 | } | |||
182 | ||||
183 | /* now do IP addresses */ | |||
184 | switch (ts->ts_type) { | |||
185 | case IKEv2_TS_IPV4_ADDR_RANGE: | |||
186 | case IKEv2_TS_IPV6_ADDR_RANGE: | |||
187 | { | |||
188 | diag_t d; | |||
189 | d = pbs_out_address(&ts_pbs2, &ts->net.start, "IP start"); | |||
190 | if (d != NULL((void*)0)) { | |||
191 | log_diag(RC_LOG_SERIOUS, outpbs->out_logger, &d, "%s", ""); | |||
192 | return STF_INTERNAL_ERROR; | |||
193 | } | |||
194 | d = pbs_out_address(&ts_pbs2, &ts->net.end, "IP end"); | |||
195 | if (d != NULL((void*)0)) { | |||
196 | log_diag(RC_LOG_SERIOUS, outpbs->out_logger, &d, "%s", ""); | |||
197 | return STF_INTERNAL_ERROR; | |||
198 | } | |||
199 | break; | |||
200 | } | |||
201 | case IKEv2_TS_FC_ADDR_RANGE: | |||
202 | DBG_log("Traffic Selector IKEv2_TS_FC_ADDR_RANGE not supported"); | |||
203 | return STF_FAIL; | |||
204 | ||||
205 | default: | |||
206 | DBG_log("Failed to create unknown IKEv2 Traffic Selector payload '%d'", | |||
207 | ts->ts_type); | |||
208 | return STF_FAIL; | |||
209 | } | |||
210 | ||||
211 | close_output_pbs(&ts_pbs2); | |||
212 | close_output_pbs(&ts_pbs); | |||
213 | ||||
214 | return STF_OK; | |||
215 | } | |||
216 | ||||
217 | static struct traffic_selector impair_ts_to_subnet(const struct traffic_selector *ts) | |||
218 | { | |||
219 | struct traffic_selector ts_ret = *ts; | |||
220 | ||||
221 | ts_ret.net.end = ts_ret.net.start; | |||
222 | ts_ret.net.is_subnet = true1; | |||
223 | ||||
224 | return ts_ret; | |||
225 | } | |||
226 | ||||
227 | ||||
228 | static struct traffic_selector impair_ts_to_supernet(const struct traffic_selector *ts) | |||
229 | { | |||
230 | struct traffic_selector ts_ret = *ts; | |||
231 | ||||
232 | if (ts_ret.ts_type == IKEv2_TS_IPV4_ADDR_RANGE) | |||
233 | ts_ret.net = range_from_subnet(&ipv4_info.all_addresses); | |||
234 | else if (ts_ret.ts_type == IKEv2_TS_IPV6_ADDR_RANGE) | |||
235 | ts_ret.net = range_from_subnet(&ipv6_info.all_addresses); | |||
236 | ||||
237 | ts_ret.net.is_subnet = true1; | |||
238 | ||||
239 | return ts_ret; | |||
240 | } | |||
241 | ||||
242 | stf_status v2_emit_ts_payloads(const struct child_sa *child, | |||
243 | pb_stream *outpbs, | |||
244 | const struct connection *c0) | |||
245 | { | |||
246 | const struct traffic_selector *ts_i, *ts_r; | |||
247 | struct traffic_selector ts_i_impaired, ts_r_impaired; | |||
248 | ||||
249 | ||||
250 | switch (child->sa.st_sa_role) { | |||
251 | case SA_INITIATOR: | |||
252 | ts_i = &child->sa.st_ts_this; | |||
253 | ts_r = &child->sa.st_ts_that; | |||
254 | if (child->sa.st_state->kind == STATE_V2_REKEY_CHILD_I0 && | |||
255 | impair.rekey_initiate_supernet) { | |||
256 | ts_i_impaired = impair_ts_to_supernet(ts_i); | |||
257 | ts_i = ts_r = &ts_i_impaired; /* supernet TSi = TSr = 0/0 */ | |||
258 | range_buf tsi_buf; | |||
259 | range_buf tsr_buf; | |||
260 | dbg("rekey-initiate-supernet TSi and TSr set to %s %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-initiate-supernet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } } | |||
261 | str_range(&ts_i->net, &tsi_buf),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-initiate-supernet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } } | |||
262 | str_range(&ts_r->net, &tsr_buf)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-initiate-supernet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } }; | |||
263 | ||||
264 | } else if (child->sa.st_state->kind == STATE_V2_REKEY_CHILD_I0 && | |||
265 | impair.rekey_initiate_subnet) { | |||
266 | ts_i_impaired = impair_ts_to_subnet(ts_i); | |||
267 | ts_r_impaired = impair_ts_to_subnet(ts_r); | |||
268 | ts_i = &ts_i_impaired; | |||
269 | ts_r = &ts_r_impaired; | |||
270 | range_buf tsi_buf; | |||
271 | range_buf tsr_buf; | |||
272 | dbg("rekey-initiate-subnet TSi and TSr set to %s %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-initiate-subnet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } } | |||
273 | str_range(&ts_i->net, &tsi_buf),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-initiate-subnet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } } | |||
274 | str_range(&ts_r->net, &tsr_buf)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-initiate-subnet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } }; | |||
275 | ||||
276 | } | |||
277 | ||||
278 | break; | |||
279 | case SA_RESPONDER: | |||
280 | ts_i = &child->sa.st_ts_that; | |||
281 | ts_r = &child->sa.st_ts_this; | |||
282 | if (child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0 && | |||
283 | impair.rekey_respond_subnet) { | |||
284 | ts_i_impaired = impair_ts_to_subnet(ts_i); | |||
285 | ts_r_impaired = impair_ts_to_subnet(ts_r); | |||
286 | ||||
287 | ts_i = &ts_i_impaired; | |||
288 | ts_r = &ts_r_impaired; | |||
289 | range_buf tsi_buf; | |||
290 | range_buf tsr_buf; | |||
291 | dbg("rekey-respond-subnet TSi and TSr set to %s %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-respond-subnet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } } | |||
292 | str_range(&ts_i->net, &tsi_buf),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-respond-subnet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } } | |||
293 | str_range(&ts_r->net, &tsr_buf)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-respond-subnet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } }; | |||
294 | } | |||
295 | if (child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0 && | |||
296 | impair.rekey_respond_supernet) { | |||
297 | ts_i_impaired = impair_ts_to_supernet(ts_i); | |||
298 | ts_i = ts_r = &ts_i_impaired; /* supernet TSi = TSr = 0/0 */ | |||
299 | range_buf tsi_buf; | |||
300 | range_buf tsr_buf; | |||
301 | dbg("rekey-respond-supernet TSi and TSr set to %s %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-respond-supernet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } } | |||
302 | str_range(&ts_i->net, &tsi_buf),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-respond-supernet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } } | |||
303 | str_range(&ts_r->net, &tsr_buf)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("rekey-respond-supernet TSi and TSr set to %s %s" , str_range(&ts_i->net, &tsi_buf), str_range(& ts_r->net, &tsr_buf)); } }; | |||
304 | } | |||
305 | break; | |||
306 | default: | |||
307 | bad_case(child->sa.st_sa_role)libreswan_bad_case("child->sa.st_sa_role", (child->sa.st_sa_role ), (where_t) { .func = __func__, .basename = "ikev2_ts.c" , . line = 307}); | |||
308 | } | |||
309 | ||||
310 | /* | |||
311 | * XXX: this looks wrong | |||
312 | * | |||
313 | * - instead of emitting two traffic selector payloads (TSi | |||
314 | * TSr) each containing all the corresponding traffic | |||
315 | * selectors, it is emitting a sequence of traffic selector | |||
316 | * payloads each containing just one traffic selector | |||
317 | * | |||
318 | * - should multiple initiator (responder) traffic selector | |||
319 | * payloads be emitted then they will all contain the same | |||
320 | * value - the loop control variable SR is never referenced | |||
321 | * | |||
322 | * - should multiple traffic selector payload be emitted then | |||
323 | * the next payload type for all but the last v2TSr payload | |||
324 | * will be wrong - it is always set to the type of the | |||
325 | * payload after these | |||
326 | */ | |||
327 | ||||
328 | for (const struct spd_route *sr = &c0->spd; sr != NULL((void*)0); | |||
329 | sr = sr->spd_next) { | |||
330 | stf_status ret = ikev2_emit_ts(outpbs, &ikev2_ts_i_desc, ts_i); | |||
331 | ||||
332 | if (ret != STF_OK) | |||
333 | return ret; | |||
334 | ret = ikev2_emit_ts(outpbs, &ikev2_ts_r_desc, ts_r); | |||
335 | if (ret != STF_OK) | |||
336 | return ret; | |||
337 | } | |||
338 | ||||
339 | return STF_OK; | |||
340 | } | |||
341 | ||||
342 | /* return success */ | |||
343 | static bool_Bool v2_parse_ts(struct payload_digest *const ts_pd, | |||
344 | struct traffic_selectors *tss, | |||
345 | const char *which) | |||
346 | { | |||
347 | dbg("%s: parsing %u traffic selectors",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: parsing %u traffic selectors", which, ts_pd ->payload.v2ts.isat_num); } } | |||
348 | which, ts_pd->payload.v2ts.isat_num){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: parsing %u traffic selectors", which, ts_pd ->payload.v2ts.isat_num); } }; | |||
349 | ||||
350 | if (ts_pd->payload.v2ts.isat_num == 0) { | |||
351 | libreswan_log("%s payload contains no entries when at least one is expected",loglog(RC_LOG, "%s payload contains no entries when at least one is expected" , which) | |||
352 | which)loglog(RC_LOG, "%s payload contains no entries when at least one is expected" , which); | |||
353 | return false0; | |||
354 | } | |||
355 | ||||
356 | if (ts_pd->payload.v2ts.isat_num >= elemsof(tss->ts)(sizeof(tss->ts) / sizeof(*(tss->ts)))) { | |||
357 | libreswan_log("%s contains %d entries which exceeds hardwired max of %zu",loglog(RC_LOG, "%s contains %d entries which exceeds hardwired max of %zu" , which, ts_pd->payload.v2ts.isat_num, (sizeof(tss->ts) / sizeof(*(tss->ts)))) | |||
358 | which, ts_pd->payload.v2ts.isat_num, elemsof(tss->ts))loglog(RC_LOG, "%s contains %d entries which exceeds hardwired max of %zu" , which, ts_pd->payload.v2ts.isat_num, (sizeof(tss->ts) / sizeof(*(tss->ts)))); | |||
359 | return false0; /* won't fit in array */ | |||
360 | } | |||
361 | ||||
362 | for (tss->nr = 0; tss->nr < ts_pd->payload.v2ts.isat_num; tss->nr++) { | |||
363 | struct traffic_selector *ts = &tss->ts[tss->nr]; | |||
364 | ||||
365 | pb_stream addr; | |||
366 | struct ikev2_ts1 ts1; | |||
367 | if (!in_struct(&ts1, &ikev2_ts1_desc, &ts_pd->pbs, &addr)) | |||
368 | return false0; | |||
369 | ||||
370 | const struct ip_info *ipv; | |||
371 | switch (ts1.isat1_type) { | |||
372 | case IKEv2_TS_IPV4_ADDR_RANGE: | |||
373 | ts->ts_type = IKEv2_TS_IPV4_ADDR_RANGE; | |||
374 | ipv = &ipv4_info; | |||
375 | break; | |||
376 | case IKEv2_TS_IPV6_ADDR_RANGE: | |||
377 | ts->ts_type = IKEv2_TS_IPV6_ADDR_RANGE; | |||
378 | ipv = &ipv6_info; | |||
379 | break; | |||
380 | default: | |||
381 | return false0; | |||
382 | } | |||
383 | ||||
384 | if (!pbs_in_address(&ts->net.start, ipv, &addr, "TS low")) { | |||
385 | return false0; | |||
386 | } | |||
387 | if (!pbs_in_address(&ts->net.end, ipv, &addr, "TS high")) { | |||
388 | return false0; | |||
389 | } | |||
390 | /* XXX: does this matter? */ | |||
391 | if (pbs_left(&addr)((size_t)((&addr)->roof - (&addr)->cur)) != 0) | |||
392 | return false0; | |||
393 | ||||
394 | ts->ipprotoid = ts1.isat1_ipprotoid; | |||
395 | ||||
396 | ts->startport = ts1.isat1_startport; | |||
397 | ts->endport = ts1.isat1_endport; | |||
398 | if (ts->startport > ts->endport) { | |||
399 | libreswan_log("%s traffic selector %d has an invalid port range",loglog(RC_LOG, "%s traffic selector %d has an invalid port range" , which, tss->nr) | |||
400 | which, tss->nr)loglog(RC_LOG, "%s traffic selector %d has an invalid port range" , which, tss->nr); | |||
401 | return false0; | |||
402 | } | |||
403 | } | |||
404 | ||||
405 | dbg("%s: parsed %d traffic selectors", which, tss->nr){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s: parsed %d traffic selectors", which, tss-> nr); } }; | |||
406 | return true1; | |||
407 | } | |||
408 | ||||
409 | static bool_Bool v2_parse_tss(const struct msg_digest *md, | |||
410 | struct traffic_selectors *tsi, | |||
411 | struct traffic_selectors *tsr) | |||
412 | { | |||
413 | if (!v2_parse_ts(md->chain[ISAKMP_NEXT_v2TSi], tsi, "TSi")) { | |||
414 | return false0; | |||
415 | } | |||
416 | ||||
417 | if (!v2_parse_ts(md->chain[ISAKMP_NEXT_v2TSr], tsr, "TSr")) { | |||
418 | return false0; | |||
419 | } | |||
420 | ||||
421 | return true1; | |||
422 | } | |||
423 | ||||
424 | #define MATCH_PREFIX" " " " | |||
425 | ||||
426 | /* | |||
427 | * Check if our policy's protocol (proto) matches the Traffic Selector | |||
428 | * protocol (ts_proto). | |||
429 | */ | |||
430 | ||||
431 | static int narrow_protocol(const struct end *end, | |||
432 | const struct traffic_selectors *tss, | |||
433 | enum fit fit, | |||
434 | const char *which, unsigned index) | |||
435 | { | |||
436 | const struct traffic_selector *ts = &tss->ts[index]; | |||
437 | int protocol = -1; | |||
438 | ||||
439 | switch (fit) { | |||
440 | case END_EQUALS_TS: | |||
441 | if (end->protocol == ts->ipprotoid) { | |||
442 | protocol = end->protocol; | |||
443 | } | |||
444 | break; | |||
445 | case END_NARROWER_THAN_TS: | |||
446 | if (ts->ipprotoid == 0 /* wild-card */ || | |||
447 | ts->ipprotoid == end->protocol) { | |||
448 | protocol = end->protocol; | |||
449 | } | |||
450 | break; | |||
451 | case END_WIDER_THAN_TS: | |||
452 | if (end->protocol == 0 /* wild-card */ || | |||
453 | end->protocol == ts->ipprotoid) { | |||
454 | protocol = ts->ipprotoid; | |||
455 | } | |||
456 | break; | |||
457 | default: | |||
458 | bad_case(fit)libreswan_bad_case("fit", (fit), (where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 458}); | |||
459 | } | |||
460 | dbg(MATCH_PREFIX "narrow protocol end=%s%d %s %s[%u]=%s%d: %d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow protocol end=%s%d %s %s[%u]=%s%d: %d" , end->protocol == 0 ? "*" : "", end->protocol, fit_string (fit), which, index, ts->ipprotoid == 0 ? "*" : "", ts-> ipprotoid, protocol); } } | |||
461 | end->protocol == 0 ? "*" : "", end->protocol,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow protocol end=%s%d %s %s[%u]=%s%d: %d" , end->protocol == 0 ? "*" : "", end->protocol, fit_string (fit), which, index, ts->ipprotoid == 0 ? "*" : "", ts-> ipprotoid, protocol); } } | |||
462 | fit_string(fit),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow protocol end=%s%d %s %s[%u]=%s%d: %d" , end->protocol == 0 ? "*" : "", end->protocol, fit_string (fit), which, index, ts->ipprotoid == 0 ? "*" : "", ts-> ipprotoid, protocol); } } | |||
463 | which, index, ts->ipprotoid == 0 ? "*" : "", ts->ipprotoid,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow protocol end=%s%d %s %s[%u]=%s%d: %d" , end->protocol == 0 ? "*" : "", end->protocol, fit_string (fit), which, index, ts->ipprotoid == 0 ? "*" : "", ts-> ipprotoid, protocol); } } | |||
464 | protocol){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow protocol end=%s%d %s %s[%u]=%s%d: %d" , end->protocol == 0 ? "*" : "", end->protocol, fit_string (fit), which, index, ts->ipprotoid == 0 ? "*" : "", ts-> ipprotoid, protocol); } }; | |||
465 | return protocol; | |||
466 | } | |||
467 | ||||
468 | static int score_narrow_protocol(const struct end *end, | |||
469 | const struct traffic_selectors *tss, | |||
470 | enum fit fit, | |||
471 | const char *which, unsigned index) | |||
472 | { | |||
473 | int f; /* strength of match */ | |||
474 | ||||
475 | int protocol = narrow_protocol(end, tss, fit, which, index); | |||
476 | if (protocol == 0) { | |||
477 | f = 255; /* ??? odd value */ | |||
478 | } else if (protocol > 0) { | |||
479 | f = 1; | |||
480 | } else { | |||
481 | f = 0; | |||
482 | } | |||
483 | LSWDBGP(DBG_BASE, buf)for (_Bool lswlog_p = (cur_debugging & (((lset_t)1 << (DBG_BASE_IX)))); lswlog_p; lswlog_p = 0) for (char lswbuf[( (size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) for (; buf != ((void*)0); jambuf_to_debug_stream (buf), buf = ((void*)0)) { | |||
484 | const struct traffic_selector *ts = &tss->ts[index]; | |||
485 | jam(buf, MATCH_PREFIX" " "match end->protocol=%s%d %s %s[%u].ipprotoid=%s%d: ", | |||
486 | end->protocol == 0 ? "*" : "", end->protocol, | |||
487 | fit_string(fit), | |||
488 | which, index, ts->ipprotoid == 0 ? "*" : "", ts->ipprotoid); | |||
489 | if (f > 0) { | |||
490 | jam(buf, "YES fitness %d", f); | |||
491 | } else { | |||
492 | jam(buf, "NO"); | |||
493 | } | |||
494 | } | |||
495 | return f; | |||
496 | } | |||
497 | ||||
498 | /* | |||
499 | * Narrow the END/TS ports according to FIT. | |||
500 | * | |||
501 | * Returns 0 (all ports), a specific port number, or -1 (no luck). | |||
502 | * | |||
503 | * Since 'struct end' only describes all-ports or a single port; only | |||
504 | * narrow to that. | |||
505 | */ | |||
506 | ||||
507 | static int narrow_port(const struct end *end, | |||
508 | const struct traffic_selectors *tss, | |||
509 | enum fit fit, | |||
510 | const char *which, unsigned index) | |||
511 | { | |||
512 | passert(index < tss->nr){ _Bool assertion__ = index < tss->nr; if (!assertion__ ) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 512}, "%s", "index < tss->nr"); } }; | |||
513 | const struct traffic_selector *ts = &tss->ts[index]; | |||
514 | ||||
515 | int end_low = end->port; | |||
516 | int end_high = end->port == 0 ? 65535 : end->port; | |||
517 | int port = -1; | |||
518 | ||||
519 | switch (fit) { | |||
520 | case END_EQUALS_TS: | |||
521 | if (end_low == ts->startport && ts->endport == end_high) { | |||
522 | /* end=ts=0-65535 || end=ts=N-N */ | |||
523 | port = end_low; | |||
524 | } | |||
525 | break; | |||
526 | case END_NARROWER_THAN_TS: | |||
527 | if (ts->startport <= end_low && end_high <= ts->endport) { | |||
528 | /* end=ts=0-65535 || ts=N<=end<=M */ | |||
529 | port = end_low; | |||
530 | } | |||
531 | break; | |||
532 | case END_WIDER_THAN_TS: | |||
533 | if (end_low < ts->startport && ts->endport < end_high && | |||
534 | ts->startport == ts->endport) { | |||
535 | /*ts=0<N-N<65535*/ | |||
536 | port = ts->startport; | |||
537 | } else if (end_low == ts->startport && ts->endport == end_high) { | |||
538 | /* end=ts=0-65535 || end=ts=N-N */ | |||
539 | port = ts->startport; | |||
540 | } | |||
541 | break; | |||
542 | default: | |||
543 | bad_case(fit)libreswan_bad_case("fit", (fit), (where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 543}); | |||
544 | } | |||
545 | dbg(MATCH_PREFIX "narrow port end=%u..%u %s %s[%u]=%u..%u: %d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow port end=%u..%u %s %s[%u]=%u..%u: %d" , end_low, end_high, fit_string(fit), which, index, ts->startport , ts->endport, port); } } | |||
546 | end_low, end_high,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow port end=%u..%u %s %s[%u]=%u..%u: %d" , end_low, end_high, fit_string(fit), which, index, ts->startport , ts->endport, port); } } | |||
547 | fit_string(fit),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow port end=%u..%u %s %s[%u]=%u..%u: %d" , end_low, end_high, fit_string(fit), which, index, ts->startport , ts->endport, port); } } | |||
548 | which, index, ts->startport, ts->endport,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow port end=%u..%u %s %s[%u]=%u..%u: %d" , end_low, end_high, fit_string(fit), which, index, ts->startport , ts->endport, port); } } | |||
549 | port){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " "narrow port end=%u..%u %s %s[%u]=%u..%u: %d" , end_low, end_high, fit_string(fit), which, index, ts->startport , ts->endport, port); } }; | |||
550 | return port; | |||
551 | } | |||
552 | ||||
553 | /* | |||
554 | * Assign a score to the narrowed port, rationale for score lost in | |||
555 | * time? | |||
556 | */ | |||
557 | ||||
558 | static int score_narrow_port(const struct end *end, | |||
559 | const struct traffic_selectors *tss, | |||
560 | enum fit fit, | |||
561 | const char *which, unsigned index) | |||
562 | { | |||
563 | int f; /* strength of match */ | |||
564 | ||||
565 | int port = narrow_port(end, tss, fit, which, index); | |||
566 | if (port > 0) { | |||
567 | f = 1; | |||
568 | } else if (port == 0) { | |||
569 | f = 65536; /* from 1 + 65535-0 */ | |||
570 | } else { | |||
571 | f = 0; | |||
572 | } | |||
573 | if (f > 0) { | |||
574 | dbg(MATCH_PREFIX " %s[%u] port match: YES fitness %d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " " %s[%u] port match: YES fitness %d" , which, index, f); } } | |||
575 | which, index, f){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " " %s[%u] port match: YES fitness %d" , which, index, f); } }; | |||
576 | } else { | |||
577 | dbg(MATCH_PREFIX " %s[%u] port match: NO",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " " %s[%u] port match: NO", which, index ); } } | |||
578 | which, index){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" " " %s[%u] port match: NO", which, index ); } }; | |||
579 | } | |||
580 | return f; | |||
581 | } | |||
582 | ||||
583 | /* | |||
584 | * Does TS fit inside of END? | |||
585 | * | |||
586 | * Given other code flips the comparison depending initiator or | |||
587 | * responder, is this right? | |||
588 | * | |||
589 | * NOTE: Our parser/config only allows 1 CIDR, however IKEv2 ranges | |||
590 | * can be non-CIDR for now we really support/limit ourselves to | |||
591 | * a single CIDR | |||
592 | * | |||
593 | * XXX: what exactly is CIDR? | |||
594 | */ | |||
595 | ||||
596 | static int score_address_range(const struct end *end, | |||
597 | const struct traffic_selectors *tss, | |||
598 | enum fit fit, | |||
599 | const char *which, unsigned index) | |||
600 | { | |||
601 | const struct traffic_selector *ts = &tss->ts[index]; | |||
602 | /* | |||
603 | * Pre-compute possible fit --- sum of bits gives how good a | |||
604 | * fit this is. | |||
605 | */ | |||
606 | int ts_range = iprange_bits(ts->net.start, ts->net.end); | |||
607 | int maskbits = end->client.maskbits; | |||
608 | int fitbits = maskbits + ts_range; | |||
609 | ||||
610 | int f = 0; | |||
611 | ||||
612 | /* | |||
613 | * NOTE: Our parser/config only allows 1 CIDR, however IKEv2 | |||
614 | * ranges can be non-CIDR for now we really | |||
615 | * support/limit ourselves to a single CIDR | |||
616 | * | |||
617 | * XXX: so what is CIDR? | |||
618 | */ | |||
619 | ip_range range = range_from_subnet(&end->client); | |||
620 | passert(addrcmp(&range.start, &range.end) <= 0){ _Bool assertion__ = addrcmp(&range.start, &range.end ) <= 0; if (!assertion__) { lsw_passert_fail((where_t) { . func = __func__, .basename = "ikev2_ts.c" , .line = 620}, "%s" , "addrcmp(&range.start, &range.end) <= 0"); } }; | |||
621 | passert(addrcmp(&ts->net.start, &ts->net.end) <= 0){ _Bool assertion__ = addrcmp(&ts->net.start, &ts-> net.end) <= 0; if (!assertion__) { lsw_passert_fail((where_t ) { .func = __func__, .basename = "ikev2_ts.c" , .line = 621} , "%s", "addrcmp(&ts->net.start, &ts->net.end) <= 0" ); } }; | |||
622 | switch (fit) { | |||
623 | case END_EQUALS_TS: | |||
624 | if (addrcmp(&range.start, &ts->net.start) == 0 && | |||
625 | addrcmp(&range.end, &ts->net.end) == 0) { | |||
626 | f = fitbits; | |||
627 | } | |||
628 | break; | |||
629 | case END_NARROWER_THAN_TS: | |||
630 | if (addrcmp(&range.start, &ts->net.start) >= 0 && | |||
631 | addrcmp(&range.end, &ts->net.end) <= 0) { | |||
632 | f = fitbits; | |||
633 | } | |||
634 | break; | |||
635 | case END_WIDER_THAN_TS: | |||
636 | if (addrcmp(&range.start, &ts->net.start) <= 0 && | |||
637 | addrcmp(&range.end, &ts->net.end) >= 0) { | |||
638 | f = fitbits; | |||
639 | } | |||
640 | break; | |||
641 | default: | |||
642 | bad_case(fit)libreswan_bad_case("fit", (fit), (where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 642}); | |||
643 | } | |||
644 | ||||
645 | /* | |||
646 | * comparing for ports for finding better local policy | |||
647 | * | |||
648 | * XXX: why do this? | |||
649 | */ | |||
650 | /* ??? arbitrary modification to objective function */ | |||
651 | if (end->port != 0 && | |||
652 | ts->startport == end->port && | |||
653 | ts->endport == end->port) | |||
654 | f = f << 1; | |||
655 | ||||
656 | LSWDBGP(DBG_BASE, buf)for (_Bool lswlog_p = (cur_debugging & (((lset_t)1 << (DBG_BASE_IX)))); lswlog_p; lswlog_p = 0) for (char lswbuf[( (size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) for (; buf != ((void*)0); jambuf_to_debug_stream (buf), buf = ((void*)0)) { | |||
657 | jam(buf, MATCH_PREFIX" " "match address end->client="); | |||
658 | jam_subnet(buf, &end->client); | |||
659 | jam(buf, " %s %s[%u]net=", fit_string(fit), which, index); | |||
660 | jam_range(buf, &ts->net); | |||
661 | jam(buf, ": "); | |||
662 | if (f > 0) { | |||
663 | jam(buf, "YES fitness %d", f); | |||
664 | } else { | |||
665 | jam(buf, "NO"); | |||
666 | } | |||
667 | } | |||
668 | return f; | |||
669 | } | |||
670 | ||||
671 | struct score { | |||
672 | bool_Bool ok; | |||
673 | int address; | |||
674 | int port; | |||
675 | int protocol; | |||
676 | }; | |||
677 | ||||
678 | static struct score score_end(const struct end *end, | |||
679 | const struct traffic_selectors *tss, | |||
680 | enum fit fit, | |||
681 | const char *what, unsigned index) | |||
682 | { | |||
683 | const struct traffic_selector *ts = &tss->ts[index]; | |||
684 | range_buf ts_net; | |||
685 | dbg(" %s[%u] .net=%s .iporotoid=%d .{start,end}port=%d..%d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" %s[%u] .net=%s .iporotoid=%d .{start,end}port=%d..%d" , what, index, str_range(&ts->net, &ts_net), ts-> ipprotoid, ts->startport, ts->endport); } } | |||
686 | what, index,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" %s[%u] .net=%s .iporotoid=%d .{start,end}port=%d..%d" , what, index, str_range(&ts->net, &ts_net), ts-> ipprotoid, ts->startport, ts->endport); } } | |||
687 | str_range(&ts->net, &ts_net),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" %s[%u] .net=%s .iporotoid=%d .{start,end}port=%d..%d" , what, index, str_range(&ts->net, &ts_net), ts-> ipprotoid, ts->startport, ts->endport); } } | |||
688 | ts->ipprotoid,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" %s[%u] .net=%s .iporotoid=%d .{start,end}port=%d..%d" , what, index, str_range(&ts->net, &ts_net), ts-> ipprotoid, ts->startport, ts->endport); } } | |||
689 | ts->startport,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" %s[%u] .net=%s .iporotoid=%d .{start,end}port=%d..%d" , what, index, str_range(&ts->net, &ts_net), ts-> ipprotoid, ts->startport, ts->endport); } } | |||
690 | ts->endport){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" %s[%u] .net=%s .iporotoid=%d .{start,end}port=%d..%d" , what, index, str_range(&ts->net, &ts_net), ts-> ipprotoid, ts->startport, ts->endport); } }; | |||
691 | ||||
692 | struct score score = { .ok = false0, }; | |||
693 | score.address = score_address_range(end, tss, fit, what, index); | |||
694 | if (score.address <= 0) { | |||
695 | return score; | |||
696 | } | |||
697 | score.port = score_narrow_port(end, tss, fit, what, index); | |||
698 | if (score.port <= 0) { | |||
699 | return score; | |||
700 | } | |||
701 | score.protocol = score_narrow_protocol(end, tss, fit, what, index); | |||
702 | if (score.protocol <= 0) { | |||
703 | return score; | |||
704 | } | |||
705 | score.ok = true1; | |||
706 | return score; | |||
707 | } | |||
708 | ||||
709 | struct best_score { | |||
710 | bool_Bool ok; | |||
711 | int address; | |||
712 | int port; | |||
713 | int protocol; | |||
714 | const struct traffic_selector *tsi; | |||
715 | const struct traffic_selector *tsr; | |||
716 | }; | |||
717 | #define NO_SCORE{ .ok = 0, .address = -1, .port = -1, .protocol = -1, } { .ok = false0, .address = -1, .port = -1, .protocol = -1, } | |||
718 | ||||
719 | static bool_Bool score_gt(const struct best_score *score, const struct best_score *best) | |||
720 | { | |||
721 | return (score->address > best->address || | |||
722 | (score->address == best->address && | |||
723 | score->port > best->port) || | |||
724 | (score->address == best->address && | |||
725 | score->port == best->port && | |||
726 | score->protocol > best->protocol)); | |||
727 | } | |||
728 | ||||
729 | static struct best_score score_ends(enum fit fit, | |||
730 | const struct connection *d, | |||
731 | const struct ends *ends, | |||
732 | const struct traffic_selectors *tsi, | |||
733 | const struct traffic_selectors *tsr) | |||
734 | { | |||
735 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
736 | selector_buf ei3; | |||
737 | selector_buf er3; | |||
738 | connection_buf cib; | |||
739 | DBG_log("evaluating our conn="PRI_CONNECTION"\"%s\"%s"" I=%s:%d/%d R=%s:%d/%d%s to their:", | |||
740 | pri_connection(d, &cib)(d)->name, str_connection_instance(d, &cib), | |||
741 | str_selector(&ends->i->client, &ei3), ends->i->protocol, ends->i->port, | |||
742 | str_selector(&ends->r->client, &er3), ends->r->protocol, ends->r->port, | |||
743 | is_virtual_connection(d) ? " (virt)" : ""); | |||
744 | } | |||
745 | ||||
746 | struct best_score best_score = NO_SCORE{ .ok = 0, .address = -1, .port = -1, .protocol = -1, }; | |||
747 | ||||
748 | /* compare tsi/r array to this/that, evaluating how well it fits */ | |||
749 | for (unsigned tsi_n = 0; tsi_n < tsi->nr; tsi_n++) { | |||
750 | const struct traffic_selector *tni = &tsi->ts[tsi_n]; | |||
751 | ||||
752 | /* choice hardwired! */ | |||
753 | struct score score_i = score_end(ends->i, tsi, fit, "TSi", tsi_n); | |||
754 | if (!score_i.ok) { | |||
755 | continue; | |||
756 | } | |||
757 | ||||
758 | for (unsigned tsr_n = 0; tsr_n < tsr->nr; tsr_n++) { | |||
759 | const struct traffic_selector *tnr = &tsr->ts[tsr_n]; | |||
760 | ||||
761 | struct score score_r = score_end(ends->r, tsr, fit, "TSr", tsr_n); | |||
762 | if (!score_r.ok) { | |||
763 | continue; | |||
764 | } | |||
765 | ||||
766 | struct best_score score = { | |||
767 | .ok = true1, | |||
768 | /* ??? this objective function is odd and arbitrary */ | |||
769 | .address = (score_i.address << 8) + score_r.address, | |||
770 | /* ??? arbitrary objective function */ | |||
771 | .port = score_i.port + score_r.port, | |||
772 | /* ??? arbitrary objective function */ | |||
773 | .protocol = score_i.protocol + score_r.protocol, | |||
774 | /* which one */ | |||
775 | .tsi = tni, .tsr = tnr, | |||
776 | }; | |||
777 | ||||
778 | /* score >= best_score? */ | |||
779 | if (score_gt(&score, &best_score)) { | |||
780 | best_score = score; | |||
781 | dbg("best fit so far: TSi[%d] TSr[%d]",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("best fit so far: TSi[%d] TSr[%d]", tsi_n, tsr_n ); } } | |||
782 | tsi_n, tsr_n){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("best fit so far: TSi[%d] TSr[%d]", tsi_n, tsr_n ); } }; | |||
783 | } | |||
784 | } | |||
785 | } | |||
786 | ||||
787 | return best_score; | |||
788 | } | |||
789 | ||||
790 | /* | |||
791 | * find the best connection and, if it is AUTH exchange, create the | |||
792 | * child state | |||
793 | * | |||
794 | * XXX: creating child as a side effect is pretty messed up. | |||
795 | */ | |||
796 | bool_Bool v2_process_ts_request(struct child_sa *child, | |||
797 | const struct msg_digest *md) | |||
798 | { | |||
799 | passert(v2_msg_role(md) == MESSAGE_REQUEST){ _Bool assertion__ = v2_msg_role(md) == MESSAGE_REQUEST; if ( !assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 799}, "%s", "v2_msg_role(md) == MESSAGE_REQUEST" ); } }; | |||
| ||||
800 | passert(child->sa.st_sa_role == SA_RESPONDER){ _Bool assertion__ = child->sa.st_sa_role == SA_RESPONDER ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 800}, "%s", "child->sa.st_sa_role == SA_RESPONDER" ); } }; | |||
801 | ||||
802 | /* | |||
803 | * XXX: md->st here is parent???? Lets find out. | |||
804 | */ | |||
805 | if (md->st == &child->sa) { | |||
806 | dbg("Child SA TS Request has child->sa == md->st; so using child connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Child SA TS Request has child->sa == md->st; so using child connection" ); } }; | |||
807 | } else if (md->st == &ike_sa(&child->sa, HERE(where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 807})->sa) { | |||
808 | dbg("Child SA TS Request has ike->sa == md->st; so using parent connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Child SA TS Request has ike->sa == md->st; so using parent connection" ); } }; | |||
809 | } else { | |||
810 | dbg("Child SA TS Request has an unknown md->st; so using unknown connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Child SA TS Request has an unknown md->st; so using unknown connection" ); } }; | |||
811 | } | |||
812 | struct connection *c = md->st->st_connection; | |||
813 | ||||
814 | struct traffic_selectors tsi = { .nr = 0, }; | |||
815 | struct traffic_selectors tsr = { .nr = 0, }; | |||
816 | if (!v2_parse_tss(md, &tsi, &tsr)) { | |||
817 | return false0; | |||
818 | } | |||
819 | ||||
820 | /* best so far; start with state's connection */ | |||
821 | struct best_score best_score = NO_SCORE{ .ok = 0, .address = -1, .port = -1, .protocol = -1, }; | |||
822 | const struct spd_route *best_spd_route = NULL((void*)0); | |||
823 | struct connection *best_connection = c; | |||
824 | ||||
825 | /* find best spd in c */ | |||
826 | ||||
827 | dbg("looking for best SPD in current connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("looking for best SPD in current connection"); } }; | |||
828 | for (const struct spd_route *sra = &c->spd; sra != NULL((void*)0); sra = sra->spd_next) { | |||
829 | ||||
830 | /* responder */ | |||
831 | const struct ends ends = { | |||
832 | .i = &sra->that, | |||
833 | .r = &sra->this, | |||
834 | }; | |||
835 | enum fit responder_fit = | |||
836 | (c->policy & POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX))) | |||
837 | ? END_NARROWER_THAN_TS | |||
838 | : END_EQUALS_TS; | |||
839 | ||||
840 | struct best_score score = score_ends(responder_fit, c, &ends, &tsi, &tsr); | |||
841 | if (!score.ok) { | |||
842 | continue; | |||
843 | } | |||
844 | if (score_gt(&score, &best_score)) { | |||
845 | dbg(" found better spd route for TSi[%td],TSr[%td]",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" found better spd route for TSi[%td],TSr[%td]" , score.tsi - tsi.ts, score.tsr - tsr.ts); } } | |||
846 | score.tsi - tsi.ts, score.tsr - tsr.ts){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" found better spd route for TSi[%td],TSr[%td]" , score.tsi - tsi.ts, score.tsr - tsr.ts); } }; | |||
847 | best_score = score; | |||
848 | best_spd_route = sra; | |||
849 | passert(best_connection == c){ _Bool assertion__ = best_connection == c; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 849}, "%s", "best_connection == c"); } }; | |||
850 | } | |||
851 | } | |||
852 | ||||
853 | /* | |||
854 | * ??? the use of hp looks nonsensical. | |||
855 | * Either the first non-empty host_pair should be used | |||
856 | * (like the current code) and the following should | |||
857 | * be broken into two loops: first find the non-empty | |||
858 | * host_pair list, second look through the host_pair list. | |||
859 | * OR | |||
860 | * what's really meant is look at the host_pair for | |||
861 | * each sra, something that matches the current | |||
862 | * nested loop structure but not what it actually does. | |||
863 | */ | |||
864 | ||||
865 | dbg("looking for better host pair"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("looking for better host pair"); } }; | |||
866 | const struct host_pair *hp = NULL((void*)0); | |||
867 | for (const struct spd_route *sra = &c->spd; | |||
868 | hp == NULL((void*)0) && sra != NULL((void*)0); sra = sra->spd_next) { | |||
869 | hp = find_host_pair(&sra->this.host_addr, | |||
870 | &sra->that.host_addr); | |||
871 | ||||
872 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
873 | selector_buf s2; | |||
874 | selector_buf d2; | |||
875 | DBG_log(" checking hostpair %s -> %s is %s", | |||
876 | str_selector(&sra->this.client, &s2), | |||
877 | str_selector(&sra->that.client, &d2), | |||
878 | hp == NULL((void*)0) ? "not found" : "found"); | |||
879 | } | |||
880 | ||||
881 | if (hp == NULL((void*)0)) | |||
882 | continue; | |||
883 | ||||
884 | for (struct connection *d = hp->connections; | |||
885 | d != NULL((void*)0); d = d->hp_next) { | |||
886 | /* groups are templates instantiated as GROUPINSTANCE */ | |||
887 | if (d->policy & POLICY_GROUP((lset_t)1 << (POLICY_GROUP_IX))) { | |||
888 | continue; | |||
889 | } | |||
890 | dbg(" investigating connection \"%s\" as a better match", d->name){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" investigating connection \"%s\" as a better match" , d->name); } }; | |||
891 | ||||
892 | /* | |||
893 | * ??? same_id && match_id seems redundant. | |||
894 | * if d->spd.this.id.kind == ID_NONE, both TRUE | |||
895 | * else if c->spd.this.id.kind == ID_NONE, | |||
896 | * same_id treats it as a wildcard and match_id | |||
897 | * does not. Odd. | |||
898 | * else if kinds differ, match_id FALSE | |||
899 | * else if kind ID_DER_ASN1_DN, wildcards are forbidden by same_id | |||
900 | * else match_id just calls same_id. | |||
901 | * So: if wildcards are desired, just use match_id. | |||
902 | * If they are not, just use same_id | |||
903 | */ | |||
904 | int wildcards; /* value ignored */ | |||
905 | int pathlen; /* value ignored */ | |||
906 | if (!(same_id(&c->spd.this.id, | |||
907 | &d->spd.this.id) && | |||
908 | match_id(&c->spd.that.id, | |||
909 | &d->spd.that.id, &wildcards) && | |||
910 | trusted_ca_nss(c->spd.that.ca, | |||
911 | d->spd.that.ca, &pathlen))) { | |||
912 | dbg(" connection \"%s\" does not match IDs or CA of current connection \"%s\"",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" connection \"%s\" does not match IDs or CA of current connection \"%s\"" , d->name, c->name); } } | |||
913 | d->name, c->name){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" connection \"%s\" does not match IDs or CA of current connection \"%s\"" , d->name, c->name); } }; | |||
914 | continue; | |||
915 | } | |||
916 | ||||
917 | const struct spd_route *sr; | |||
918 | ||||
919 | for (sr = &d->spd; sr != NULL((void*)0); sr = sr->spd_next) { | |||
920 | ||||
921 | /* responder */ | |||
922 | const struct ends ends = { | |||
923 | .i = &sr->that, | |||
924 | .r = &sr->this, | |||
925 | }; | |||
926 | /* responder -- note D! */ | |||
927 | enum fit responder_fit = | |||
928 | (d->policy & POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX))) | |||
929 | ? END_NARROWER_THAN_TS | |||
930 | : END_EQUALS_TS; | |||
931 | ||||
932 | struct best_score score = score_ends(responder_fit, d/*note D*/, | |||
933 | &ends, &tsi, &tsr); | |||
934 | if (!score.ok) { | |||
935 | continue; | |||
936 | } | |||
937 | if (score_gt(&score, &best_score)) { | |||
938 | dbg(" protocol fitness found better match d %s, TSi[%td],TSr[%td]",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" protocol fitness found better match d %s, TSi[%td],TSr[%td]" , d->name, score.tsi - tsi.ts, score.tsr - tsr.ts); } } | |||
939 | d->name,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" protocol fitness found better match d %s, TSi[%td],TSr[%td]" , d->name, score.tsi - tsi.ts, score.tsr - tsr.ts); } } | |||
940 | score.tsi - tsi.ts, score.tsr - tsr.ts){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" protocol fitness found better match d %s, TSi[%td],TSr[%td]" , d->name, score.tsi - tsi.ts, score.tsr - tsr.ts); } }; | |||
941 | best_connection = d; | |||
942 | best_score = score; | |||
943 | best_spd_route = sr; | |||
944 | } | |||
945 | } | |||
946 | } | |||
947 | } | |||
948 | ||||
949 | if (best_connection == c) { | |||
950 | dbg(" did not find a better connection using host pair"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" did not find a better connection using host pair" ); } }; | |||
951 | } | |||
952 | ||||
953 | #define CONNECTION_POLICIES(((lset_t)1 << (POLICY_NEGO_PASS_IX)) | ((lset_t)1 << (POLICY_DONT_REKEY_IX)) | ((lset_t)1 << (POLICY_REAUTH_IX )) | ((lset_t)1 << (POLICY_OPPORTUNISTIC_IX)) | ((lset_t )1 << (POLICY_GROUP_IX)) | ((lset_t)1 << (POLICY_GROUTED_IX )) | ((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | ((lset_t )1 << (POLICY_UP_IX)) | ((lset_t)1 << (POLICY_XAUTH_IX )) | ((lset_t)1 << (POLICY_MODECFG_PULL_IX)) | ((lset_t )1 << (POLICY_AGGRESSIVE_IX)) | ((lset_t)1 << (POLICY_OVERLAPIP_IX )) | ((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX))) (POLICY_NEGO_PASS((lset_t)1 << (POLICY_NEGO_PASS_IX)) | \ | |||
954 | POLICY_DONT_REKEY((lset_t)1 << (POLICY_DONT_REKEY_IX)) | \ | |||
955 | POLICY_REAUTH((lset_t)1 << (POLICY_REAUTH_IX)) | \ | |||
956 | POLICY_OPPORTUNISTIC((lset_t)1 << (POLICY_OPPORTUNISTIC_IX)) | \ | |||
957 | POLICY_GROUP((lset_t)1 << (POLICY_GROUP_IX)) | \ | |||
958 | POLICY_GROUTED((lset_t)1 << (POLICY_GROUTED_IX)) | \ | |||
959 | POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | \ | |||
960 | POLICY_UP((lset_t)1 << (POLICY_UP_IX)) | \ | |||
961 | POLICY_XAUTH((lset_t)1 << (POLICY_XAUTH_IX)) | \ | |||
962 | POLICY_MODECFG_PULL((lset_t)1 << (POLICY_MODECFG_PULL_IX)) | \ | |||
963 | POLICY_AGGRESSIVE((lset_t)1 << (POLICY_AGGRESSIVE_IX)) | \ | |||
964 | POLICY_OVERLAPIP((lset_t)1 << (POLICY_OVERLAPIP_IX)) | \ | |||
965 | POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX))) | |||
966 | ||||
967 | /* | |||
968 | * Try instantiating something better. | |||
969 | */ | |||
970 | if (best_spd_route == NULL((void*)0) && c->kind != CK_INSTANCE) { | |||
971 | /* | |||
972 | * Don't try to look for something else to | |||
973 | * 'instantiate' when the current connection is | |||
974 | * permanent. | |||
975 | * | |||
976 | * XXX: Is this missing an opportunity? Could there | |||
977 | * be a better connection to instantiate when the | |||
978 | * current one is permanent? | |||
979 | * | |||
980 | * XXX: 'instantiate', not really? The code below | |||
981 | * blats the current instance with new values - | |||
982 | * something that should not be done to a permanent | |||
983 | * connection. | |||
984 | */ | |||
985 | pexpect(c->kind == CK_PERMANENT)({ _Bool assertion__ = c->kind == CK_PERMANENT; if (!assertion__ ) { log_pexpect((where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 985}, "%s", "c->kind == CK_PERMANENT"); } assertion__ ; }); | |||
986 | dbg("no best spd route; but the current %s connection \"%s\" is not a CK_INSTANCE",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("no best spd route; but the current %s connection \"%s\" is not a CK_INSTANCE" , enum_name(&connection_kind_names, c->kind), c->name ); } } | |||
987 | enum_name(&connection_kind_names, c->kind), c->name){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("no best spd route; but the current %s connection \"%s\" is not a CK_INSTANCE" , enum_name(&connection_kind_names, c->kind), c->name ); } }; | |||
988 | } else if (best_spd_route == NULL((void*)0) && | |||
989 | ((c->policy & POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX))) || | |||
990 | c->policy & POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)))) { | |||
991 | /* | |||
992 | * Is there something better than the current | |||
993 | * connection? | |||
994 | * | |||
995 | * Rather than overwrite the current INSTANCE; would | |||
996 | * it be better to instantiate a new instance, and | |||
997 | * then replace it? Would also address the above. | |||
998 | */ | |||
999 | pexpect(c->kind == CK_INSTANCE)({ _Bool assertion__ = c->kind == CK_INSTANCE; if (!assertion__ ) { log_pexpect((where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 999}, "%s", "c->kind == CK_INSTANCE"); } assertion__ ; }); | |||
1000 | /* since an SPD_ROUTE wasn't found */ | |||
1001 | passert(best_connection == c){ _Bool assertion__ = best_connection == c; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 1001}, "%s", "best_connection == c"); } }; | |||
1002 | dbg("no best spd route; looking for a better template connection to instantiate"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("no best spd route; looking for a better template connection to instantiate" ); } }; | |||
1003 | ||||
1004 | dbg("FOR_EACH_CONNECTION_... in %s", __func__){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("FOR_EACH_CONNECTION_... in %s", __func__); } }; | |||
1005 | for (struct connection *t = connections; t != NULL((void*)0); t = t->ac_next) { | |||
1006 | /* require a template */ | |||
1007 | if (t->kind != CK_TEMPLATE) { | |||
1008 | continue; | |||
1009 | } | |||
1010 | LSWDBGP(DBG_BASE, buf)for (_Bool lswlog_p = (cur_debugging & (((lset_t)1 << (DBG_BASE_IX)))); lswlog_p; lswlog_p = 0) for (char lswbuf[( (size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) for (; buf != ((void*)0); jambuf_to_debug_stream (buf), buf = ((void*)0)) { | |||
1011 | jam(buf, " investigating template \"%s\";", | |||
1012 | t->name); | |||
1013 | if (t->foodgroup != NULL((void*)0)) { | |||
1014 | jam(buf, " food-group=\"%s\"", t->foodgroup); | |||
1015 | } | |||
1016 | jam(buf, " policy=%s", prettypolicy(t->policy & CONNECTION_POLICIES(((lset_t)1 << (POLICY_NEGO_PASS_IX)) | ((lset_t)1 << (POLICY_DONT_REKEY_IX)) | ((lset_t)1 << (POLICY_REAUTH_IX )) | ((lset_t)1 << (POLICY_OPPORTUNISTIC_IX)) | ((lset_t )1 << (POLICY_GROUP_IX)) | ((lset_t)1 << (POLICY_GROUTED_IX )) | ((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | ((lset_t )1 << (POLICY_UP_IX)) | ((lset_t)1 << (POLICY_XAUTH_IX )) | ((lset_t)1 << (POLICY_MODECFG_PULL_IX)) | ((lset_t )1 << (POLICY_AGGRESSIVE_IX)) | ((lset_t)1 << (POLICY_OVERLAPIP_IX )) | ((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX))))); | |||
1017 | } | |||
1018 | ||||
1019 | /* | |||
1020 | * Is it worth looking at the template. | |||
1021 | * | |||
1022 | * XXX: treat the combination the same as | |||
1023 | * group instance, like the old code did; is | |||
1024 | * this valid? | |||
1025 | */ | |||
1026 | switch (c->policy & (POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | | |||
1027 | POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)))) { | |||
1028 | case POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)): | |||
1029 | case POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)): /* XXX: true */ | |||
1030 | /* XXX: why does this matter; does it imply t->foodgroup != NULL? */ | |||
1031 | if (!LIN(POLICY_GROUPINSTANCE, t->policy)(((((lset_t)1 << (POLICY_GROUPINSTANCE_IX))) & (t-> policy)) == (((lset_t)1 << (POLICY_GROUPINSTANCE_IX))))) { | |||
1032 | dbg(" skipping; not a group instance"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; not a group instance"); } }; | |||
1033 | continue; | |||
1034 | } | |||
1035 | /* when OE, don't change food groups? */ | |||
1036 | if (!streq(c->foodgroup, t->foodgroup)(strcmp((c->foodgroup), (t->foodgroup)) == 0)) { | |||
| ||||
1037 | dbg(" skipping; wrong foodgroup name"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; wrong foodgroup name"); } }; | |||
1038 | continue; | |||
1039 | } | |||
1040 | /* ??? why require current connection->name and t->name to be different */ | |||
1041 | /* XXX: don't re-instantiate the same connection template???? */ | |||
1042 | if (streq(c->name, t->name)(strcmp((c->name), (t->name)) == 0)) { | |||
1043 | dbg(" skipping; name same as current connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; name same as current connection" ); } }; | |||
1044 | continue; | |||
1045 | } | |||
1046 | break; | |||
1047 | case POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)): | |||
1048 | if (!LIN(POLICY_IKEV2_ALLOW_NARROWING, t->policy)(((((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX))) & (t->policy)) == (((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX ))))) { | |||
1049 | dbg(" skipping; cannot narrow"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; cannot narrow"); } }; | |||
1050 | continue; | |||
1051 | } | |||
1052 | break; | |||
1053 | default: | |||
1054 | bad_case(c->policy)libreswan_bad_case("c->policy", (c->policy), (where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 1054}); /* not quite true */ | |||
1055 | } | |||
1056 | ||||
1057 | /* require initiator's subnet <= T; why? */ | |||
1058 | if (!subnetinsubnet(&c->spd.that.client, &t->spd.that.client)) { | |||
1059 | dbg(" skipping; current connection's initiator subnet is not <= template"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; current connection's initiator subnet is not <= template" ); } }; | |||
1060 | continue; | |||
1061 | } | |||
1062 | /* require responder address match; why? */ | |||
1063 | if (!sameaddr(&c->spd.this.client.addr, &t->spd.this.client.addr)) { | |||
1064 | dbg(" skipping; responder addresses don't match"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; responder addresses don't match" ); } }; | |||
1065 | continue; | |||
1066 | } | |||
1067 | ||||
1068 | /* require a valid narrowed port? */ | |||
1069 | enum fit fit; | |||
1070 | switch (c->policy & (POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | | |||
1071 | POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)))) { | |||
1072 | case POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)): | |||
1073 | case POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)): /* XXX: true */ | |||
1074 | /* exact match; XXX: 'cos that is what old code did */ | |||
1075 | fit = END_EQUALS_TS; | |||
1076 | break; | |||
1077 | case POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)): | |||
1078 | /* narrow END's port to TS port */ | |||
1079 | fit = END_WIDER_THAN_TS; | |||
1080 | break; | |||
1081 | default: | |||
1082 | bad_case(c->policy)libreswan_bad_case("c->policy", (c->policy), (where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 1082}); | |||
1083 | } | |||
1084 | ||||
1085 | passert(tsi.nr >= 1){ _Bool assertion__ = tsi.nr >= 1; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 1085}, "%s", "tsi.nr >= 1"); } }; | |||
1086 | int tsi_port = narrow_port(&t->spd.that, &tsi, | |||
1087 | fit, "TSi", 0); | |||
1088 | if (tsi_port < 0) { | |||
1089 | dbg(" skipping; TSi port too wide"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; TSi port too wide"); } }; | |||
1090 | continue; | |||
1091 | } | |||
1092 | int tsi_protocol = narrow_protocol(&t->spd.that, &tsi, | |||
1093 | fit, "TSi", 0); | |||
1094 | if (tsi_protocol < 0) { | |||
1095 | dbg(" skipping; TSi protocol too wide"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; TSi protocol too wide"); } }; | |||
1096 | continue; | |||
1097 | } | |||
1098 | ||||
1099 | passert(tsr.nr >= 1){ _Bool assertion__ = tsr.nr >= 1; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 1099}, "%s", "tsr.nr >= 1"); } }; | |||
1100 | int tsr_port = narrow_port(&t->spd.this, &tsr, | |||
1101 | fit, "TRi", 0); | |||
1102 | if (tsr_port < 0) { | |||
1103 | dbg(" skipping; TSr port too wide"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; TSr port too wide"); } }; | |||
1104 | continue; | |||
1105 | } | |||
1106 | int tsr_protocol = narrow_protocol(&t->spd.this, &tsr, | |||
1107 | fit, "TSr", 0); | |||
1108 | if (tsr_protocol < 0) { | |||
1109 | dbg(" skipping; TSr protocol too wide"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" skipping; TSr protocol too wide"); } }; | |||
1110 | continue; | |||
1111 | } | |||
1112 | ||||
1113 | passert(best_connection == c){ _Bool assertion__ = best_connection == c; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev2_ts.c" , .line = 1113}, "%s", "best_connection == c"); } }; /* aka st->st_connection, no leak */ | |||
1114 | ||||
1115 | bool_Bool shared = v2_child_connection_probably_shared(child); | |||
1116 | if (shared) { | |||
1117 | /* instantiate it, filling in peer's ID */ | |||
1118 | best_connection = instantiate(t, &c->spd.that.host_addr, | |||
1119 | NULL((void*)0)); | |||
1120 | } | |||
1121 | ||||
1122 | /* "this" == responder; see function name */ | |||
1123 | best_connection->spd.this.port = tsr_port; | |||
1124 | best_connection->spd.that.port = tsi_port; | |||
1125 | best_connection->spd.this.protocol = tsr_protocol; | |||
1126 | best_connection->spd.that.protocol = tsi_protocol; | |||
1127 | best_spd_route = &best_connection->spd; | |||
1128 | ||||
1129 | if (shared) { | |||
1130 | char old[CONN_INST_BUF(2 + 10 + 1 + sizeof(subnet_buf) + 7 + sizeof(address_reversed_buf ) + 3 + sizeof(subnet_buf) + 1 + 1)]; | |||
1131 | char new[CONN_INST_BUF(2 + 10 + 1 + sizeof(subnet_buf) + 7 + sizeof(address_reversed_buf ) + 3 + sizeof(subnet_buf) + 1 + 1)]; | |||
1132 | dbg("switching from \"%s\"%s to \"%s\"%s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("switching from \"%s\"%s to \"%s\"%s", c->name , fmt_conn_instance(c, old), best_connection->name, fmt_conn_instance (best_connection, new)); } } | |||
1133 | c->name, fmt_conn_instance(c, old),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("switching from \"%s\"%s to \"%s\"%s", c->name , fmt_conn_instance(c, old), best_connection->name, fmt_conn_instance (best_connection, new)); } } | |||
1134 | best_connection->name, fmt_conn_instance(best_connection, new)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("switching from \"%s\"%s to \"%s\"%s", c->name , fmt_conn_instance(c, old), best_connection->name, fmt_conn_instance (best_connection, new)); } }; | |||
1135 | } else { | |||
1136 | char cib[CONN_INST_BUF(2 + 10 + 1 + sizeof(subnet_buf) + 7 + sizeof(address_reversed_buf ) + 3 + sizeof(subnet_buf) + 1 + 1)]; | |||
1137 | dbg(" overwrote connection with instance %s%s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" overwrote connection with instance %s%s", best_connection ->name, fmt_conn_instance(best_connection, cib)); } } | |||
1138 | best_connection->name, fmt_conn_instance(best_connection, cib)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" overwrote connection with instance %s%s", best_connection ->name, fmt_conn_instance(best_connection, cib)); } }; | |||
1139 | } | |||
1140 | break; | |||
1141 | } | |||
1142 | } | |||
1143 | ||||
1144 | if (best_spd_route == NULL((void*)0)) { | |||
1145 | dbg("giving up"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("giving up"); } }; | |||
1146 | return false0; | |||
1147 | } | |||
1148 | ||||
1149 | /* | |||
1150 | * this both replaces the child's connection, and flips any | |||
1151 | * underlying current-connection | |||
1152 | * | |||
1153 | * XXX: but this is responder code, there probably isn't a | |||
1154 | * current-connection - it would have gone straight to current | |||
1155 | * state. | |||
1156 | * | |||
1157 | * XXX: ah, but the state code does: set-state; set-connection | |||
1158 | * (yes order is wrong). Why does it bother? | |||
1159 | * | |||
1160 | * update_state_connection(), if the connection changes, | |||
1161 | * de-references the old connection; which is what really | |||
1162 | * matters | |||
1163 | */ | |||
1164 | update_state_connection(&child->sa, best_connection); | |||
1165 | ||||
1166 | child->sa.st_ts_this = ikev2_end_to_ts(&best_spd_route->this); | |||
1167 | child->sa.st_ts_that = ikev2_end_to_ts(&best_spd_route->that); | |||
1168 | ||||
1169 | ikev2_print_ts(&child->sa.st_ts_this); | |||
1170 | ikev2_print_ts(&child->sa.st_ts_that); | |||
1171 | ||||
1172 | return true1; | |||
1173 | } | |||
1174 | ||||
1175 | /* check TS payloads, response */ | |||
1176 | bool_Bool v2_process_ts_response(struct child_sa *child, | |||
1177 | struct msg_digest *md) | |||
1178 | { | |||
1179 | passert(child->sa.st_sa_role == SA_INITIATOR){ _Bool assertion__ = child->sa.st_sa_role == SA_INITIATOR ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 1179}, "%s", "child->sa.st_sa_role == SA_INITIATOR" ); } }; | |||
1180 | passert(v2_msg_role(md) == MESSAGE_RESPONSE){ _Bool assertion__ = v2_msg_role(md) == MESSAGE_RESPONSE; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 1180}, "%s", "v2_msg_role(md) == MESSAGE_RESPONSE" ); } }; | |||
1181 | ||||
1182 | struct connection *c = child->sa.st_connection; | |||
1183 | ||||
1184 | struct traffic_selectors tsi = { .nr = 0, }; | |||
1185 | struct traffic_selectors tsr = { .nr = 0, }; | |||
1186 | if (!v2_parse_tss(md, &tsi, &tsr)) { | |||
1187 | return false0; | |||
1188 | } | |||
1189 | ||||
1190 | /* initiator */ | |||
1191 | const struct spd_route *sra = &c->spd; | |||
1192 | const struct ends e = { | |||
1193 | .i = &sra->this, | |||
1194 | .r = &sra->that, | |||
1195 | }; | |||
1196 | enum fit initiator_widening = | |||
1197 | (c->policy & POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX))) | |||
1198 | ? END_WIDER_THAN_TS | |||
1199 | : END_EQUALS_TS; | |||
1200 | ||||
1201 | struct best_score best = score_ends(initiator_widening, c, &e, &tsi, &tsr); | |||
1202 | ||||
1203 | if (!best.ok) { | |||
1204 | dbg("reject responder TSi/TSr Traffic Selector"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("reject responder TSi/TSr Traffic Selector"); } }; | |||
1205 | /* prevents parent from going to I3 */ | |||
1206 | return false0; | |||
1207 | } | |||
1208 | ||||
1209 | dbg("found an acceptable TSi/TSr Traffic Selector"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("found an acceptable TSi/TSr Traffic Selector" ); } }; | |||
1210 | struct state *st = &child->sa; | |||
1211 | memcpy(&st->st_ts_this, best.tsi, | |||
1212 | sizeof(struct traffic_selector)); | |||
1213 | memcpy(&st->st_ts_that, best.tsr, | |||
1214 | sizeof(struct traffic_selector)); | |||
1215 | ikev2_print_ts(&st->st_ts_this); | |||
1216 | ikev2_print_ts(&st->st_ts_that); | |||
1217 | ||||
1218 | ip_subnet tmp_subnet_i; | |||
1219 | ip_subnet tmp_subnet_r; | |||
1220 | rangetosubnet(&st->st_ts_this.net.start, | |||
1221 | &st->st_ts_this.net.end, &tmp_subnet_i); | |||
1222 | rangetosubnet(&st->st_ts_that.net.start, | |||
1223 | &st->st_ts_that.net.end, &tmp_subnet_r); | |||
1224 | ||||
1225 | c->spd.this.client = tmp_subnet_i; | |||
1226 | c->spd.this.port = st->st_ts_this.startport; | |||
1227 | c->spd.this.protocol = st->st_ts_this.ipprotoid; | |||
1228 | setportof(htons(c->spd.this.port),{ *(&c->spd.this.client.addr) = set_endpoint_hport((& c->spd.this.client.addr), ntohs(htons(c->spd.this.port) )); } | |||
1229 | &c->spd.this.client.addr){ *(&c->spd.this.client.addr) = set_endpoint_hport((& c->spd.this.client.addr), ntohs(htons(c->spd.this.port) )); }; | |||
1230 | ||||
1231 | c->spd.this.has_client = | |||
1232 | !(subnetishost(&c->spd.this.client) && | |||
1233 | addrinsubnet(&c->spd.this.host_addr, | |||
1234 | &c->spd.this.client)); | |||
1235 | ||||
1236 | c->spd.that.client = tmp_subnet_r; | |||
1237 | c->spd.that.port = st->st_ts_that.startport; | |||
1238 | c->spd.that.protocol = st->st_ts_that.ipprotoid; | |||
1239 | setportof(htons(c->spd.that.port),{ *(&c->spd.that.client.addr) = set_endpoint_hport((& c->spd.that.client.addr), ntohs(htons(c->spd.that.port) )); } | |||
1240 | &c->spd.that.client.addr){ *(&c->spd.that.client.addr) = set_endpoint_hport((& c->spd.that.client.addr), ntohs(htons(c->spd.that.port) )); }; | |||
1241 | ||||
1242 | c->spd.that.has_client = | |||
1243 | !(subnetishost(&c->spd.that.client) && | |||
1244 | addrinsubnet(&c->spd.that.host_addr, | |||
1245 | &c->spd.that.client)); | |||
1246 | ||||
1247 | return true1; | |||
1248 | } | |||
1249 | ||||
1250 | /* | |||
1251 | * RFC 7296 https://tools.ietf.org/html/rfc7296#section-2.8 | |||
1252 | * "when rekeying, the new Child SA SHOULD NOT have different Traffic | |||
1253 | * Selectors and algorithms than the old one." | |||
1254 | * | |||
1255 | * We already matched the right connection by the SPI of v2N_REKEY_SA | |||
1256 | */ | |||
1257 | bool_Bool child_rekey_ts_verify(struct child_sa *child, struct msg_digest *md) | |||
1258 | { | |||
1259 | if (!pexpect(child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0 ||({ _Bool assertion__ = child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0 || child->sa.st_state->kind == STATE_V2_REKEY_CHILD_I1 ; if (!assertion__) { log_pexpect((where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 1260}, "%s", "child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0 || child->sa.st_state->kind == STATE_V2_REKEY_CHILD_I1" ); } assertion__; }) | |||
1260 | child->sa.st_state->kind == STATE_V2_REKEY_CHILD_I1)({ _Bool assertion__ = child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0 || child->sa.st_state->kind == STATE_V2_REKEY_CHILD_I1 ; if (!assertion__) { log_pexpect((where_t) { .func = __func__ , .basename = "ikev2_ts.c" , .line = 1260}, "%s", "child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0 || child->sa.st_state->kind == STATE_V2_REKEY_CHILD_I1" ); } assertion__; })) { | |||
1261 | return false0; | |||
1262 | } | |||
1263 | ||||
1264 | struct traffic_selectors their_tsis = { .nr = 0, }; | |||
1265 | struct traffic_selectors their_tsrs = { .nr = 0, }; | |||
1266 | enum message_role md_role = v2_msg_role(md); | |||
1267 | ||||
1268 | if (!v2_parse_tss(md, &their_tsis, &their_tsrs)) { | |||
1269 | log_state(RC_LOG_SERIOUS, &child->sa, "received malformed TSi/TSr payload(s)"); | |||
1270 | return false0; | |||
1271 | } | |||
1272 | ||||
1273 | struct traffic_selector ts_this = ikev2_end_to_ts(&child->sa.st_connection->spd.this); | |||
1274 | struct traffic_selector ts_that = ikev2_end_to_ts(&child->sa.st_connection->spd.that); | |||
1275 | ||||
1276 | if (!ts_in_tslist(&their_tsis, (md_role == MESSAGE_REQUEST) ? &ts_that : &ts_this)) { | |||
1277 | log_state(RC_LOG_SERIOUS, &child->sa, | |||
1278 | "received TSi payload does not contain existing IPsec SA traffic Selectors"); | |||
1279 | return false0; | |||
1280 | } | |||
1281 | ||||
1282 | if (!ts_in_tslist(&their_tsrs, (md_role == MESSAGE_REQUEST) ? &ts_this : &ts_that)) { | |||
1283 | log_state(RC_LOG_SERIOUS, &child->sa, "received TSr payload(s) does not contain existing IPsec SA Traffic Selectors"); | |||
1284 | return false0; | |||
1285 | } | |||
1286 | return true1; | |||
1287 | } |