1 /*	$OpenBSD: constraints.c,v 1.4 2024/03/15 05:14:16 tb Exp $ */
2 /*
3  * Copyright (c) 2023 Job Snijders <job@openbsd.org>
4  * Copyright (c) 2023 Theo Buehler <tb@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/socket.h>
20 
21 #include <arpa/inet.h>
22 
23 #include <ctype.h>
24 #include <err.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <libgen.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include <openssl/asn1.h>
35 #include <openssl/x509v3.h>
36 
37 #include "extern.h"
38 
39 struct tal_constraints {
40 	int		 fd;		/* constraints file descriptor or -1. */
41 	char		*fn;		/* constraints filename */
42 	char		*warn;		/* warning msg used for violations */
43 	struct cert_ip	*allow_ips;	/* list of allowed IP address ranges */
44 	size_t		 allow_ipsz;	/* length of "allow_ips" */
45 	struct cert_as	*allow_as;	/* allowed AS numbers and ranges */
46 	size_t		 allow_asz;	/* length of "allow_as" */
47 	struct cert_ip	*deny_ips;	/* forbidden IP address ranges */
48 	size_t		 deny_ipsz;	/* length of "deny_ips" */
49 	struct cert_as	*deny_as;	/* forbidden AS numbers and ranges */
50 	size_t		 deny_asz;	/* length of "deny_as" */
51 } tal_constraints[TALSZ_MAX];
52 
53 /*
54  * If there is a .constraints file next to a .tal file, load its contents
55  * into into tal_constraints[talid]. The load function only opens the fd
56  * and stores the filename. The actual parsing happens in constraints_parse().
57  * Resources of EE certs can then be constrained using constraints_validate().
58  */
59 
60 static void
constraints_load_talid(int talid)61 constraints_load_talid(int talid)
62 {
63 	const char	*tal = tals[talid];
64 	char		*constraints = NULL, *warning = NULL, *cbn;
65 	int		 fd;
66 	size_t		 len;
67 	int		 saved_errno;
68 
69 	tal_constraints[talid].fd = -1;
70 
71 	if (rtype_from_file_extension(tal) != RTYPE_TAL)
72 		return;
73 
74 	/* Replace .tal suffix with .constraints. */
75 	len = strlen(tal) - 4;
76 	if (asprintf(&constraints, "%.*s.constraints", (int)len, tal) == -1)
77 		err(1, NULL);
78 
79 	/* prepare warning message for when violations are detected */
80 	if ((cbn = basename(constraints)) == NULL)
81 		err(1, "basename");
82 	if (asprintf(&warning, "resource violates %s", cbn) == -1)
83 		err(1, NULL);
84 
85 	saved_errno = errno;
86 
87 	fd = open(constraints, O_RDONLY);
88 	if (fd == -1 && errno != ENOENT)
89 		err(1, "failed to load constraints for %s", tal);
90 
91 	tal_constraints[talid].fn = constraints;
92 	tal_constraints[talid].fd = fd;
93 	tal_constraints[talid].warn = warning;
94 
95 	errno = saved_errno;
96 }
97 
98 /*
99  * Iterate over all TALs and load the corresponding constraints files.
100  */
101 void
constraints_load(void)102 constraints_load(void)
103 {
104 	int	 talid;
105 
106 	for (talid = 0; talid < talsz; talid++)
107 		constraints_load_talid(talid);
108 }
109 
110 void
constraints_unload(void)111 constraints_unload(void)
112 {
113 	int	 saved_errno, talid;
114 
115 	saved_errno = errno;
116 	for (talid = 0; talid < talsz; talid++) {
117 		if (tal_constraints[talid].fd != -1)
118 			close(tal_constraints[talid].fd);
119 		free(tal_constraints[talid].fn);
120 		free(tal_constraints[talid].warn);
121 		tal_constraints[talid].fd = -1;
122 		tal_constraints[talid].fn = NULL;
123 		tal_constraints[talid].warn = NULL;
124 	}
125 	errno = saved_errno;
126 }
127 
128 /*
129  * Split a string at '-' and trim whitespace around the '-'.
130  * Assumes leading and trailing whitespace in p has already been trimmed.
131  */
132 static int
constraints_split_range(char * p,const char ** min,const char ** max)133 constraints_split_range(char *p, const char **min, const char **max)
134 {
135 	char	*pp;
136 
137 	*min = p;
138 	if ((*max = pp = strchr(p, '-')) == NULL)
139 		return 0;
140 
141 	/* Trim whitespace before '-'. */
142 	while (pp > *min && isspace((unsigned char)pp[-1]))
143 		pp--;
144 	*pp = '\0';
145 
146 	/* Skip past '-' and whitespace following it. */
147 	(*max)++;
148 	while (isspace((unsigned char)**max))
149 		(*max)++;
150 
151 	return 1;
152 }
153 
154 /*
155  * Helper functions to parse textual representations of IP prefixes or ranges.
156  * The RFC 3779 API has poor error reporting, so as a debugging aid, we call
157  * the prohibitively expensive X509v3_addr_canonize() in high verbosity mode.
158  */
159 
160 static void
constraints_parse_ip_prefix(const char * fn,const char * prefix,enum afi afi,IPAddrBlocks * addrs)161 constraints_parse_ip_prefix(const char *fn, const char *prefix, enum afi afi,
162     IPAddrBlocks *addrs)
163 {
164 	unsigned char	 addr[16] = { 0 };
165 	int		 af = afi == AFI_IPV4 ? AF_INET : AF_INET6;
166 	int		 plen;
167 
168 	if ((plen = inet_net_pton(af, prefix, addr, sizeof(addr))) == -1)
169 		errx(1, "%s: failed to parse %s", fn, prefix);
170 
171 	if (!X509v3_addr_add_prefix(addrs, afi, NULL, addr, plen))
172 		errx(1, "%s: failed to add prefix %s", fn, prefix);
173 
174 	if (verbose < 3)
175 		return;
176 
177 	if (!X509v3_addr_canonize(addrs))
178 		errx(1, "%s: failed to canonize with prefix %s", fn, prefix);
179 }
180 
181 static void
constraints_parse_ip_range(const char * fn,const char * min,const char * max,enum afi afi,IPAddrBlocks * addrs)182 constraints_parse_ip_range(const char *fn, const char *min, const char *max,
183     enum afi afi, IPAddrBlocks *addrs)
184 {
185 	unsigned char	 min_addr[16] = {0}, max_addr[16] = {0};
186 	int		 af = afi == AFI_IPV4 ? AF_INET : AF_INET6;
187 
188 	if (inet_pton(af, min, min_addr) != 1)
189 		errx(1, "%s: failed to parse %s", fn, min);
190 	if (inet_pton(af, max, max_addr) != 1)
191 		errx(1, "%s: failed to parse %s", fn, max);
192 
193 	if (!X509v3_addr_add_range(addrs, afi, NULL, min_addr, max_addr))
194 		errx(1, "%s: failed to add range %s--%s", fn, min, max);
195 
196 	if (verbose < 3)
197 		return;
198 
199 	if (!X509v3_addr_canonize(addrs))
200 		errx(1, "%s: failed to canonize with range %s--%s", fn,
201 		    min, max);
202 }
203 
204 static void
constraints_parse_ip(const char * fn,char * p,enum afi afi,IPAddrBlocks * addrs)205 constraints_parse_ip(const char *fn, char *p, enum afi afi, IPAddrBlocks *addrs)
206 {
207 	const char	*min, *max;
208 
209 	if (strchr(p, '-') == NULL) {
210 		constraints_parse_ip_prefix(fn, p, afi, addrs);
211 		return;
212 	}
213 
214 	if (!constraints_split_range(p, &min, &max))
215 		errx(1, "%s: failed to split range: %s", fn, p);
216 
217 	constraints_parse_ip_range(fn, min, max, afi, addrs);
218 }
219 
220 /*
221  * Helper functions to parse textual representations of AS numbers or ranges.
222  * The RFC 3779 API has poor error reporting, so as a debugging aid, we call
223  * the prohibitively expensive X509v3_asid_canonize() in high verbosity mode.
224  */
225 
226 static void
constraints_parse_asn(const char * fn,const char * asn,ASIdentifiers * asids)227 constraints_parse_asn(const char *fn, const char *asn, ASIdentifiers *asids)
228 {
229 	ASN1_INTEGER	*id;
230 
231 	if ((id = s2i_ASN1_INTEGER(NULL, asn)) == NULL)
232 		errx(1, "%s: failed to parse AS %s", fn, asn);
233 
234 	if (!X509v3_asid_add_id_or_range(asids, V3_ASID_ASNUM, id, NULL))
235 		errx(1, "%s: failed to add AS %s", fn, asn);
236 
237 	if (verbose < 3)
238 		return;
239 
240 	if (!X509v3_asid_canonize(asids))
241 		errx(1, "%s: failed to canonize with AS %s", fn, asn);
242 }
243 
244 static void
constraints_parse_asn_range(const char * fn,const char * min,const char * max,ASIdentifiers * asids)245 constraints_parse_asn_range(const char *fn, const char *min, const char *max,
246     ASIdentifiers *asids)
247 {
248 	ASN1_INTEGER	*min_as, *max_as;
249 
250 	if ((min_as = s2i_ASN1_INTEGER(NULL, min)) == NULL)
251 		errx(1, "%s: failed to parse AS %s", fn, min);
252 	if ((max_as = s2i_ASN1_INTEGER(NULL, max)) == NULL)
253 		errx(1, "%s: failed to parse AS %s", fn, max);
254 
255 	if (!X509v3_asid_add_id_or_range(asids, V3_ASID_ASNUM, min_as, max_as))
256 		errx(1, "%s: failed to add AS range %s--%s", fn, min, max);
257 
258 	if (verbose < 3)
259 		return;
260 
261 	if (!X509v3_asid_canonize(asids))
262 		errx(1, "%s: failed to canonize with AS range %s--%s", fn,
263 		    min, max);
264 }
265 
266 static void
constraints_parse_as(const char * fn,char * p,ASIdentifiers * asids)267 constraints_parse_as(const char *fn, char *p, ASIdentifiers *asids)
268 {
269 	const char	*min, *max;
270 
271 	if (strchr(p, '-') == NULL) {
272 		constraints_parse_asn(fn, p, asids);
273 		return;
274 	}
275 
276 	if (!constraints_split_range(p, &min, &max))
277 		errx(1, "%s: failed to split range: %s", fn, p);
278 
279 	constraints_parse_asn_range(fn, min, max, asids);
280 }
281 
282 /*
283  * Work around an annoying bug in X509v3_addr_add_range(). The upper bound
284  * of a range can have unused bits set in its ASN1_BIT_STRING representation.
285  * This triggers a check in ip_addr_parse(). A round trip through DER fixes
286  * this mess up. For extra special fun, {d2i,i2d}_IPAddrBlocks() isn't part
287  * of the API and implementing them for OpenSSL 3 is hairy, so do the round
288  * tripping once per address family.
289  */
290 static void
constraints_normalize_ip_addrblocks(const char * fn,IPAddrBlocks ** addrs)291 constraints_normalize_ip_addrblocks(const char *fn, IPAddrBlocks **addrs)
292 {
293 	IPAddrBlocks		*new_addrs;
294 	IPAddressFamily		*af;
295 	const unsigned char	*p;
296 	unsigned char		*der;
297 	int			 der_len, i;
298 
299 	if ((new_addrs = IPAddrBlocks_new()) == NULL)
300 		err(1, NULL);
301 
302 	for (i = 0; i < sk_IPAddressFamily_num(*addrs); i++) {
303 		af = sk_IPAddressFamily_value(*addrs, i);
304 
305 		der = NULL;
306 		if ((der_len = i2d_IPAddressFamily(af, &der)) <= 0)
307 			errx(1, "%s: failed to convert to DER", fn);
308 		p = der;
309 		if ((af = d2i_IPAddressFamily(NULL, &p, der_len)) == NULL)
310 			errx(1, "%s: failed to convert from DER", fn);
311 		free(der);
312 
313 		if (!sk_IPAddressFamily_push(new_addrs, af))
314 			errx(1, "%s: failed to push constraints", fn);
315 	}
316 
317 	IPAddrBlocks_free(*addrs);
318 	*addrs = new_addrs;
319 }
320 
321 /*
322  * If there is a constraints file for tals[talid], load it into a buffer
323  * and parse it line by line. Leverage the above parse helpers to build up
324  * IPAddrBlocks and ASIdentifiers. We use the RFC 3779 API to benefit from
325  * the limited abilities of X509v3_{addr,asid}_canonize() to sort and merge
326  * adjacent ranges. This doesn't deal with overlaps or duplicates, but it's
327  * better than nothing.
328  */
329 
330 static void
constraints_parse_talid(int talid)331 constraints_parse_talid(int talid)
332 {
333 	IPAddrBlocks	*allow_addrs, *deny_addrs;
334 	ASIdentifiers	*allow_asids, *deny_asids;
335 	FILE		*f;
336 	char		*fn, *p, *pp;
337 	struct cert_as	*allow_as = NULL, *deny_as = NULL;
338 	struct cert_ip	*allow_ips = NULL, *deny_ips = NULL;
339 	size_t		 allow_asz = 0, allow_ipsz = 0,
340 			 deny_asz = 0, deny_ipsz = 0;
341 	char		*line = NULL;
342 	size_t		 len = 0;
343 	ssize_t		 n;
344 	int		 fd, have_allow_as = 0, have_allow_ips = 0,
345 			 have_deny_as = 0, have_deny_ips = 0;
346 
347 	fd = tal_constraints[talid].fd;
348 	fn = tal_constraints[talid].fn;
349 	tal_constraints[talid].fd = -1;
350 	tal_constraints[talid].fn = NULL;
351 
352 	if (fd == -1) {
353 		free(fn);
354 		return;
355 	}
356 
357 	if ((f = fdopen(fd, "r")) == NULL)
358 		err(1, "fdopen");
359 
360 	if ((allow_addrs = IPAddrBlocks_new()) == NULL)
361 		err(1, NULL);
362 	if ((allow_asids = ASIdentifiers_new()) == NULL)
363 		err(1, NULL);
364 	if ((deny_addrs = IPAddrBlocks_new()) == NULL)
365 		err(1, NULL);
366 	if ((deny_asids = ASIdentifiers_new()) == NULL)
367 		err(1, NULL);
368 
369 	while ((n = getline(&line, &len, f)) != -1) {
370 		if (line[n - 1] == '\n')
371 			line[n - 1] = '\0';
372 
373 		p = line;
374 
375 		/* Zap leading whitespace */
376 		while (isspace((unsigned char)*p))
377 			p++;
378 
379 		/* Zap comments */
380 		if ((pp = strchr(p, '#')) != NULL)
381 			*pp = '\0';
382 
383 		/* Zap trailing whitespace */
384 		if (pp == NULL)
385 			pp = p + strlen(p);
386 		while (pp > p && isspace((unsigned char)pp[-1]))
387 			pp--;
388 		*pp = '\0';
389 
390 		if (strlen(p) == 0)
391 			continue;
392 
393 		if (strncmp(p, "allow", strlen("allow")) == 0) {
394 			p += strlen("allow");
395 
396 			/* Ensure there's whitespace and jump over it. */
397 			if (!isspace((unsigned char)*p))
398 				errx(1, "%s: failed to parse %s", fn, p);
399 			while (isspace((unsigned char)*p))
400 				p++;
401 
402 			if (strchr(p, '.') != NULL) {
403 				constraints_parse_ip(fn, p, AFI_IPV4,
404 				    allow_addrs);
405 				have_allow_ips = 1;
406 			} else if (strchr(p, ':') != NULL) {
407 				constraints_parse_ip(fn, p, AFI_IPV6,
408 				    allow_addrs);
409 				have_allow_ips = 1;
410 			} else {
411 				constraints_parse_as(fn, p, allow_asids);
412 				have_allow_as = 1;
413 			}
414 		} else if (strncmp(p, "deny", strlen("deny")) == 0) {
415 			p += strlen("deny");
416 
417 			/* Ensure there's whitespace and jump over it. */
418 			if (!isspace((unsigned char)*p))
419 				errx(1, "%s: failed to parse %s", fn, p);
420 			/* Zap leading whitespace */
421 			while (isspace((unsigned char)*p))
422 				p++;
423 
424 			if (strchr(p, '.') != NULL) {
425 				constraints_parse_ip(fn, p, AFI_IPV4,
426 				    deny_addrs);
427 				have_deny_ips = 1;
428 			} else if (strchr(p, ':') != NULL) {
429 				constraints_parse_ip(fn, p, AFI_IPV6,
430 				    deny_addrs);
431 				have_deny_ips = 1;
432 			} else {
433 				constraints_parse_as(fn, p, deny_asids);
434 				have_deny_as = 1;
435 			}
436 		} else
437 			errx(1, "%s: failed to parse %s", fn, p);
438 	}
439 	free(line);
440 
441 	if (ferror(f))
442 		err(1, "%s", fn);
443 	fclose(f);
444 
445 	if (!X509v3_addr_canonize(allow_addrs))
446 		errx(1, "%s: failed to canonize IP addresses allowlist", fn);
447 	if (!X509v3_asid_canonize(allow_asids))
448 		errx(1, "%s: failed to canonize AS numbers allowlist", fn);
449 	if (!X509v3_addr_canonize(deny_addrs))
450 		errx(1, "%s: failed to canonize IP addresses denylist", fn);
451 	if (!X509v3_asid_canonize(deny_asids))
452 		errx(1, "%s: failed to canonize AS numbers denylist", fn);
453 
454 	if (have_allow_as) {
455 		if (!sbgp_parse_assysnum(fn, allow_asids, &allow_as,
456 		    &allow_asz))
457 			errx(1, "%s: failed to parse AS identifiers allowlist",
458 			    fn);
459 	}
460 	if (have_deny_as) {
461 		if (!sbgp_parse_assysnum(fn, deny_asids, &deny_as,
462 		    &deny_asz))
463 			errx(1, "%s: failed to parse AS identifiers denylist",
464 			    fn);
465 	}
466 	if (have_allow_ips) {
467 		constraints_normalize_ip_addrblocks(fn, &allow_addrs);
468 
469 		if (!sbgp_parse_ipaddrblk(fn, allow_addrs, &allow_ips,
470 		    &allow_ipsz))
471 			errx(1, "%s: failed to parse IP addresses allowlist",
472 			    fn);
473 	}
474 	if (have_deny_ips) {
475 		constraints_normalize_ip_addrblocks(fn, &deny_addrs);
476 
477 		if (!sbgp_parse_ipaddrblk(fn, deny_addrs, &deny_ips,
478 		    &deny_ipsz))
479 			errx(1, "%s: failed to parse IP addresses denylist",
480 			    fn);
481 	}
482 
483 	tal_constraints[talid].allow_as = allow_as;
484 	tal_constraints[talid].allow_asz = allow_asz;
485 	tal_constraints[talid].allow_ips = allow_ips;
486 	tal_constraints[talid].allow_ipsz = allow_ipsz;
487 	tal_constraints[talid].deny_as = deny_as;
488 	tal_constraints[talid].deny_asz = deny_asz;
489 	tal_constraints[talid].deny_ips = deny_ips;
490 	tal_constraints[talid].deny_ipsz = deny_ipsz;
491 
492 	IPAddrBlocks_free(allow_addrs);
493 	IPAddrBlocks_free(deny_addrs);
494 	ASIdentifiers_free(allow_asids);
495 	ASIdentifiers_free(deny_asids);
496 
497 	free(fn);
498 }
499 
500 /*
501  * Iterate over all TALs and parse the constraints files loaded previously.
502  */
503 void
constraints_parse(void)504 constraints_parse(void)
505 {
506 	int	 talid;
507 
508 	for (talid = 0; talid < talsz; talid++)
509 		constraints_parse_talid(talid);
510 }
511 
512 static int
constraints_check_as(const char * fn,struct cert_as * cert,const struct cert_as * allow_as,size_t allow_asz,const struct cert_as * deny_as,size_t deny_asz)513 constraints_check_as(const char *fn, struct cert_as *cert,
514     const struct cert_as *allow_as, size_t allow_asz,
515     const struct cert_as *deny_as, size_t deny_asz)
516 {
517 	uint32_t min, max;
518 
519 	/* Inheriting EE resources are not to be constrained. */
520 	if (cert->type == CERT_AS_INHERIT)
521 		return 1;
522 
523 	if (cert->type == CERT_AS_ID) {
524 		min = cert->id;
525 		max = cert->id;
526 	} else {
527 		min = cert->range.min;
528 		max = cert->range.max;
529 	}
530 
531 	if (deny_as != NULL) {
532 		if (!as_check_overlap(cert, fn, deny_as, deny_asz, 1))
533 			return 0;
534 	}
535 	if (allow_as != NULL) {
536 		if (as_check_covered(min, max, allow_as, allow_asz) <= 0)
537 			return 0;
538 	}
539 	return 1;
540 }
541 
542 static int
constraints_check_ips(const char * fn,struct cert_ip * cert,const struct cert_ip * allow_ips,size_t allow_ipsz,const struct cert_ip * deny_ips,size_t deny_ipsz)543 constraints_check_ips(const char *fn, struct cert_ip *cert,
544     const struct cert_ip *allow_ips, size_t allow_ipsz,
545     const struct cert_ip *deny_ips, size_t deny_ipsz)
546 {
547 	/* Inheriting EE resources are not to be constrained. */
548 	if (cert->type == CERT_IP_INHERIT)
549 		return 1;
550 
551 	if (deny_ips != NULL) {
552 		if (!ip_addr_check_overlap(cert, fn, deny_ips, deny_ipsz, 1))
553 			return 0;
554 	}
555 	if (allow_ips != NULL) {
556 		if (ip_addr_check_covered(cert->afi, cert->min, cert->max,
557 		    allow_ips, allow_ipsz) <= 0)
558 			return 0;
559 	}
560 	return 1;
561 }
562 
563 /*
564  * Check whether an EE cert's resources are covered by its TAL's constraints.
565  * We accept certs with a negative talid as "unknown TAL" for filemode. The
566  * logic nearly duplicates valid_cert().
567  */
568 int
constraints_validate(const char * fn,const struct cert * cert)569 constraints_validate(const char *fn, const struct cert *cert)
570 {
571 	int		 talid = cert->talid;
572 	struct cert_as	*allow_as, *deny_as;
573 	struct cert_ip	*allow_ips, *deny_ips;
574 	size_t		 i, allow_asz, allow_ipsz, deny_asz, deny_ipsz;
575 
576 	/* Accept negative talid to bypass validation. */
577 	if (talid < 0)
578 		return 1;
579 	if (talid >= talsz)
580 		errx(1, "%s: talid out of range %d", fn, talid);
581 
582 	allow_as = tal_constraints[talid].allow_as;
583 	allow_asz = tal_constraints[talid].allow_asz;
584 	deny_as = tal_constraints[talid].deny_as;
585 	deny_asz = tal_constraints[talid].deny_asz;
586 
587 	for (i = 0; i < cert->asz; i++) {
588 		if (constraints_check_as(fn, &cert->as[i], allow_as, allow_asz,
589 		    deny_as, deny_asz))
590 			continue;
591 
592 		as_warn(fn, tal_constraints[talid].warn, &cert->as[i]);
593 		return 0;
594 	}
595 
596 	allow_ips = tal_constraints[talid].allow_ips;
597 	allow_ipsz = tal_constraints[talid].allow_ipsz;
598 	deny_ips = tal_constraints[talid].deny_ips;
599 	deny_ipsz = tal_constraints[talid].deny_ipsz;
600 
601 	for (i = 0; i < cert->ipsz; i++) {
602 		if (constraints_check_ips(fn, &cert->ips[i], allow_ips,
603 		    allow_ipsz, deny_ips, deny_ipsz))
604 			continue;
605 
606 		ip_warn(fn, tal_constraints[talid].warn, &cert->ips[i]);
607 		return 0;
608 	}
609 
610 	return 1;
611 }
612