Bug Summary

File:programs/pluto/ikev2_ts.c
Warning:line 1222, column 8
Access to field 'ike_version' results in a dereference of a null pointer (loaded from variable 'c')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ikev2_ts.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/build/quick-libreswan-2/programs/pluto -resource-dir /usr/lib64/clang/13.0.0 -D TimeZoneOffset=timezone -D PIE -D NSS_IPSEC_PROFILE -D XFRM_LIFETIME_DEFAULT=30 -D USE_IKEv1 -D XFRM_SUPPORT -D USE_XFRM_INTERFACE -D USE_DNSSEC -D DEFAULT_DNSSEC_ROOTKEY_FILE="/var/lib/unbound/root.key" -D HAVE_LABELED_IPSEC -D HAVE_SECCOMP -D LIBCURL -D USE_LINUX_AUDIT -D HAVE_NM -D USE_PAM_AUTH -D USE_3DES -D USE_AES -D USE_CAMELLIA -D USE_CHACHA -D USE_DH31 -D USE_MD5 -D USE_SHA1 -D USE_SHA2 -D USE_PRF_AES_XCBC -D USE_NSS_KDF -D DEFAULT_RUNDIR="/run/pluto" -D IPSEC_CONF="/etc/ipsec.conf" -D IPSEC_CONFDDIR="/etc/ipsec.d" -D IPSEC_NSSDIR="/var/lib/ipsec/nss" -D IPSEC_CONFDIR="/etc" -D IPSEC_EXECDIR="/usr/local/libexec/ipsec" -D IPSEC_SBINDIR="/usr/local/sbin" -D IPSEC_VARDIR="/var" -D POLICYGROUPSDIR="/etc/ipsec.d/policies" -D IPSEC_SECRETS_FILE="/etc/ipsec.secrets" -D FORCE_PR_ASSERT -D USE_FORK=1 -D USE_VFORK=0 -D USE_DAEMON=0 -D USE_PTHREAD_SETSCHEDPRIO=1 -D GCC_LINT -D HAVE_LIBCAP_NG -I . -I ../../OBJ.linux.x86_64/programs/pluto -I ../../include -I /usr/include/nss3 -I /usr/include/nspr4 -I /home/build/quick-libreswan-2/programs/pluto/linux-copy -D HERE_FILENAME="programs/pluto/ikev2_ts.c" -internal-isystem /usr/lib64/clang/13.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/11/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu99 -fdebug-compilation-dir=/home/build/quick-libreswan-2/programs/pluto -ferror-limit 19 -stack-protector 3 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-01-01-205714-1273399-1 -x c /home/build/quick-libreswan-2/programs/pluto/ikev2_ts.c
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 * Copyright (C) 2021 Paul Wouters <paul.wouters@aiven.io>
14 *
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 2 of the License, or (at your
18 * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * for more details.
24 *
25 */
26
27#include "defs.h"
28
29#include "log.h"
30#include "ikev2_ts.h"
31#include "connections.h" /* for struct end */
32#include "demux.h"
33#include "virtual_ip.h"
34#include "host_pair.h"
35#include "ip_info.h"
36#include "ip_selector.h"
37#include "labeled_ipsec.h"
38#include "ip_range.h"
39#include "iface.h"
40#include "pending.h" /* for connection_is_pending() */
41#include "state_db.h" /* for FOR_EACH_STATE_NEW2OLD() */
42
43/*
44 * While the RFC seems to suggest that the traffic selectors come in
45 * pairs, strongswan, at least, doesn't.
46 */
47
48struct traffic_selectors {
49 const char *name;
50 bool_Bool contains_sec_label;
51 unsigned nr;
52 /* ??? is 16 an undocumented limit - IKEv2 has no limit */
53 struct traffic_selector ts[16];
54};
55
56struct traffic_selector_payloads {
57 struct traffic_selectors i;
58 struct traffic_selectors r;
59};
60
61static const struct traffic_selector_payloads empty_traffic_selectors = {
62 .i = {
63 .name = "TSi",
64 },
65 .r = {
66 .name = "TSr",
67 },
68};
69
70struct ends {
71 const struct end *i;
72 const struct end *r;
73};
74
75enum fit {
76 END_EQUALS_TS = 1,
77 END_NARROWER_THAN_TS,
78 END_WIDER_THAN_TS,
79};
80
81
82static const char *fit_string(enum fit fit)
83{
84 switch (fit) {
85 case END_EQUALS_TS: return "==";
86 case END_NARROWER_THAN_TS: return "<=";
87 case END_WIDER_THAN_TS: return ">=";
88 default: bad_case(fit)libreswan_bad_case("fit", (fit), ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 88, }; &here; }))
;
89 }
90}
91
92void dbg_v2_ts(const struct traffic_selector *ts, const char *prefix, ...)
93{
94 if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) {
95 va_list ap;
96 va_start(ap, prefix)__builtin_va_start(ap, prefix);
97 DBG_va_list(prefix, ap);
98 va_end(ap)__builtin_va_end(ap);
99 DBG_log(" ts_type: %s", enum_name(&ikev2_ts_type_names, ts->ts_type));
100 DBG_log(" ipprotoid: %d", ts->ipprotoid);
101 DBG_log(" port range: %d-%d", ts->startport, ts->endport);
102 range_buf b;
103 DBG_log(" ip range: %s", str_range(&ts->net, &b));
104 DBG_log(" sec_label: "PRI_SHUNK"%.*s", pri_shunk(ts->sec_label)((int) (ts->sec_label).len), (const char *) ((ts->sec_label
).ptr)
);
105 }
106}
107
108static void traffic_selector_to_end(const struct traffic_selector *ts, struct end *end,
109 const char *story)
110{
111 dbg_v2_ts(ts, "%s() %s", __func__, story);
112 ip_subnet subnet;
113 happy(range_to_subnet(ts->net, &subnet)){ err_t ugh = range_to_subnet(ts->net, &subnet); if (ugh
!= ((void*)0)) { llog_passert(&failsafe_logger, ({ static
const struct where here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 113, }; &here; }), "%s", ugh); } }
;
114 const ip_protocol *protocol = protocol_by_ipproto(ts->ipprotoid);
115 /* XXX: check port range valid */
116 ip_port port = ip_hport(ts->startport);
117 end->client = selector_from_subnet_protocol_port(subnet, protocol, port);
118 /* redundant */
119 end->port = ts->startport;
120 end->protocol = ts->ipprotoid;
121 end->has_client = !selector_eq_address(end->client, end->host_addr);
122}
123
124/* rewrite me with address_as_{chunk,shunk}()? */
125/* For now, note the struct traffic_selector can contain
126 * two selectors - an IPvX range and a sec_label
127 */
128struct traffic_selector traffic_selector_from_end(const struct end *e, const char *what)
129{
130 struct traffic_selector ts = {
131 /*
132 * Setting ts_type IKEv2_TS_FC_ADDR_RANGE (RFC-4595)
133 * not yet supported.
134 */
135 .ts_type = selector_type(&e->client)->ikev2_ts_addr_range_type,
136 /* subnet => range */
137 .net = selector_range(e->client),
138 .ipprotoid = e->protocol,
139 /*
140 * Use the 'instance/narrowed' label from the ACQUIRE
141 * and stored in the connection instance's sends, if
142 * present.
143 */
144 .sec_label = HUNK_AS_SHUNK(e->sec_label)({ typeof(e->sec_label) h_ = (e->sec_label); shunk2(h_.
ptr, h_.len); })
,
145 };
146
147 /*
148 * if port is %any or 0 we mean all ports (or all
149 * iccmp/icmpv6).
150 *
151 * See RFC-5996 Section 3.13.1 handling for ICMP(1) and
152 * ICMPv6(58) we only support providing Type, not Code, eg
153 * protoport=1/1
154 */
155 if (e->port == 0 || e->has_port_wildcard) {
156 ts.startport = 0;
157 ts.endport = 65535;
158 } else {
159 ts.startport = e->port;
160 ts.endport = e->port;
161 }
162
163 dbg_v2_ts(&ts, "%s TS", what);
164 return ts;
165}
166
167/*
168 * A struct end is converted to a struct traffic_selector.
169 *
170 * This (currently) can contain both an IP range AND a SEC_LABEL,
171 * which will get output here as two Traffic Selectors. The label is
172 * optional, the IP range is mandatory.
173 */
174static stf_status emit_v2TS(struct pbs_outpacket_byte_stream *outpbs,
175 const struct_desc *ts_desc,
176 const struct traffic_selector *ts)
177{
178 struct pbs_outpacket_byte_stream ts_pbs;
179 bool_Bool with_label = (ts->sec_label.len > 0);
180
181 if (ts->ts_type != IKEv2_TS_IPV4_ADDR_RANGE &&
182 ts->ts_type != IKEv2_TS_IPV6_ADDR_RANGE) {
183 return STF_INTERNAL_ERROR;
184 }
185
186 {
187 struct ikev2_ts its = {
188 .isat_critical = ISAKMP_PAYLOAD_NONCRITICAL0x00,
189 /*
190 * If there is a security label in the Traffic
191 * Selector, then we must send a TS_SECLABEL
192 * substructure as part of the Traffic
193 * Selector (TS) Payload.
194 *
195 * That means the TS Payload contains two TS
196 * substructures:
197 * - One for the address/port range
198 * - One for the TS_SECLABEL
199 */
200 .isat_num = with_label ? 2 : 1,
201 };
202
203 if (!out_struct(&its, ts_desc, outpbs, &ts_pbs))
204 return STF_INTERNAL_ERROR;
205 }
206
207 {
208 pb_stream ts_range_pbs;
209 struct ikev2_ts_header ts_header = {
210 .isath_ipprotoid = ts->ipprotoid
211 };
212
213 switch (ts->ts_type) {
214 case IKEv2_TS_IPV4_ADDR_RANGE:
215 ts_header.isath_type = IKEv2_TS_IPV4_ADDR_RANGE;
216 break;
217 case IKEv2_TS_IPV6_ADDR_RANGE:
218 ts_header.isath_type = IKEv2_TS_IPV6_ADDR_RANGE;
219 break;
220 }
221
222 if (!out_struct(&ts_header, &ikev2_ts_header_desc, &ts_pbs, &ts_range_pbs))
223 return STF_INTERNAL_ERROR;
224
225
226 struct ikev2_ts_portrange ts_ports = {
227 .isatpr_startport = ts->startport,
228 .isatpr_endport = ts->endport
229 };
230
231 if (!out_struct(&ts_ports, &ikev2_ts_portrange_desc, &ts_range_pbs, NULL((void*)0)))
232 return STF_INTERNAL_ERROR;
233
234 diag_t d;
235 d = pbs_out_address(&ts_range_pbs, range_start(ts->net), "IP start");
236 if (d != NULL((void*)0)) {
237 llog_diag(RC_LOG_SERIOUS, outpbs->outs_logger, &d, "%s", "");
238 return STF_INTERNAL_ERROR;
239 }
240 d = pbs_out_address(&ts_range_pbs, range_end(ts->net), "IP end");
241 if (d != NULL((void*)0)) {
242 llog_diag(RC_LOG_SERIOUS, outpbs->outs_logger, &d, "%s", "");
243 return STF_INTERNAL_ERROR;
244 }
245 close_output_pbs(&ts_range_pbs);
246 }
247
248 /*
249 * Emit the security label, if known.
250 */
251 if (with_label) {
252
253 struct ikev2_ts_header ts_header = {
254 .isath_type = IKEv2_TS_SECLABEL,
255 .isath_ipprotoid = 0 /* really RESERVED, not iprotoid */
256 };
257 /* Output the header of the TS_SECLABEL substructure payload. */
258 struct pbs_outpacket_byte_stream ts_label_pbs;
259 if (!out_struct(&ts_header, &ikev2_ts_header_desc, &ts_pbs, &ts_label_pbs)) {
260 return STF_INTERNAL_ERROR;
261 }
262
263 /*
264 * Output the security label value of the TS_SECLABEL
265 * substructure payload.
266 *
267 * If we got ACQUIRE, or received a subset TS_LABEL,
268 * use that one - it is subset of connection policy
269 * one
270 */
271
272 dbg("emitting sec_label="PRI_SHUNK, pri_shunk(ts->sec_label)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("emitting sec_label=""%.*s", ((int) (ts->sec_label
).len), (const char *) ((ts->sec_label).ptr)); } }
;
273
274 diag_t d = pbs_out_hunk(&ts_label_pbs, ts->sec_label, "output Security label")({ typeof(ts->sec_label) hunk_ = ts->sec_label; struct packet_byte_stream
*outs_ = &ts_label_pbs; pbs_out_raw(outs_, hunk_.ptr, hunk_
.len, ("output Security label")); })
;
275 if (d != NULL((void*)0)) {
276 llog_diag(RC_LOG_SERIOUS, outpbs->outs_logger, &d, "%s", "");
277 return STF_INTERNAL_ERROR;
278 }
279
280 close_output_pbs(&ts_label_pbs);
281 }
282
283 close_output_pbs(&ts_pbs);
284 return STF_OK;
285}
286
287static struct traffic_selector impair_ts_to_subnet(const struct traffic_selector ts)
288{
289 struct traffic_selector ts_ret = ts;
290
291 ts_ret.net.end = ts_ret.net.start;
292 ts_ret.net.is_subnet = true1;
293
294 return ts_ret;
295}
296
297
298static struct traffic_selector impair_ts_to_supernet(const struct traffic_selector ts)
299{
300 struct traffic_selector ts_ret = ts;
301
302 if (ts_ret.ts_type == IKEv2_TS_IPV4_ADDR_RANGE)
303 ts_ret.net = range_from_subnet(ipv4_info.subnet.all);
304 else if (ts_ret.ts_type == IKEv2_TS_IPV6_ADDR_RANGE)
305 ts_ret.net = range_from_subnet(ipv6_info.subnet.all);
306
307 ts_ret.net.is_subnet = true1;
308
309 ts_ret.sec_label = ts.sec_label;
310
311 return ts_ret;
312}
313
314stf_status emit_v2TS_payloads(struct pbs_outpacket_byte_stream *outpbs, const struct child_sa *child)
315{
316 stf_status ret;
317 struct traffic_selector ts_i, ts_r;
318
319 switch (child->sa.st_sa_role) {
320 case SA_INITIATOR:
321 ts_i = traffic_selector_from_end(&child->sa.st_connection->spd.this, "this TSi");
322 ts_r = traffic_selector_from_end(&child->sa.st_connection->spd.that, "that TSr");
323 if (child->sa.st_state->kind == STATE_V2_REKEY_CHILD_I0 &&
324 impair.rekey_initiate_supernet) {
325 ts_i = ts_r = impair_ts_to_supernet(ts_i);
326 range_buf tsi_buf;
327 range_buf tsr_buf;
328 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)); } }
329 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)); } }
330 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)); } }
;
331
332 } else if (child->sa.st_state->kind == STATE_V2_REKEY_CHILD_I0 &&
333 impair.rekey_initiate_subnet) {
334 ts_i = impair_ts_to_subnet(ts_i);
335 ts_r = impair_ts_to_subnet(ts_r);
336 range_buf tsi_buf;
337 range_buf tsr_buf;
338 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)); } }
339 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)); } }
340 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)); } }
;
341
342 }
343
344 break;
345 case SA_RESPONDER:
346 ts_i = traffic_selector_from_end(&child->sa.st_connection->spd.that, "that TSi");
347 ts_r = traffic_selector_from_end(&child->sa.st_connection->spd.this, "this TSr");
348 if (child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0 &&
349 impair.rekey_respond_subnet) {
350 ts_i = impair_ts_to_subnet(ts_i);
351 ts_r = impair_ts_to_subnet(ts_r);
352 range_buf tsi_buf;
353 range_buf tsr_buf;
354 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)); } }
355 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)); } }
356 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)); } }
;
357 }
358 if (child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0 &&
359 impair.rekey_respond_supernet) {
360 ts_i = ts_r = impair_ts_to_supernet(ts_i);
361 range_buf tsi_buf;
362 range_buf tsr_buf;
363 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)); } }
364 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)); } }
365 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)); } }
;
366 }
367 break;
368 default:
369 bad_case(child->sa.st_sa_role)libreswan_bad_case("child->sa.st_sa_role", (child->sa.st_sa_role
), ({ static const struct where here = { .func = __func__, .file
= "programs/pluto/ikev2_ts.c", .line = 369, }; &here; })
)
;
370 }
371
372 ret = emit_v2TS(outpbs, &ikev2_ts_i_desc, &ts_i);
373 if (ret != STF_OK)
374 return ret;
375
376 ret = emit_v2TS(outpbs, &ikev2_ts_r_desc, &ts_r);
377 if (ret != STF_OK)
378 return ret;
379
380 return STF_OK;
381}
382
383/* return success */
384static bool_Bool v2_parse_tss(struct payload_digest *const ts_pd,
385 struct traffic_selectors *tss,
386 struct logger *logger)
387{
388 dbg("%s: parsing %u traffic selectors",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("%s: parsing %u traffic selectors", tss->name
, ts_pd->payload.v2ts.isat_num); } }
389 tss->name, ts_pd->payload.v2ts.isat_num){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("%s: parsing %u traffic selectors", tss->name
, ts_pd->payload.v2ts.isat_num); } }
;
390
391 if (ts_pd->payload.v2ts.isat_num == 0) {
392 llog(RC_LOG, logger,
393 "%s payload contains no entries when at least one is expected",
394 tss->name);
395 return false0;
396 }
397
398 if (ts_pd->payload.v2ts.isat_num >= elemsof(tss->ts)(sizeof(tss->ts) / sizeof(*(tss->ts)))) {
399 llog(RC_LOG, logger,
400 "%s contains %d entries which exceeds hardwired max of %zu",
401 tss->name, ts_pd->payload.v2ts.isat_num, elemsof(tss->ts)(sizeof(tss->ts) / sizeof(*(tss->ts))));
402 return false0; /* won't fit in array */
403 }
404
405 for (tss->nr = 0; tss->nr < ts_pd->payload.v2ts.isat_num; ) {
406 diag_t d;
407 struct traffic_selector *ts = &tss->ts[tss->nr];
408
409 *ts = (struct traffic_selector){0};
410
411 struct ikev2_ts_header ts_h;
412 struct pbs_inpacket_byte_stream ts_body_pbs;
413
414 d = pbs_in_struct(&ts_pd->pbs, &ikev2_ts_header_desc,
415 &ts_h, sizeof(ts_h), &ts_body_pbs);
416
417 switch (ts_h.isath_type) {
418 case IKEv2_TS_IPV4_ADDR_RANGE:
419 case IKEv2_TS_IPV6_ADDR_RANGE:
420 {
421 ts->ipprotoid = ts_h.isath_ipprotoid;
422
423 /* read and fill in port range */
424 struct ikev2_ts_portrange pr;
425
426 d = pbs_in_struct(&ts_body_pbs, &ikev2_ts_portrange_desc,
427 &pr, sizeof(pr), NULL((void*)0));
428 if (d != NULL((void*)0)) {
429 llog_diag(RC_LOG, logger, &d, "%s", "");
430 return false0;
431 }
432
433 ts->startport = pr.isatpr_startport;
434 ts->endport = pr.isatpr_endport;
435
436 if (ts->startport > ts->endport) {
437 llog(RC_LOG, logger,
438 "%s traffic selector %d has an invalid port range - ignored",
439 tss->name, tss->nr);
440 continue;
441 }
442
443 /* read and fill in IP address range */
444 const struct ip_info *ipv;
445 switch (ts_h.isath_type) {
446 case IKEv2_TS_IPV4_ADDR_RANGE:
447 ipv = &ipv4_info;
448 break;
449 case IKEv2_TS_IPV6_ADDR_RANGE:
450 ipv = &ipv6_info;
451 break;
452 default:
453 bad_case(ts_h.isath_type)libreswan_bad_case("ts_h.isath_type", (ts_h.isath_type), ({ static
const struct where here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 453, }; &here; }))
; /* make compiler happy */
454 }
455
456 ip_address start;
457 d = pbs_in_address(&ts_body_pbs, &start, ipv, "TS IP start");
458 if (d != NULL((void*)0)) {
459 llog_diag(RC_LOG, logger, &d, "%s", "");
460 return false0;
461 }
462
463 ip_address end;
464 d = pbs_in_address(&ts_body_pbs, &end, ipv, "TS IP end");
465 if (d != NULL((void*)0)) {
466 llog_diag(RC_LOG, logger, &d, "%s", "");
467 return false0;
468 }
469
470 /* XXX: does this matter? */
471 if (pbs_left(&ts_body_pbs)((size_t)((&ts_body_pbs)->roof - (&ts_body_pbs)->
cur))
!= 0)
472 return false0;
473
474 err_t err = addresses_to_nonzero_range(start, end, &ts->net);
475
476 /* pluto doesn't yet do full ranges; check for subnet */
477 ip_subnet ignore;
478 err = err == NULL((void*)0) ? range_to_subnet(ts->net, &ignore) : err;
479
480 if (err != NULL((void*)0)) {
481 address_buf sb, eb;
482 llog(RC_LOG, logger, "Traffic Selector range %s-%s invalid: %s",
483 str_address_sensitive(&start, &sb),
484 str_address_sensitive(&end, &eb),
485 err);
486 return false0;
487 }
488
489 ts->ts_type = ts_h.isath_type;
490 break;
491 }
492
493 case IKEv2_TS_SECLABEL:
494 {
495 if (ts_h.isath_ipprotoid != 0) {
496 llog(RC_LOG, logger, "Traffic Selector of type Security Label should not have non-zero IP protocol '%u' - ignored",
497 ts_h.isath_ipprotoid);
498 }
499
500 shunk_t sec_label = pbs_in_left_as_shunk(&ts_body_pbs);
501 err_t ugh = vet_seclabel(sec_label);
502 if (ugh != NULL((void*)0)) {
503 llog(RC_LOG, logger, "Traffic Selector %s", ugh);
504 /* ??? should we just ignore? If so, use continue */
505 return false0;
506 }
507
508 ts->sec_label = sec_label;
509 ts->ts_type = ts_h.isath_type;
510 tss->contains_sec_label = true1;
511 break;
512 }
513
514 case IKEv2_TS_FC_ADDR_RANGE:
515 llog(RC_LOG, logger, "Encountered Traffic Selector Type FC_ADDR_RANGE not supported");
516 return false0;
517
518 default:
519 llog(RC_LOG, logger, "Encountered Traffic Selector of unknown Type");
520 return false0;
521 }
522 tss->nr++;
523 }
524
525 dbg("%s: parsed %d traffic selectors", tss->name, tss->nr){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("%s: parsed %d traffic selectors", tss->name
, tss->nr); } }
;
526 return true1;
527}
528
529static bool_Bool v2_parse_tsp(const struct msg_digest *md,
530 struct traffic_selector_payloads *tsp,
531 struct logger *logger)
532{
533 if (!v2_parse_tss(md->chain[ISAKMP_NEXT_v2TSi], &tsp->i, logger)) {
6
Assuming the condition is false
7
Taking false branch
534 return false0;
535 }
536
537 if (!v2_parse_tss(md->chain[ISAKMP_NEXT_v2TSr], &tsp->r, logger)) {
8
Assuming the condition is false
9
Taking false branch
538 return false0;
539 }
540
541 return true1;
10
Returning the value 1, which participates in a condition later
542}
543
544#define MATCH_PREFIX" " " "
545
546/*
547 * Check if our policy's protocol (proto) matches the Traffic Selector
548 * protocol (ts_proto).
549 */
550
551static int narrow_protocol(const struct end *end,
552 const struct traffic_selectors *tss,
553 enum fit fit, unsigned index)
554{
555 const struct traffic_selector *ts = &tss->ts[index];
556 int protocol = -1;
557
558 switch (fit) {
559 case END_EQUALS_TS:
560 if (end->protocol == ts->ipprotoid) {
561 protocol = end->protocol;
562 }
563 break;
564 case END_NARROWER_THAN_TS:
565 if (ts->ipprotoid == 0 /* wild-card */ ||
566 ts->ipprotoid == end->protocol) {
567 protocol = end->protocol;
568 }
569 break;
570 case END_WIDER_THAN_TS:
571 if (end->protocol == 0 /* wild-card */ ||
572 end->protocol == ts->ipprotoid) {
573 protocol = ts->ipprotoid;
574 }
575 break;
576 default:
577 bad_case(fit)libreswan_bad_case("fit", (fit), ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 577, }; &here; }))
;
578 }
579 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), tss->name, index, ts->ipprotoid == 0 ? "*" : "",
ts->ipprotoid, protocol); } }
580 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), tss->name, index, ts->ipprotoid == 0 ? "*" : "",
ts->ipprotoid, protocol); } }
581 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), tss->name, index, ts->ipprotoid == 0 ? "*" : "",
ts->ipprotoid, protocol); } }
582 tss->name, 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), tss->name, index, ts->ipprotoid == 0 ? "*" : "",
ts->ipprotoid, protocol); } }
583 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), tss->name, index, ts->ipprotoid == 0 ? "*" : "",
ts->ipprotoid, protocol); } }
;
584 return protocol;
585}
586
587static int score_narrow_protocol(const struct end *end,
588 const struct traffic_selectors *tss,
589 enum fit fit, unsigned index)
590{
591 int f; /* strength of match */
592
593 int protocol = narrow_protocol(end, tss, fit, index);
594 if (protocol == 0) {
595 f = 255; /* ??? odd value */
596 } else if (protocol > 0) {
597 f = 1;
598 } else {
599 f = 0;
600 }
601 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_logger(buf
, &failsafe_logger, DEBUG_STREAM), buf = ((void*)0))
{
602 const struct traffic_selector *ts = &tss->ts[index];
603 jam(buf, MATCH_PREFIX" " "match end->protocol=%s%d %s %s[%u].ipprotoid=%s%d: ",
604 end->protocol == 0 ? "*" : "", end->protocol,
605 fit_string(fit),
606 tss->name, index, ts->ipprotoid == 0 ? "*" : "", ts->ipprotoid);
607 if (f > 0) {
608 jam(buf, "YES fitness %d", f);
609 } else {
610 jam(buf, "NO");
611 }
612 }
613 return f;
614}
615
616/*
617 * Narrow the END/TS ports according to FIT.
618 *
619 * Returns 0 (all ports), a specific port number, or -1 (no luck).
620 *
621 * Since 'struct end' only describes all-ports or a single port; only
622 * narrow to that.
623 */
624
625static int narrow_port(const struct end *end,
626 const struct traffic_selectors *tss,
627 enum fit fit, unsigned index)
628{
629 passert(index < tss->nr)({ _Bool assertion__ = index < tss->nr; if (!assertion__
) { where_t here = ({ static const struct where here = { .func
= __func__, .file = "programs/pluto/ikev2_ts.c", .line = 629
, }; &here; }); const struct logger *logger_ = &failsafe_logger
; llog_passert(logger_, here, "%s", "index < tss->nr");
} (void) 1; })
;
630 const struct traffic_selector *ts = &tss->ts[index];
631
632 int end_low = end->port;
633 int end_high = end->port == 0 ? 65535 : end->port;
634 int port = -1;
635
636 switch (fit) {
637 case END_EQUALS_TS:
638 if (end_low == ts->startport && ts->endport == end_high) {
639 /* end=ts=0-65535 || end=ts=N-N */
640 port = end_low;
641 }
642 break;
643 case END_NARROWER_THAN_TS:
644 if (ts->startport <= end_low && end_high <= ts->endport) {
645 /* end=ts=0-65535 || ts=N<=end<=M */
646 port = end_low;
647 }
648 break;
649 case END_WIDER_THAN_TS:
650 if (end_low < ts->startport && ts->endport < end_high &&
651 ts->startport == ts->endport) {
652 /*ts=0<N-N<65535*/
653 port = ts->startport;
654 } else if (end_low == ts->startport && ts->endport == end_high) {
655 /* end=ts=0-65535 || end=ts=N-N */
656 port = ts->startport;
657 }
658 break;
659 default:
660 bad_case(fit)libreswan_bad_case("fit", (fit), ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 660, }; &here; }))
;
661 }
662 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), tss->name, index, ts
->startport, ts->endport, port); } }
663 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), tss->name, index, ts
->startport, ts->endport, port); } }
664 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), tss->name, index, ts
->startport, ts->endport, port); } }
665 tss->name, 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), tss->name, index, ts
->startport, ts->endport, port); } }
666 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), tss->name, index, ts
->startport, ts->endport, port); } }
;
667 return port;
668}
669
670/*
671 * Assign a score to the narrowed port, rationale for score lost in
672 * time?
673 */
674
675static int score_narrow_port(const struct end *end,
676 const struct traffic_selectors *tss,
677 enum fit fit, unsigned index)
678{
679 int f; /* strength of match */
680
681 int port = narrow_port(end, tss, fit, index);
682 if (port > 0) {
683 f = 1;
684 } else if (port == 0) {
685 f = 65536; /* from 1 + 65535-0 */
686 } else {
687 f = 0;
688 }
689 if (f > 0) {
690 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"
, tss->name, index, f); } }
691 tss->name, index, f){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" " " %s[%u] port match: YES fitness %d"
, tss->name, index, f); } }
;
692 } else {
693 dbg(MATCH_PREFIX " %s[%u] port match: NO",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" " " %s[%u] port match: NO", tss->
name, index); } }
694 tss->name, index){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" " " %s[%u] port match: NO", tss->
name, index); } }
;
695 }
696 return f;
697}
698
699
700/*
701 * Does TS fit inside of END?
702 *
703 * Given other code flips the comparison depending initiator or
704 * responder, is this right?
705 *
706 * NOTE: Our parser/config only allows 1 CIDR, however IKEv2 ranges
707 * can be non-CIDR for now we really support/limit ourselves to
708 * a single CIDR
709 */
710
711static int score_address_range(const struct end *end,
712 const struct traffic_selectors *tss,
713 enum fit fit, unsigned index)
714{
715 const struct traffic_selector *ts = &tss->ts[index];
716 /*
717 * Pre-compute possible fit --- sum of bits gives how good a
718 * fit this is.
719 */
720 int ts_range = range_host_bits(ts->net);
721 int maskbits = end->client.maskbits;
722 int fitbits = maskbits + ts_range;
723
724 int f = 0;
725
726 /*
727 * NOTE: Our parser/config only allows 1 CIDR, however IKEv2
728 * ranges can be non-CIDR for now we really
729 * support/limit ourselves to a single CIDR
730 *
731 * XXX: so what is CIDR?
732 */
733 ip_range range = selector_range(end->client);
734 switch (fit) {
735 case END_EQUALS_TS:
736 if (range_eq_range(range, ts->net)) {
737 f = fitbits;
738 }
739 break;
740 case END_NARROWER_THAN_TS:
741 if (range_in_range(range, ts->net)) {
742 f = fitbits;
743 }
744 break;
745 case END_WIDER_THAN_TS:
746 if (range_in_range(ts->net, range)) {
747 f = fitbits;
748 }
749 break;
750 default:
751 bad_case(fit)libreswan_bad_case("fit", (fit), ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 751, }; &here; }))
;
752 }
753
754 /*
755 * comparing for ports for finding better local policy
756 *
757 * XXX: why do this?
758 */
759 /* ??? arbitrary modification to objective function */
760 if (end->port != 0 &&
761 ts->startport == end->port &&
762 ts->endport == end->port)
763 f = f << 1;
764
765 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_logger(buf
, &failsafe_logger, DEBUG_STREAM), buf = ((void*)0))
{
766 jam(buf, MATCH_PREFIX" " "match address end->client=");
767 jam_selector(buf, &end->client);
768 jam(buf, " %s %s[%u]net=", fit_string(fit), tss->name, index);
769 jam_range(buf, &ts->net);
770 jam(buf, ": ");
771 if (f > 0) {
772 jam(buf, "YES fitness %d", f);
773 } else {
774 jam(buf, "NO");
775 }
776 }
777 return f;
778}
779
780struct score {
781 bool_Bool ok;
782 int address;
783 int port;
784 int protocol;
785};
786
787static struct score score_end(const struct end *end,
788 const struct traffic_selectors *tss,
789 enum fit fit, unsigned index)
790{
791 const struct traffic_selector *ts = &tss->ts[index];
792
793 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_logger(buf
, &failsafe_logger, DEBUG_STREAM), buf = ((void*)0))
{
794 jam(buf, " %s[%u]", tss->name, index);
795 if (ts->sec_label.len > 0) {
796 jam(buf, " sec_label=");
797 jam_sanitized_hunk(buf, ts->sec_label)({ typeof(ts->sec_label) hunk_ = (ts->sec_label); jam_sanitized_bytes
(buf, hunk_.ptr, hunk_.len); })
;
798 } else {
799 range_buf ts_net;
800 jam(buf, " net=%s iporotoid=%d {start,end}port=%d..%d",
801 str_range(&ts->net, &ts_net),
802 ts->ipprotoid,
803 ts->startport,
804 ts->endport);
805 }
806 }
807
808 struct score score = {
809 .ok = false0,
810 };
811
812 switch(ts->ts_type) {
813 case IKEv2_TS_IPV4_ADDR_RANGE:
814 case IKEv2_TS_IPV6_ADDR_RANGE:
815 score.address = score_address_range(end, tss, fit, index);
816 if (score.address <= 0) {
817 return score;
818 }
819 score.port = score_narrow_port(end, tss, fit, index);
820 if (score.port <= 0) {
821 return score;
822 }
823 score.protocol = score_narrow_protocol(end, tss, fit, index);
824 if (score.protocol <= 0) {
825 return score;
826 }
827 score.ok = true1;
828 return score;
829 case IKEv2_TS_SECLABEL:
830 default:
831 return score;
832 }
833}
834
835struct best_score {
836 bool_Bool ok;
837 int address;
838 int port;
839 int protocol;
840 const struct traffic_selector *tsi;
841 const struct traffic_selector *tsr;
842};
843#define NO_SCORE{ .ok = 0, .address = -1, .port = -1, .protocol = -1, } { .ok = false0, .address = -1, .port = -1, .protocol = -1, }
844
845static bool_Bool score_gt(const struct best_score *score, const struct best_score *best)
846{
847 return (score->address > best->address ||
848 (score->address == best->address &&
849 score->port > best->port) ||
850 (score->address == best->address &&
851 score->port == best->port &&
852 score->protocol > best->protocol));
853}
854
855/*
856 * Return true for sec_label expected and good XOR not expected and
857 * not present.
858 *
859 * Return false when required sec_label is missing or bad; or
860 * sec_label encountered when it wasn't expected.
861 *
862 * The code calls sec_label_within_range() to check that the "source
863 * context has the access permission for the specified class on the
864 * "target context" (see selinux_check_access()):
865 *
866 * - for the initiator searching for a matching template connection to
867 * instantiate, the "source context" is the sec_label from acquire,
868 * and the "target context" is the sec_label in the template
869 * connection.
870 *
871 * - for the responder searching for a template connection to match
872 * the on-wire TS, the "source context" is the sec_label included in
873 * the traffic selector, and the "target context" is (again) the
874 * sec_label in the template connection.
875 *
876 * However, when the initiator gets back the responder's accepted TS
877 * containing a sec_label, the initiator only checks it is identical
878 * to what was sent out in the initiator's TS:
879 *
880 * - the RFC makes vague references to narrowing; but what that means
881 * for sec_labels isn't clear
882 *
883 * - one interpretation, that the responder's "source context" has
884 * "access permission" for the initiator's "source context" seems to
885 * always fail when enforcing is enabled (suspect
886 * selinux_check_access() requires a "ptarget context").
887 */
888
889static bool_Bool check_tss_sec_label(const struct traffic_selectors *tss,
890 chunk_t config_sec_label,
891 shunk_t *selected_sec_label,
892 struct logger *logger)
893{
894 passert(tss->contains_sec_label)({ _Bool assertion__ = tss->contains_sec_label; if (!assertion__
) { where_t here = ({ static const struct where here = { .func
= __func__, .file = "programs/pluto/ikev2_ts.c", .line = 894
, }; &here; }); const struct logger *logger_ = &failsafe_logger
; llog_passert(logger_, here, "%s", "tss->contains_sec_label"
); } (void) 1; })
;
895
896 *selected_sec_label = null_shunk;
897 for (unsigned i = 0; i < tss->nr; i++) {
898 const struct traffic_selector *ts = &tss->ts[i];
899 if (ts->ts_type != IKEv2_TS_SECLABEL) {
900 continue;
901 }
902
903 passert(vet_seclabel(ts->sec_label) == NULL)({ _Bool assertion__ = vet_seclabel(ts->sec_label) == ((void
*)0); if (!assertion__) { where_t here = ({ static const struct
where here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 903, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_passert(logger_, here, "%s", "vet_seclabel(ts->sec_label) == ((void*)0)"
); } (void) 1; })
;
904
905 if (!sec_label_within_range(ts->sec_label, config_sec_label, logger)) {
906 dbg("ikev2ts: %s sec_label="PRI_SHUNK" is not within range connection sec_label="PRI_SHUNK,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("ikev2ts: %s sec_label=""%.*s"" is not within range connection sec_label="
"%.*s", tss->name, ((int) (ts->sec_label).len), (const char
*) ((ts->sec_label).ptr), ((int) (config_sec_label).len),
(const char *) ((config_sec_label).ptr)); } }
907 tss->name, pri_shunk(ts->sec_label), pri_shunk(config_sec_label)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("ikev2ts: %s sec_label=""%.*s"" is not within range connection sec_label="
"%.*s", tss->name, ((int) (ts->sec_label).len), (const char
*) ((ts->sec_label).ptr), ((int) (config_sec_label).len),
(const char *) ((config_sec_label).ptr)); } }
;
908 continue;
909 }
910
911 dbg("ikev2ts: received %s label within range of our security label",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("ikev2ts: received %s label within range of our security label"
, tss->name); } }
912 tss->name){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("ikev2ts: received %s label within range of our security label"
, tss->name); } }
;
913
914 /* XXX we return the first match. Should we return the best? */
915 *selected_sec_label = ts->sec_label; /* first match */
916 return true1;
917 }
918
919 return false0;
920}
921
922static bool_Bool score_tsp_sec_label(const struct traffic_selector_payloads *tsp,
923 chunk_t config_sec_label,
924 shunk_t *selected_sec_label,
925 struct logger *logger)
926{
927 if (config_sec_label.len == 0) {
928 /* This endpoint is not configured to use labeled IPsec. */
929 if (tsp->i.contains_sec_label || tsp->r.contains_sec_label) {
930 dbg("error: received sec_label but this end is *not* configured to use sec_label"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("error: received sec_label but this end is *not* configured to use sec_label"
); } }
;
931 return false0;
932 }
933 /* No sec_label was found and none was expected */
934 return true1; /* success: no label, as expected */
935 }
936
937 /* This endpoint is configured to use labeled IPsec. */
938 passert(vet_seclabel(HUNK_AS_SHUNK(config_sec_label)) == NULL)({ _Bool assertion__ = vet_seclabel(({ typeof(config_sec_label
) h_ = (config_sec_label); shunk2(h_.ptr, h_.len); })) == ((void
*)0); if (!assertion__) { where_t here = ({ static const struct
where here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 938, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_passert(logger_, here, "%s", "vet_seclabel(({ typeof(config_sec_label) h_ = (config_sec_label); shunk2(h_.ptr, h_.len); })) == ((void*)0)"
); } (void) 1; })
;
939
940 if (!tsp->i.contains_sec_label || !tsp->r.contains_sec_label) {
941 dbg("error: connection requires sec_label but not received TSi/TSr with sec_label"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("error: connection requires sec_label but not received TSi/TSr with sec_label"
); } }
;
942 return false0;
943 }
944
945 if (!check_tss_sec_label(&tsp->i, config_sec_label, selected_sec_label, logger) ||
946 !check_tss_sec_label(&tsp->r, config_sec_label, selected_sec_label, logger)) {
947 return false0;
948 }
949
950 /* security label required and matched */
951 return true1;
952}
953
954static struct best_score score_ends_iprange(enum fit fit,
955 const struct connection *d,
956 const struct ends *ends,
957 const struct traffic_selector_payloads *tsp)
958{
959 if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) {
960 selector_buf ei3;
961 selector_buf er3;
962 connection_buf cib;
963 DBG_log("evaluating our conn="PRI_CONNECTION"\"%s\"%s"" I=%s:%d/%d R=%s:%d/%d%s to their:",
964 pri_connection(d, &cib)(d)->name, str_connection_instance(d, &cib),
965 str_selector(&ends->i->client, &ei3), ends->i->protocol, ends->i->port,
966 str_selector(&ends->r->client, &er3), ends->r->protocol, ends->r->port,
967 is_virtual_connection(d) ? " (virt)" : "");
968 }
969
970 struct best_score best_score = NO_SCORE{ .ok = 0, .address = -1, .port = -1, .protocol = -1, };
971
972 /* compare tsi/r array to this/that, evaluating how well it fits */
973 for (unsigned tsi_n = 0; tsi_n < tsp->i.nr; tsi_n++) {
974 const struct traffic_selector *tni = &tsp->i.ts[tsi_n];
975
976 /* choice hardwired for IPrange and sec_label */
977 struct score score_i = score_end(ends->i, &tsp->i, fit, tsi_n);
978 if (!score_i.ok) {
979 continue;
980 }
981
982 for (unsigned tsr_n = 0; tsr_n < tsp->r.nr; tsr_n++) {
983 const struct traffic_selector *tnr = &tsp->r.ts[tsr_n];
984
985 struct score score_r = score_end(ends->r, &tsp->r, fit, tsr_n);
986 if (!score_r.ok) {
987 continue;
988 }
989 struct best_score score = {
990 .ok = true1,
991 /* ??? this objective function is odd and arbitrary */
992 .address = (score_i.address << 8) + score_r.address,
993 /* ??? arbitrary objective function */
994 .port = score_i.port + score_r.port,
995 /* ??? arbitrary objective function */
996 .protocol = score_i.protocol + score_r.protocol,
997 /* which one */
998 .tsi = tni, .tsr = tnr,
999 };
1000
1001 /* score >= best_score? */
1002 if (score_gt(&score, &best_score)) {
1003 best_score = score;
1004 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
); } }
1005 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
); } }
;
1006 }
1007 }
1008 }
1009
1010 return best_score;
1011}
1012
1013static bool_Bool v2_child_connection_probably_shared(struct child_sa *child)
1014{
1015 struct connection *c = child->sa.st_connection;
1016
1017 if (connection_is_pending(c)) {
1018 dbg("#%lu connection is also pending; but what about pending for this state???",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("#%lu connection is also pending; but what about pending for this state???"
, child->sa.st_serialno); } }
1019 child->sa.st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("#%lu connection is also pending; but what about pending for this state???"
, child->sa.st_serialno); } }
;
1020 return true1;
1021 }
1022
1023 dbg("FOR_EACH_STATE_... in %s", __func__){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("FOR_EACH_STATE_... in %s", __func__); } }
;
1024 struct ike_sa *ike = ike_sa(&child->sa, HERE({ static const struct where here = { .func = __func__, .file
= "programs/pluto/ikev2_ts.c", .line = 1024, }; &here; }
)
);
1025 struct state *st = NULL((void*)0);
1026 FOR_EACH_STATE_NEW2OLD(st)for (struct list_entry *entry_ = (&state_serialno_list_head
)->head.older; entry_ != ((void*)0); entry_ = ((void*)0)) for
(st = (typeof(st))entry_->data, entry_ = entry_->older
; st != ((void*)0); st = (typeof(st))entry_->data, entry_ =
entry_->older)
{
1027 if (st->st_connection != c) {
1028 continue;
1029 }
1030 if (st == &child->sa) {
1031 dbg("ignoring ourselves #%lu sharing connection %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("ignoring ourselves #%lu sharing connection %s"
, st->st_serialno, c->name); } }
1032 st->st_serialno, c->name){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("ignoring ourselves #%lu sharing connection %s"
, st->st_serialno, c->name); } }
;
1033 continue;
1034 }
1035 if (st == &ike->sa) {
1036 dbg("ignoring IKE SA #%lu sharing connection %s with #%lu",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("ignoring IKE SA #%lu sharing connection %s with #%lu"
, st->st_serialno, c->name, child->sa.st_serialno); }
}
1037 st->st_serialno, c->name, child->sa.st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("ignoring IKE SA #%lu sharing connection %s with #%lu"
, st->st_serialno, c->name, child->sa.st_serialno); }
}
;
1038 continue;
1039 }
1040 dbg("#%lu and #%lu share connection %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("#%lu and #%lu share connection %s", child->
sa.st_serialno, st->st_serialno, c->name); } }
1041 child->sa.st_serialno, st->st_serialno,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("#%lu and #%lu share connection %s", child->
sa.st_serialno, st->st_serialno, c->name); } }
1042 c->name){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("#%lu and #%lu share connection %s", child->
sa.st_serialno, st->st_serialno, c->name); } }
;
1043 return true1;
1044 }
1045
1046 return false0;
1047}
1048
1049struct narrowed_ts {
1050 bool_Bool ok;
1051 int tsi_port;
1052 int tsi_protocol;
1053 int tsr_port;
1054 int tsr_protocol;
1055};
1056
1057static struct narrowed_ts narrow_request_ts(struct connection *c,
1058 const struct traffic_selector_payloads *tsp,
1059 enum fit fit)
1060{
1061 struct narrowed_ts n = {
1062 .ok = false0, /* until proven */
1063 };
1064
1065 passert(tsp->i.nr >= 1)({ _Bool assertion__ = tsp->i.nr >= 1; if (!assertion__
) { where_t here = ({ static const struct where here = { .func
= __func__, .file = "programs/pluto/ikev2_ts.c", .line = 1065
, }; &here; }); const struct logger *logger_ = &failsafe_logger
; llog_passert(logger_, here, "%s", "tsp->i.nr >= 1"); }
(void) 1; })
;
1066 n.tsi_port = narrow_port(&c->spd.that, &tsp->i, fit, 0);
1067 if (n.tsi_port < 0) {
1068 dbg(" skipping; TSi port too wide"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" skipping; TSi port too wide"); } }
;
1069 return n;
1070 }
1071
1072 n.tsi_protocol = narrow_protocol(&c->spd.that, &tsp->r, fit, 0);
1073 if (n.tsi_protocol < 0) {
1074 dbg(" skipping; TSi protocol too wide"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" skipping; TSi protocol too wide"); } }
;
1075 return n;
1076 }
1077
1078 passert(tsp->r.nr >= 1)({ _Bool assertion__ = tsp->r.nr >= 1; if (!assertion__
) { where_t here = ({ static const struct where here = { .func
= __func__, .file = "programs/pluto/ikev2_ts.c", .line = 1078
, }; &here; }); const struct logger *logger_ = &failsafe_logger
; llog_passert(logger_, here, "%s", "tsp->r.nr >= 1"); }
(void) 1; })
;
1079 n.tsr_port = narrow_port(&c->spd.this, &tsp->r, fit, 0);
1080 if (n.tsr_port < 0) {
1081 dbg(" skipping; TSr port too wide"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" skipping; TSr port too wide"); } }
;
1082 return n;
1083 }
1084
1085 n.tsr_protocol = narrow_protocol(&c->spd.this, &tsp->r, fit, 0);
1086 if (n.tsr_protocol < 0) {
1087 dbg(" skipping; TSr protocol too wide"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" skipping; TSr protocol too wide"); } }
;
1088 return n;
1089 }
1090
1091 n.ok = true1;
1092 return n;
1093}
1094
1095static void scribble_request_ts_on_connection(struct child_sa *child,
1096 struct connection *c,
1097 struct narrowed_ts n)
1098{
1099 if (c != child->sa.st_connection) {
1100 connection_buf from, to;
1101 dbg(" switching #%lu from "PRI_CONNECTION" to just-instantiated "PRI_CONNECTION,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" switching #%lu from ""\"%s\"%s"" to just-instantiated "
"\"%s\"%s", child->sa.st_serialno, (child->sa.st_connection
)->name, str_connection_instance(child->sa.st_connection
, &from), (c)->name, str_connection_instance(c, &to
)); } }
1102 child->sa.st_serialno,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" switching #%lu from ""\"%s\"%s"" to just-instantiated "
"\"%s\"%s", child->sa.st_serialno, (child->sa.st_connection
)->name, str_connection_instance(child->sa.st_connection
, &from), (c)->name, str_connection_instance(c, &to
)); } }
1103 pri_connection(child->sa.st_connection, &from),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" switching #%lu from ""\"%s\"%s"" to just-instantiated "
"\"%s\"%s", child->sa.st_serialno, (child->sa.st_connection
)->name, str_connection_instance(child->sa.st_connection
, &from), (c)->name, str_connection_instance(c, &to
)); } }
1104 pri_connection(c, &to)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" switching #%lu from ""\"%s\"%s"" to just-instantiated "
"\"%s\"%s", child->sa.st_serialno, (child->sa.st_connection
)->name, str_connection_instance(child->sa.st_connection
, &from), (c)->name, str_connection_instance(c, &to
)); } }
;
1105 } else {
1106 connection_buf cib;
1107 dbg(" overwrote #%lu connection "PRI_CONNECTION,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" overwrote #%lu connection ""\"%s\"%s", child
->sa.st_serialno, (c)->name, str_connection_instance(c,
&cib)); } }
1108 child->sa.st_serialno, pri_connection(c, &cib)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" overwrote #%lu connection ""\"%s\"%s", child
->sa.st_serialno, (c)->name, str_connection_instance(c,
&cib)); } }
;
1109 }
1110
1111 /* "this" == responder; see function name */
1112 c->spd.this.port = n.tsr_port;
1113 c->spd.that.port = n.tsi_port;
1114 c->spd.this.protocol = n.tsr_protocol;
1115 c->spd.that.protocol = n.tsi_protocol;
1116 /* hack */
1117 dbg("XXX: updating best connection's ports/protocols"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("XXX: updating best connection's ports/protocols"
); } }
;
1118 update_selector_hport(&c->spd.this.client, n.tsr_port){ (&c->spd.this.client)->hport = (n.tsr_port); };
1119 update_selector_hport(&c->spd.that.client, n.tsi_port){ (&c->spd.that.client)->hport = (n.tsi_port); };
1120 update_selector_ipproto(&c->spd.this.client, n.tsr_protocol){ (&c->spd.this.client)->ipproto = (n.tsr_protocol)
; }
;
1121 update_selector_ipproto(&c->spd.that.client, n.tsi_protocol){ (&c->spd.that.client)->ipproto = (n.tsi_protocol)
; }
;
1122}
1123
1124/*
1125 * Find the best connection, possibly updating child.
1126 */
1127bool_Bool v2_process_request_ts_payloads(struct child_sa *child,
1128 const struct msg_digest *md)
1129{
1130 passert(v2_msg_role(md) == MESSAGE_REQUEST)({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_REQUEST; if
(!assertion__) { where_t here = ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1130, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_passert(logger_, here, "%s", "v2_msg_role(md) == MESSAGE_REQUEST"
); } (void) 1; })
;
1
Assuming the condition is true
2
Taking false branch
1131 passert(child->sa.st_sa_role == SA_RESPONDER)({ _Bool assertion__ = child->sa.st_sa_role == SA_RESPONDER
; if (!assertion__) { where_t here = ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1131, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_passert(logger_, here, "%s", "child->sa.st_sa_role == SA_RESPONDER"
); } (void) 1; })
;
3
Assuming field 'st_sa_role' is equal to SA_RESPONDER
4
Taking false branch
1132
1133 struct traffic_selector_payloads tsp = empty_traffic_selectors;
1134 if (!v2_parse_tsp(md, &tsp, child->sa.st_logger)) {
5
Calling 'v2_parse_tsp'
11
Returning from 'v2_parse_tsp'
12
Taking false branch
1135 return false0;
1136 }
1137
1138 /* best so far; start with state's connection */
1139 struct best_score best_score = NO_SCORE{ .ok = 0, .address = -1, .port = -1, .protocol = -1, };
1140 const struct spd_route *best_spd_route = NULL((void*)0);
1141 struct connection *const c = child->sa.st_connection;
13
'c' initialized here
1142 struct connection *best_connection = c;
1143 shunk_t best_sec_label = null_shunk;
1144
1145 /* find best spd in c */
1146
1147 connection_buf ccb;
1148 dbg("responder looking for best SPD in current connection "PRI_CONNECTION,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("responder looking for best SPD in current connection "
"\"%s\"%s", (c)->name, str_connection_instance(c, &ccb
)); } }
14
Assuming the condition is false
15
Taking false branch
1149 pri_connection(c, &ccb)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("responder looking for best SPD in current connection "
"\"%s\"%s", (c)->name, str_connection_instance(c, &ccb
)); } }
;
1150 for (const struct spd_route *sra = &c->spd; sra != NULL((void*)0); sra = sra->spd_next) {
16
Assuming 'sra' is equal to NULL
17
Loop condition is false. Execution continues on line 1203
1151
1152 /* responder */
1153 const struct ends ends = {
1154 .i = &sra->that,
1155 .r = &sra->this,
1156 };
1157
1158 shunk_t selected_sec_label = null_shunk;
1159 if (!score_tsp_sec_label(&tsp, c->config->sec_label,
1160 &selected_sec_label,
1161 child->sa.st_logger)) {
1162 /*
1163 * Either:
1164 * - Security label required, but not found.
1165 * OR
1166 * - Security label *not* required, but found.
1167 */
1168 continue;
1169 }
1170
1171 enum fit responder_fit =
1172 (c->policy & POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)))
1173 ? END_NARROWER_THAN_TS
1174 : END_EQUALS_TS;
1175 struct best_score score = score_ends_iprange(responder_fit, c, &ends, &tsp);
1176 if (!score.ok) {
1177 continue;
1178 }
1179
1180 if (score_gt(&score, &best_score)) {
1181 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 - tsp.i.ts, score.tsr - tsp.r.ts); } }
1182 score.tsi - tsp.i.ts, score.tsr - tsp.r.ts){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" found better spd route for TSi[%td],TSr[%td]"
, score.tsi - tsp.i.ts, score.tsr - tsp.r.ts); } }
;
1183 best_score = score;
1184 best_spd_route = sra;
1185 best_sec_label = selected_sec_label;
1186 /* better SPD still within current connection */
1187 passert(best_connection == c)({ _Bool assertion__ = best_connection == c; if (!assertion__
) { where_t here = ({ static const struct where here = { .func
= __func__, .file = "programs/pluto/ikev2_ts.c", .line = 1187
, }; &here; }); const struct logger *logger_ = &failsafe_logger
; llog_passert(logger_, here, "%s", "best_connection == c"); }
(void) 1; })
;
1188 }
1189 }
1190
1191 /*
1192 * ??? the use of hp looks nonsensical.
1193 * Either the first non-empty host_pair should be used
1194 * (like the current code) and the following should
1195 * be broken into two loops: first find the non-empty
1196 * host_pair list, second look through the host_pair list.
1197 * OR
1198 * what's really meant is look at the host_pair for
1199 * each sra, something that matches the current
1200 * nested loop structure but not what it actually does.
1201 */
1202
1203 dbg("looking for better host pair"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("looking for better host pair"); } }
;
18
Taking false branch
1204
1205 const ip_address local = md->iface->ip_dev->id_address;
1206 FOR_EACH_THING(remote, endpoint_address(md->sender), unset_address)for (typeof(endpoint_address(md->sender)) things_[] = { endpoint_address
(md->sender), unset_address }, *thingp_ = things_, remote;
thingp_ < things_ + (sizeof(things_) / sizeof(*(things_))
) ? (remote = *thingp_, 1) : 0; thingp_++)
{
19
'?' condition is true
20
Loop condition is true. Entering loop body
1207
1208 FOR_EACH_HOST_PAIR_CONNECTION(local, remote, d)for (struct connection *next_ = ((void*)0), *d = next_host_pair_connection
(local, remote, &next_, 1, ({ static const struct where here
= { .func = __func__, .file = "programs/pluto/ikev2_ts.c", .
line = 1208, }; &here; })); d != ((void*)0); d = next_host_pair_connection
(local, remote, &next_, 0, ({ static const struct where here
= { .func = __func__, .file = "programs/pluto/ikev2_ts.c", .
line = 1208, }; &here; })))
{
21
Assuming 'd' is not equal to null
22
Loop condition is true. Entering loop body
1209
1210 /* groups are templates instantiated as GROUPINSTANCE */
1211 if (d->policy & POLICY_GROUP((lset_t)1 << (POLICY_GROUP_IX))) {
23
Assuming the condition is false
24
Taking false branch
1212 continue;
1213 }
1214
1215 /*
1216 * For labeled IPsec, always start with the
1217 * template. Who are we to argue if the
1218 * kernel asks for a new SA with, seemingly, a
1219 * security label that matches an existing
1220 * connection instance.
1221 */
1222 if (c->ike_version == IKEv2 &&
25
Access to field 'ike_version' results in a dereference of a null pointer (loaded from variable 'c')
1223 c->config->sec_label.len > 0 &&
1224 c->kind != CK_TEMPLATE) {
1225 connection_buf cb;
1226 dbg("skipping non-template IKEv2 "PRI_CONNECTION" with a security label",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("skipping non-template IKEv2 ""\"%s\"%s"" with a security label"
, (c)->name, str_connection_instance(c, &cb)); } }
1227 pri_connection(c, &cb)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("skipping non-template IKEv2 ""\"%s\"%s"" with a security label"
, (c)->name, str_connection_instance(c, &cb)); } }
;
1228 continue;
1229 }
1230
1231 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); } }
;
1232
1233 /*
1234 * ??? same_id && match_id seems redundant.
1235 * if d->spd.this.id.kind == ID_NONE, both TRUE
1236 * else if c->spd.this.id.kind == ID_NONE,
1237 * same_id treats it as a wildcard and match_id
1238 * does not. Odd.
1239 * else if kinds differ, match_id FALSE
1240 * else if kind ID_DER_ASN1_DN, wildcards are forbidden by same_id
1241 * else match_id just calls same_id.
1242 * So: if wildcards are desired, just use match_id.
1243 * If they are not, just use same_id
1244 */
1245 int wildcards; /* value ignored */
1246 int pathlen; /* value ignored */
1247
1248 /* conns created as aliases from the same source have identical ID/CA */
1249 if (!(c->connalias != NULL((void*)0) && d->connalias != NULL((void*)0) && streq(c->connalias, d->connalias)(strcmp((c->connalias), (d->connalias)) == 0))) {
1250 if (!(same_id(&c->spd.this.id, &d->spd.this.id) &&
1251 match_id(&c->spd.that.id, &d->spd.that.id, &wildcards) &&
1252 trusted_ca_nss(c->spd.that.ca, d->spd.that.ca, &pathlen)))
1253 {
1254 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); } }
1255 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); } }
;
1256 continue;
1257 }
1258 }
1259
1260 const struct spd_route *sr;
1261
1262 for (sr = &d->spd; sr != NULL((void*)0); sr = sr->spd_next) {
1263
1264 /* responder */
1265 const struct ends ends = {
1266 .i = &sr->that,
1267 .r = &sr->this,
1268 };
1269 /* responder -- note D! */
1270 enum fit responder_fit =
1271 (d->policy & POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)))
1272 ? END_NARROWER_THAN_TS
1273 : END_EQUALS_TS;
1274
1275 /* Returns NULL(ok), &null_shunk(skip), memory(ok). */
1276 shunk_t selected_sec_label = null_shunk;
1277 if (!score_tsp_sec_label(&tsp, d->config->sec_label,
1278 &selected_sec_label, child->sa.st_logger)) {
1279 /*
1280 * Either:
1281 * - Security label required, but not found.
1282 * OR
1283 * - Security label *not* required, but found.
1284 */
1285 continue;
1286 }
1287
1288 struct best_score score = score_ends_iprange(responder_fit, d/*note D*/,
1289 &ends, &tsp);
1290 if (!score.ok) {
1291 continue;
1292 }
1293 if (score_gt(&score, &best_score)) {
1294 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 - tsp.i.ts, score.tsr - tsp.r.ts); } }
1295 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 - tsp.i.ts, score.tsr - tsp.r.ts); } }
1296 score.tsi - tsp.i.ts, score.tsr - tsp.r.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 - tsp.i.ts, score.tsr - tsp.r.ts); } }
;
1297 best_connection = d;
1298 best_score = score;
1299 best_spd_route = sr;
1300 best_sec_label = selected_sec_label;
1301 }
1302 }
1303 }
1304 }
1305
1306 if (best_connection == c) {
1307 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"
); } }
;
1308 }
1309
1310#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)) | \
1311 POLICY_DONT_REKEY((lset_t)1 << (POLICY_DONT_REKEY_IX)) | \
1312 POLICY_REAUTH((lset_t)1 << (POLICY_REAUTH_IX)) | \
1313 POLICY_OPPORTUNISTIC((lset_t)1 << (POLICY_OPPORTUNISTIC_IX)) | \
1314 POLICY_GROUP((lset_t)1 << (POLICY_GROUP_IX)) | \
1315 POLICY_GROUTED((lset_t)1 << (POLICY_GROUTED_IX)) | \
1316 POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | \
1317 POLICY_UP((lset_t)1 << (POLICY_UP_IX)) | \
1318 POLICY_XAUTH((lset_t)1 << (POLICY_XAUTH_IX)) | \
1319 POLICY_MODECFG_PULL((lset_t)1 << (POLICY_MODECFG_PULL_IX)) | \
1320 POLICY_AGGRESSIVE((lset_t)1 << (POLICY_AGGRESSIVE_IX)) | \
1321 POLICY_OVERLAPIP((lset_t)1 << (POLICY_OVERLAPIP_IX)) | \
1322 POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)))
1323
1324 /*
1325 * Try instantiating something better.
1326 */
1327 if (best_spd_route == NULL((void*)0) && c->kind != CK_INSTANCE) {
1328 /*
1329 * Don't try to look for something else to
1330 * 'instantiate' when the current connection is
1331 * permanent.
1332 *
1333 * XXX: but c->kind could be CK_TEMPLATE?
1334 *
1335 * XXX: Is this missing an opportunity? Could there
1336 * be a better connection to instantiate when the
1337 * current one is permanent?
1338 *
1339 * XXX: 'instantiate', not really? The code below
1340 * sometimes blats the current instance with new
1341 * values - something that should not be done to a
1342 * permanent connection.
1343 */
1344 pexpect((c->kind == CK_PERMANENT) ||({ _Bool assertion__ = (c->kind == CK_PERMANENT) || (c->
kind == CK_TEMPLATE && c->config->sec_label.len
> 0); if (!assertion__) { where_t here_ = ({ static const
struct where here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1345, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_pexpect(logger_, here_, "%s", "(c->kind == CK_PERMANENT) || (c->kind == CK_TEMPLATE && c->config->sec_label.len > 0)"
); } assertion__; })
1345 (c->kind == CK_TEMPLATE && c->config->sec_label.len > 0))({ _Bool assertion__ = (c->kind == CK_PERMANENT) || (c->
kind == CK_TEMPLATE && c->config->sec_label.len
> 0); if (!assertion__) { where_t here_ = ({ static const
struct where here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1345, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_pexpect(logger_, here_, "%s", "(c->kind == CK_PERMANENT) || (c->kind == CK_TEMPLATE && c->config->sec_label.len > 0)"
); } assertion__; })
;
1346 dbg("no best spd route; but the current %s connection \"%s\" is not a CK_INSTANCE; giving up",{ 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; giving up"
, enum_name(&connection_kind_names, c->kind), c->name
); } }
1347 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; giving up"
, enum_name(&connection_kind_names, c->kind), c->name
); } }
;
1348 llog_sa(RC_LOG_SERIOUS, child, "No IKEv2 connection found with compatible Traffic Selectors")llog(RC_LOG_SERIOUS, (child)->sa.st_logger, "No IKEv2 connection found with compatible Traffic Selectors"
)
;
1349 return false0;
1350 }
1351
1352 if (best_spd_route == NULL((void*)0) && ((c->policy & POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX))) ||
1353 (c->policy & POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX))))) {
1354 /*
1355 * Is there something better than the current
1356 * connection?
1357 *
1358 * Rather than overwrite the current INSTANCE; would
1359 * it be better to instantiate a new instance, and
1360 * then replace it?
1361 *
1362 * Would also address the above.
1363 *
1364 * If the connection seems to be shared, this happens.
1365 */
1366 pexpect(c->kind == CK_INSTANCE)({ _Bool assertion__ = c->kind == CK_INSTANCE; if (!assertion__
) { where_t here_ = ({ static const struct where here = { .func
= __func__, .file = "programs/pluto/ikev2_ts.c", .line = 1366
, }; &here; }); const struct logger *logger_ = &failsafe_logger
; llog_pexpect(logger_, here_, "%s", "c->kind == CK_INSTANCE"
); } assertion__; })
;
1367 /* since an SPD_ROUTE wasn't found */
1368 passert(best_connection == c)({ _Bool assertion__ = best_connection == c; if (!assertion__
) { where_t here = ({ static const struct where here = { .func
= __func__, .file = "programs/pluto/ikev2_ts.c", .line = 1368
, }; &here; }); const struct logger *logger_ = &failsafe_logger
; llog_passert(logger_, here, "%s", "best_connection == c"); }
(void) 1; })
;
1369 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"
); } }
;
1370
1371 struct connection_query cq = { .where = HERE({ static const struct where here = { .func = __func__, .file
= "programs/pluto/ikev2_ts.c", .line = 1371, }; &here; }
)
, .c = NULL((void*)0), };
1372 while (new2old_connection(&cq)) {
1373 struct connection *t = cq.c;
1374 /* require a template */
1375 if (t->kind != CK_TEMPLATE) {
1376 continue;
1377 }
1378 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_logger(buf
, &failsafe_logger, DEBUG_STREAM), buf = ((void*)0))
{
1379 jam(buf, " investigating template \"%s\";",
1380 t->name);
1381 if (t->foodgroup != NULL((void*)0)) {
1382 jam(buf, " food-group=\"%s\"", t->foodgroup);
1383 }
1384 jam(buf, " policy=");
1385 jam_policy(buf, 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)))
);
1386 }
1387
1388 /*
1389 * Is it worth looking at the template.
1390 *
1391 * XXX: treat the combination the same as
1392 * group instance, like the old code did; is
1393 * this valid?
1394 */
1395 switch (c->policy & (POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) |
1396 POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)))) {
1397 case POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)):
1398 case POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)): /* XXX: true */
1399 /* XXX: why does this matter; does it imply t->foodgroup != NULL? */
1400 if (!LIN(POLICY_GROUPINSTANCE, t->policy)(((((lset_t)1 << (POLICY_GROUPINSTANCE_IX))) & (t->
policy)) == (((lset_t)1 << (POLICY_GROUPINSTANCE_IX))))
) {
1401 dbg(" skipping; not a group instance"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" skipping; not a group instance"); } }
;
1402 continue;
1403 }
1404 /* when OE, don't change food groups? */
1405 if (!streq(c->foodgroup, t->foodgroup)(strcmp((c->foodgroup), (t->foodgroup)) == 0)) {
1406 dbg(" skipping; wrong foodgroup name"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" skipping; wrong foodgroup name"); } }
;
1407 continue;
1408 }
1409 /* ??? why require current connection->name and t->name to be different */
1410 /* XXX: don't re-instantiate the same connection template???? */
1411 if (streq(c->name, t->name)(strcmp((c->name), (t->name)) == 0)) {
1412 dbg(" skipping; name same as current connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" skipping; name same as current connection"
); } }
;
1413 continue;
1414 }
1415 break;
1416 case POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)):
1417 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
))))
) {
1418 dbg(" skipping; cannot narrow"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" skipping; cannot narrow"); } }
;
1419 continue;
1420 }
1421 break;
1422 default:
1423 bad_case(c->policy)libreswan_bad_case("c->policy", (c->policy), ({ static const
struct where here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1423, }; &here; }))
; /* not quite true */
1424 }
1425
1426 /* require initiator's subnet <= T; why? */
1427 if (!selector_in_selector(c->spd.that.client, t->spd.that.client)) {
1428 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"
); } }
;
1429 continue;
1430 }
1431 /* require responder address match; why? */
1432 ip_address c_this_client_address = selector_prefix(c->spd.this.client);
1433 ip_address t_this_client_address = selector_prefix(t->spd.this.client);
1434 if (!address_eq_address(c_this_client_address, t_this_client_address)) {
1435 dbg(" skipping; responder addresses don't match"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" skipping; responder addresses don't match"
); } }
;
1436 continue;
1437 }
1438
1439 /* require a valid narrowed port? */
1440 enum fit fit;
1441 switch (c->policy & (POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) |
1442 POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)))) {
1443 case POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)):
1444 case POLICY_GROUPINSTANCE((lset_t)1 << (POLICY_GROUPINSTANCE_IX)) | POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)): /* XXX: true */
1445 /* exact match; XXX: 'cos that is what old code did */
1446 fit = END_EQUALS_TS;
1447 break;
1448 case POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)):
1449 /* narrow END's port to TS port */
1450 fit = END_WIDER_THAN_TS;
1451 break;
1452 default:
1453 bad_case(c->policy)libreswan_bad_case("c->policy", (c->policy), ({ static const
struct where here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1453, }; &here; }))
;
1454 }
1455
1456 passert(best_connection == c)({ _Bool assertion__ = best_connection == c; if (!assertion__
) { where_t here = ({ static const struct where here = { .func
= __func__, .file = "programs/pluto/ikev2_ts.c", .line = 1456
, }; &here; }); const struct logger *logger_ = &failsafe_logger
; llog_passert(logger_, here, "%s", "best_connection == c"); }
(void) 1; })
; /* aka st->st_connection, no leak */
1457 pexpect(best_connection == child->sa.st_connection)({ _Bool assertion__ = best_connection == child->sa.st_connection
; if (!assertion__) { where_t here_ = ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1457, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_pexpect(logger_, here_, "%s", "best_connection == child->sa.st_connection"
); } assertion__; })
;
1458 struct narrowed_ts n = narrow_request_ts(t, &tsp, fit);
1459 if (!n.ok) {
1460 continue;
1461 }
1462
1463 struct connection *s;
1464 if (v2_child_connection_probably_shared(child)) {
1465 /* instantiate it, filling in peer's ID */
1466 /* XXX: is best_sec_label ever non-NULL? */
1467 s = instantiate(t, &child->sa.st_connection->spd.that.host_addr,
1468 NULL((void*)0), best_sec_label);
1469 } else {
1470 s = child->sa.st_connection;
1471 }
1472 scribble_request_ts_on_connection(child, s, n);
1473
1474 /* switch */
1475 best_connection = s;
1476 best_spd_route = &best_connection->spd;
1477 break;
1478 }
1479 } else if (best_connection == c &&
1480 c->kind == CK_TEMPLATE &&
1481 c->config->sec_label.len > 0) {
1482 dbg(" instantiating template security label connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log(" instantiating template security label connection"
); } }
;
1483 /* sure looks like a sec-label template */
1484 struct narrowed_ts n = narrow_request_ts(c, &tsp, END_WIDER_THAN_TS);
1485 if (!n.ok) {
1486 return false0;
1487 }
1488
1489 struct connection *s = instantiate(c, &child->sa.st_connection->spd.that.host_addr,
1490 NULL((void*)0), best_sec_label);
1491 scribble_request_ts_on_connection(child, s, n);
1492
1493 /* switch */
1494 best_connection = s;
1495 best_spd_route = &best_connection->spd;
1496 }
1497
1498 if (best_spd_route == NULL((void*)0)) {
1499 dbg("giving up"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("giving up"); } }
;
1500 return false0;
1501 }
1502
1503 /*
1504 * this both replaces the child's connection, and flips any
1505 * underlying current-connection
1506 *
1507 * XXX: but this is responder code, there probably isn't a
1508 * current-connection - it would have gone straight to current
1509 * state.
1510 *
1511 * XXX: ah, but the state code does: set-state; set-connection
1512 * (yes order is wrong). Why does it bother?
1513 *
1514 * update_state_connection(), if the connection changes,
1515 * de-references the old connection; which is what really
1516 * matters
1517 */
1518 update_state_connection(&child->sa, best_connection);
1519
1520 return true1;
1521}
1522
1523/* check TS payloads, response */
1524bool_Bool v2_process_ts_response(struct child_sa *child,
1525 struct msg_digest *md)
1526{
1527 passert(child->sa.st_sa_role == SA_INITIATOR)({ _Bool assertion__ = child->sa.st_sa_role == SA_INITIATOR
; if (!assertion__) { where_t here = ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1527, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_passert(logger_, here, "%s", "child->sa.st_sa_role == SA_INITIATOR"
); } (void) 1; })
;
1528 passert(v2_msg_role(md) == MESSAGE_RESPONSE)({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_RESPONSE; if
(!assertion__) { where_t here = ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1528, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_passert(logger_, here, "%s", "v2_msg_role(md) == MESSAGE_RESPONSE"
); } (void) 1; })
;
1529
1530 struct connection *c = child->sa.st_connection;
1531
1532 struct traffic_selector_payloads tsp = empty_traffic_selectors;
1533 if (!v2_parse_tsp(md, &tsp, child->sa.st_logger)) {
1534 return false0;
1535 }
1536
1537 /* initiator */
1538 const struct spd_route *sra = &c->spd;
1539 const struct ends e = {
1540 .i = &sra->this,
1541 .r = &sra->that,
1542 };
1543 enum fit initiator_widening =
1544 (c->policy & POLICY_IKEV2_ALLOW_NARROWING((lset_t)1 << (POLICY_IKEV2_ALLOW_NARROWING_IX)))
1545 ? END_WIDER_THAN_TS
1546 : END_EQUALS_TS;
1547
1548 /* Returns NULL(ok), &null_shunk(skip), memory(ok). */
1549 shunk_t selected_sec_label = null_shunk;
1550 if (!score_tsp_sec_label(&tsp, c->config->sec_label,
1551 &selected_sec_label, child->sa.st_logger)) {
1552 /*
1553 * Either:
1554 * - Security label required, but not found.
1555 * OR
1556 * - Security label *not* required, but found.
1557 */
1558 return false0;
1559 }
1560
1561 struct best_score best = score_ends_iprange(initiator_widening, c, &e, &tsp);
1562
1563 if (!best.ok) {
1564 dbg("reject responder TSi/TSr Traffic Selector"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("reject responder TSi/TSr Traffic Selector"); }
}
;
1565 /* prevents parent from going to I3 */
1566 return false0;
1567 }
1568
1569 traffic_selector_to_end(best.tsi, &c->spd.this,
1570 "scribble accepted TSi response on initiator's this");
1571 traffic_selector_to_end(best.tsr, &c->spd.that,
1572 "scribble accepted TSr response on initiator's that");
1573
1574 return true1;
1575}
1576
1577/*
1578 * RFC 7296 https://tools.ietf.org/html/rfc7296#section-2.8
1579 * "when rekeying, the new Child SA SHOULD NOT have different Traffic
1580 * Selectors and algorithms than the old one."
1581 *
1582 * However, when narrowed down, the original TSi/TSr is wider than the
1583 * returned narrowed TSi/TSr. Windows 10 is known to use the original
1584 * and not the narrowed TSi/TSr.
1585 *
1586 * RFC 7296 #1.3.3 "The Traffic Selectors for traffic to be sent
1587 * on that SA are specified in the TS payloads in the response,
1588 * which may be a subset of what the initiator of the Child SA proposed."
1589 *
1590 * However, the rekey initiator, when it is the original initiator of
1591 * the Child SA, may request a super set. And responder should
1592 * respond with same set as initially negotiated, ie RFC 7296 #2.8
1593 *
1594 * See RFC 7296 Section 1.7. for the above change.
1595 * Significant Differences between RFC 4306 and RFC 5996
1596 *
1597 * We already matched the right connection by the SPI of v2N_REKEY_SA
1598 */
1599bool_Bool child_rekey_responder_ts_verify(struct child_sa *child, struct msg_digest *md)
1600{
1601 if (!pexpect(child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0)({ _Bool assertion__ = child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0
; if (!assertion__) { where_t here_ = ({ static const struct where
here = { .func = __func__, .file = "programs/pluto/ikev2_ts.c"
, .line = 1601, }; &here; }); const struct logger *logger_
= &failsafe_logger; llog_pexpect(logger_, here_, "%s", "child->sa.st_state->kind == STATE_V2_REKEY_CHILD_R0"
); } assertion__; })
)
1602 return false0;
1603
1604 const struct connection *c = child->sa.st_connection;
1605 struct traffic_selector_payloads their_tsp = empty_traffic_selectors;
1606
1607 if (!v2_parse_tsp(md, &their_tsp, child->sa.st_logger)) {
1608 log_state(RC_LOG_SERIOUS, &child->sa,
1609 "received malformed TSi/TSr payload(s)");
1610 return false0;
1611 }
1612
1613 const struct ends ends = {
1614 .i = &c->spd.that,
1615 .r = &c->spd.this,
1616 };
1617
1618 enum fit fitness = END_NARROWER_THAN_TS;
1619
1620 /* Returns NULL(ok), &null_shunk(skip), memory(ok). */
1621 shunk_t selected_sec_label = null_shunk;
1622 if (!score_tsp_sec_label(&their_tsp, c->config->sec_label,
1623 &selected_sec_label,
1624 child->sa.st_logger)) {
1625 /*
1626 * Either:
1627 * - Security label required, but not found.
1628 * OR
1629 * - Security label *not* required, but found.
1630 */
1631 log_state(RC_LOG_SERIOUS, &child->sa,
1632 "rekey: received Traffic Selectors mismatch configured selectors for Security Label");
1633 return false0;
1634 }
1635
1636 struct best_score score = score_ends_iprange(fitness, c, &ends, &their_tsp);
1637
1638 if (!score.ok) {
1639 log_state(RC_LOG_SERIOUS, &child->sa,
1640 "rekey: received Traffic Selectors does not contain existing IPsec SA Traffic Selectors");
1641 return false0;
1642 }
1643
1644 return true1;
1645}