Bug Summary

File:lib/libswan/ip_range.c
Warning:line 178, column 3
Value stored to 'afi' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ip_range.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 -mrelocation-model pic -pic-level 2 -pic-is-pie -mthread-model posix -mdisable-fp-elim -relaxed-aliasing -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib64/clang/8.0.0 -D TimeZoneOffset=timezone -D linux -D PIE -D NSS_IPSEC_PROFILE -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 USE_SYSTEMD_WATCHDOG -D HAVE_NM -D XAUTH_HAVE_PAM -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 DEFAULT_RUNDIR="/run/pluto" -D IPSEC_CONF="/etc/ipsec.conf" -D IPSEC_CONFDDIR="/etc/ipsec.d" -D IPSEC_NSSDIR="/etc/ipsec.d" -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/lib/libswan -I ../../include -I /usr/include/nss3 -I /usr/include/nspr4 -D HERE_BASENAME="ip_range.c" -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/8.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-missing-field-initializers -std=gnu99 -fdebug-compilation-dir /home/build/libreswan/lib/libswan -ferror-limit 19 -fmessage-length 0 -stack-protector 3 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /tmp/scan-build-2020-09-09-193337-25440-1 -x c /home/build/libreswan/lib/libswan/ip_range.c -faddrsig
1/* ip_range type, for libreswan
2 *
3 * Copyright (C) 2007 Michael Richardson <mcr@xelerance.com>
4 * Copyright (C) 2000 Henry Spencer.
5 * Copyright (C) 2013 Antony Antony <antony@phenome.org>
6 * Copyright (C) 2019 Andrew Cagney <cagney@gnu.org>
7 *
8 * This library is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Library General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <https://www.gnu.org/licenses/lgpl-2.1.txt>.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
16 * License for more details.
17 */
18
19/*
20 * convert from text form of IP address range specification to binary;
21 * and more minor utilities for mask length calculations for IKEv2
22 */
23
24#include <string.h>
25#include <arpa/inet.h> /* for ntohl() */
26
27#include "jambuf.h"
28#include "ip_range.h"
29#include "ip_info.h"
30#include "passert.h"
31#include "lswlog.h" /* for pexpect() */
32
33const ip_range unset_range; /* all zeros */
34
35ip_range range(const ip_address *start, const ip_address *end)
36{
37 /* does the caller know best? */
38 const struct ip_info *st = address_type(start);
39 const struct ip_info *et = address_type(end);
40 passert(st == et){ _Bool assertion__ = st == et; if (!assertion__) { lsw_passert_fail
((where_t) { .func = __func__, .basename = "ip_range.c" , .line
= 40}, "%s", "st == et"); } }
;
41 bool_Bool ss = address_is_specified(start);
42 bool_Bool es = address_is_specified(end);
43 passert(ss == es){ _Bool assertion__ = ss == es; if (!assertion__) { lsw_passert_fail
((where_t) { .func = __func__, .basename = "ip_range.c" , .line
= 43}, "%s", "ss == es"); } }
;
44 ip_range r = {
45 .start = *start,
46 .end = *end,
47 };
48 return r;
49}
50
51/*
52 * Calculate the number of significant bits in the size of the range.
53 * floor(lg(|high-low| + 1))
54 *
55 * ??? this really should use ip_range rather than a pair of ip_address values
56 */
57
58int iprange_bits(ip_address low, ip_address high)
59{
60 const struct ip_info *ht = address_type(&high);
61 const struct ip_info *lt = address_type(&low);
62 if (ht == NULL((void*)0) || lt == NULL((void*)0)) {
63 /* either invalid */
64 return -1;
65 }
66 if (ht != lt) {
67 return -1;
68 }
69
70 shunk_t hs = address_as_shunk(&high);
71 const uint8_t *hp = hs.ptr; /* cast const void * */
72 passert(hs.len > 0){ _Bool assertion__ = hs.len > 0; if (!assertion__) { lsw_passert_fail
((where_t) { .func = __func__, .basename = "ip_range.c" , .line
= 72}, "%s", "hs.len > 0"); } }
;
73 size_t n = hs.len;
74
75 shunk_t ls = address_as_shunk(&low);
76 const uint8_t *lp = ls.ptr; /* cast const void * */
77 passert(hs.len == ls.len){ _Bool assertion__ = hs.len == ls.len; if (!assertion__) { lsw_passert_fail
((where_t) { .func = __func__, .basename = "ip_range.c" , .line
= 77}, "%s", "hs.len == ls.len"); } }
;
78
79 ip_address diff = low; /* initialize all the contents to sensible values */
80 unsigned char *dp;
81 chunk_t diff_chunk = address_as_chunk(&diff);
82 dp = diff_chunk.ptr; /* cast void* */
83
84 unsigned lastnz = n;
85
86 /* subtract: d = h - l */
87 int carry = 0;
88 unsigned j;
89 for (j = n; j > 0; ) {
90 j--;
91 int val = hp[j] - lp[j] - carry;
92 if (val < 0) {
93 val += 0x100u;
94 carry = 1;
95 } else {
96 carry = 0;
97 }
98 dp[j] = val;
99 if (val != 0)
100 lastnz = j;
101 }
102
103 /* if the answer was negative, complement it */
104 if (carry != 0) {
105 lastnz = n; /* redundant, but not obviously so */
106 for (j = n; j > 0; ) {
107 j--;
108 int val = 0xFFu - dp[j] + carry;
109 if (val >= 0x100) {
110 val -= 0x100;
111 carry = 1; /* redundant, but not obviously so */
112 } else {
113 carry = 0;
114 }
115 dp[j] = val;
116 if (val != 0)
117 lastnz = j;
118 }
119 }
120
121 /* find leftmost bit in dp[lastnz] */
122 unsigned bo = 0;
123 if (lastnz != n) {
124 bo = 0;
125 for (unsigned m = 0x80u; (m & dp[lastnz]) == 0; m >>=1)
126 bo++;
127 }
128 return (n - lastnz) * 8 - bo;
129}
130
131static err_t extract_ends(const char *src, const struct ip_info *afi, ip_range *dst)
132{
133 const char *dash;
134 const char *high;
135 size_t hlen;
136 const char *oops;
137 size_t srclen = strlen(src);
138
139 dash = memchr(src, '-', srclen);
140 if (dash == NULL((void*)0))
141 return "not ipv4 address range with '-' or ipv6 subnet";
142
143 high = dash + 1;
144 hlen = srclen - (high - src);
145
146 /* extract start ip address */
147 oops = ttoaddr_num(src, dash - src, afi->af, &dst->start);
148 if (oops != NULL((void*)0))
149 return oops;
150
151 /* extract end ip address */
152 oops = ttoaddr_num(high, hlen, afi->af, &dst->end);
153 if (oops != NULL((void*)0))
154 return oops;
155
156 return NULL((void*)0);
157}
158
159/*
160 * ttorange - convert text v4 "addr1-addr2" to address_start address_end
161 * v6 allows "subnet/mask" to address_start address_end
162 */
163err_t ttorange(const char *src, const struct ip_info *afi, ip_range *dst,
164 struct logger *logger)
165{
166 err_t er = NULL((void*)0);
167
168 zero(dst)memset((dst), '\0', sizeof(*(dst)));
169 ip_range tmp = *dst; /* clear it */
170
171 ip_subnet v6_subnet;
172 er = ttosubnet(src, 0, AF_INET610, '6', &v6_subnet, logger);
173 if (er == NULL((void*)0)) {
174 if (v6_subnet.addr.hport != 0)
175 return "port must be zero for IPv6 addresspool";
176 tmp = range_from_subnet(&v6_subnet);
177 tmp.is_subnet = true1;
178 afi = &ipv6_info;
Value stored to 'afi' is never read
179 } else {
180 if (afi == NULL((void*)0)) {
181 afi = &ipv4_info;
182 if (extract_ends(src, afi, &tmp) != NULL((void*)0)) {
183 afi = &ipv6_info;
184 er = extract_ends(src, afi, &tmp);
185 if (er != NULL((void*)0))
186 return er; /* v4 error is ignored */
187
188 }
189 } else {
190 er = extract_ends(src, afi, &tmp);
191 if (er != NULL((void*)0))
192 return er;
193 }
194 }
195
196 if (addrcmp(&tmp.start, &tmp.end) > 0) {
197 return "start of range must not be greater than end";
198 }
199
200 if (address_is_any(&tmp.start) ||
201 address_is_any(&tmp.end)) {
202 return "'0.0.0.0 or ::0' not allowed in range";
203 }
204
205 /* We have validated the range. Now put bounds in dst. */
206 *dst = tmp;
207 return NULL((void*)0);
208}
209
210void jam_range(struct jambuf *buf, const ip_range *range)
211{
212 jam_address(buf, &range->start);
213 if (range_type(range) == &ipv6_info && range->is_subnet) {
214 ip_subnet tmp_subnet;
215 rangetosubnet(&range->start, &range->end, &tmp_subnet);
216 jam(buf, "/%u", tmp_subnet.maskbits);
217 } else {
218 jam(buf, "-");
219 jam_address(buf, &range->end);
220 }
221}
222
223const char *str_range(const ip_range *range, range_buf *out)
224{
225 struct jambuf buf = ARRAY_AS_JAMBUF(out->buf)array_as_jambuf((out->buf), sizeof(out->buf));
226 jam_range(&buf, range);
227 return out->buf;
228}
229
230ip_range range_from_subnet(const ip_subnet *subnet)
231{
232 ip_range r = {
233 /* SHHHHH */
234 .start = address_blit(endpoint_address(&subnet->addr),
235 &keep_bits, &clear_bits,
236 subnet->maskbits),
237 .end = address_blit(endpoint_address(&subnet->addr),
238 &keep_bits, &set_bits,
239 subnet->maskbits),
240 };
241 return r;
242}
243
244const struct ip_info *range_type(const ip_range *range)
245{
246 const struct ip_info *start = address_type(&range->start);
247 const struct ip_info *end = address_type(&range->end);
248 if (!pexpect(start == end)({ _Bool assertion__ = start == end; if (!assertion__) { log_pexpect
((where_t) { .func = __func__, .basename = "ip_range.c" , .line
= 248}, "%s", "start == end"); } assertion__; })
) {
249 return NULL((void*)0);
250 }
251 return start;
252}
253
254bool_Bool range_is_set(const ip_range *r)
255{
256 return range_type(r) != NULL((void*)0);
257}
258
259bool_Bool range_is_specified(const ip_range *r)
260{
261 bool_Bool start = address_is_specified(&r->start);
262 bool_Bool end = address_is_specified(&r->end);
263 if (!pexpect(start == end)({ _Bool assertion__ = start == end; if (!assertion__) { log_pexpect
((where_t) { .func = __func__, .basename = "ip_range.c" , .line
= 263}, "%s", "start == end"); } assertion__; })
) {
264 return false0;
265 }
266 return start;
267}
268
269bool_Bool range_size(ip_range *r, uint32_t *size) {
270
271 bool_Bool truncated = false0;
272 uint32_t n = *size = 0;
273
274 n = (ntohl_address(&r->end) - ntohl_address(&r->start));
275 if (address_type(&r->start) == &ipv6_info) {
276 int prefix_len = ipv6_info.mask_cnt - iprange_bits(r->start, r->end);
277 if (prefix_len < IPV6_MIN_POOL_PREFIX_LEN96) {
278 truncated = true1;
279 uint32_t s = ntohl_address(&r->start);
280 n = UINT32_MAX(4294967295U) - s;
281 }
282
283 if (n < UINT32_MAX(4294967295U))
284 n++;
285 else
286 truncated = true1;
287 } else {
288 /* IPv4 */
289 n++;
290 }
291
292 *size = n;
293 return truncated;
294}