Bug Summary

File:src/sbin/iked/vroute.c
Warning:line 678, column 2
Value stored to 'left' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name vroute.c -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 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/iked/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sbin/iked -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/iked/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/sbin/iked/vroute.c
1/* $OpenBSD: vroute.c,v 1.19 2023/06/13 12:34:12 tb Exp $ */
2
3/*
4 * Copyright (c) 2021 Tobias Heider <tobhe@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/ioctl.h>
20
21#include <net/if.h>
22#include <net/route.h>
23#include <netinet/in.h>
24#include <netinet6/in6_var.h>
25#include <netinet6/nd6.h>
26
27#include <event.h>
28#include <err.h>
29#include <errno(*__errno()).h>
30#include <poll.h>
31#include <string.h>
32#include <strings.h>
33#include <unistd.h>
34#include <netdb.h>
35
36#include <iked.h>
37
38#define ROUTE_SOCKET_BUF_SIZE16384 16384
39#define IKED_VROUTE_PRIO6 6
40
41#define ROUNDUP(a)(a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long
))
(a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
42
43int vroute_setroute(struct iked *, uint32_t, struct sockaddr *, uint8_t,
44 struct sockaddr *, int);
45int vroute_doroute(struct iked *, int, int, int, uint8_t, struct sockaddr *,
46 struct sockaddr *, struct sockaddr *, int *);
47int vroute_doaddr(struct iked *, char *, struct sockaddr *, struct sockaddr *, int);
48int vroute_dodns(struct iked *, struct sockaddr *, int, unsigned int);
49void vroute_cleanup(struct iked *);
50void vroute_rtmsg_cb(int, short, void *);
51
52void vroute_insertaddr(struct iked *, int, struct sockaddr *, struct sockaddr *);
53void vroute_removeaddr(struct iked *, int, struct sockaddr *, struct sockaddr *);
54void vroute_insertdns(struct iked *, int, struct sockaddr *);
55void vroute_removedns(struct iked *, int, struct sockaddr *);
56void vroute_insertroute(struct iked *, int, struct sockaddr *, struct sockaddr *);
57void vroute_removeroute(struct iked *, int, struct sockaddr *, struct sockaddr *);
58
59struct vroute_addr {
60 int va_ifidx;
61 struct sockaddr_storage va_addr;
62 struct sockaddr_storage va_mask;
63 TAILQ_ENTRY(vroute_addr)struct { struct vroute_addr *tqe_next; struct vroute_addr **tqe_prev
; }
va_entry;
64};
65TAILQ_HEAD(vroute_addrs, vroute_addr)struct vroute_addrs { struct vroute_addr *tqh_first; struct vroute_addr
**tqh_last; }
;
66
67struct vroute_route {
68 int vr_rdomain;
69 int vr_flags;
70 struct sockaddr_storage vr_dest;
71 struct sockaddr_storage vr_mask;
72 TAILQ_ENTRY(vroute_route)struct { struct vroute_route *tqe_next; struct vroute_route *
*tqe_prev; }
vr_entry;
73};
74TAILQ_HEAD(vroute_routes, vroute_route)struct vroute_routes { struct vroute_route *tqh_first; struct
vroute_route **tqh_last; }
;
75
76struct vroute_dns {
77 struct sockaddr_storage vd_addr;
78 int vd_ifidx;
79 TAILQ_ENTRY(vroute_dns)struct { struct vroute_dns *tqe_next; struct vroute_dns **tqe_prev
; }
vd_entry;
80};
81TAILQ_HEAD(vroute_dnss, vroute_dns)struct vroute_dnss { struct vroute_dns *tqh_first; struct vroute_dns
**tqh_last; }
;
82
83struct iked_vroute_sc {
84 struct vroute_addrs ivr_addrs;
85 struct vroute_routes ivr_routes;
86 struct vroute_dnss ivr_dnss;
87 struct event ivr_routeev;
88 int ivr_iosock;
89 int ivr_iosock6;
90 int ivr_rtsock;
91 int ivr_rtseq;
92 pid_t ivr_pid;
93};
94
95struct vroute_msg {
96 struct rt_msghdr vm_rtm;
97 uint8_t vm_space[512];
98};
99
100int vroute_process(struct iked *, int msglen, struct vroute_msg *,
101 struct sockaddr *, struct sockaddr *, struct sockaddr *, int *);
102
103void
104vroute_rtmsg_cb(int fd, short events, void *arg)
105{
106 struct iked *env = (struct iked *) arg;
107 struct iked_vroute_sc *ivr = env->sc_vroute;
108 struct vroute_dns *dns;
109 static uint8_t *buf;
110 struct rt_msghdr *rtm;
111 ssize_t n;
112
113 if (buf == NULL((void *)0)) {
114 buf = malloc(ROUTE_SOCKET_BUF_SIZE16384);
115 if (buf == NULL((void *)0))
116 fatal("malloc");
117 }
118 rtm = (struct rt_msghdr *)buf;
119 if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE16384)) == -1) {
120 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
121 return;
122 log_warn("%s: read error", __func__);
123 return;
124 }
125
126 if (n == 0)
127 fatal("routing socket closed");
128
129 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
130 log_warnx("partial rtm of %zd in buffer", n);
131 return;
132 }
133
134 if (rtm->rtm_version != RTM_VERSION5)
135 return;
136
137 switch(rtm->rtm_type) {
138 case RTM_PROPOSAL0x13:
139 if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT62) {
140 TAILQ_FOREACH(dns, &ivr->ivr_dnss, vd_entry)for((dns) = ((&ivr->ivr_dnss)->tqh_first); (dns) !=
((void *)0); (dns) = ((dns)->vd_entry.tqe_next))
{
141 log_debug("%s: got solicit", __func__);
142 vroute_dodns(env, (struct sockaddr *) &dns->vd_addr,
143 1, dns->vd_ifidx);
144 }
145 }
146 break;
147 default:
148 log_debug("%s: unexpected RTM: %d", __func__, rtm->rtm_type);
149 break;
150 }
151}
152
153void
154vroute_init(struct iked *env)
155{
156 struct iked_vroute_sc *ivr;
157 int rtfilter;
158
159 ivr = calloc(1, sizeof(*ivr));
160 if (ivr == NULL((void *)0))
161 fatal("%s: calloc.", __func__);
162
163 if ((ivr->ivr_iosock = socket(AF_INET2, SOCK_DGRAM2, 0)) == -1)
164 fatal("%s: failed to create ioctl socket", __func__);
165
166 if ((ivr->ivr_iosock6 = socket(AF_INET624, SOCK_DGRAM2, 0)) == -1)
167 fatal("%s: failed to create ioctl socket", __func__);
168
169 if ((ivr->ivr_rtsock = socket(AF_ROUTE17, SOCK_RAW3, AF_UNSPEC0)) == -1)
170 fatal("%s: failed to create routing socket", __func__);
171
172 rtfilter = ROUTE_FILTER(RTM_GET)(1 << (0x4)) | ROUTE_FILTER(RTM_PROPOSAL)(1 << (0x13));
173 if (setsockopt(ivr->ivr_rtsock, AF_ROUTE17, ROUTE_MSGFILTER1, &rtfilter,
174 sizeof(rtfilter)) == -1)
175 fatal("%s: setsockopt(ROUTE_MSGFILTER)", __func__);
176
177 TAILQ_INIT(&ivr->ivr_addrs)do { (&ivr->ivr_addrs)->tqh_first = ((void *)0); (&
ivr->ivr_addrs)->tqh_last = &(&ivr->ivr_addrs
)->tqh_first; } while (0)
;
178 TAILQ_INIT(&ivr->ivr_dnss)do { (&ivr->ivr_dnss)->tqh_first = ((void *)0); (&
ivr->ivr_dnss)->tqh_last = &(&ivr->ivr_dnss)
->tqh_first; } while (0)
;
179 TAILQ_INIT(&ivr->ivr_routes)do { (&ivr->ivr_routes)->tqh_first = ((void *)0); (
&ivr->ivr_routes)->tqh_last = &(&ivr->ivr_routes
)->tqh_first; } while (0)
;
180
181 ivr->ivr_pid = getpid();
182
183 env->sc_vroute = ivr;
184
185 event_set(&ivr->ivr_routeev, ivr->ivr_rtsock, EV_READ0x02 | EV_PERSIST0x10,
186 vroute_rtmsg_cb, env);
187 event_add(&ivr->ivr_routeev, NULL((void *)0));
188}
189
190void
191vroute_cleanup(struct iked *env)
192{
193 char ifname[IF_NAMESIZE16];
194 struct iked_vroute_sc *ivr = env->sc_vroute;
195 struct vroute_addr *addr;
196 struct vroute_route *route;
197 struct vroute_dns *dns;
198
199 while ((addr = TAILQ_FIRST(&ivr->ivr_addrs)((&ivr->ivr_addrs)->tqh_first))) {
200 if_indextoname(addr->va_ifidx, ifname);
201 vroute_doaddr(env, ifname,
202 (struct sockaddr *)&addr->va_addr,
203 (struct sockaddr *)&addr->va_mask, 0);
204 TAILQ_REMOVE(&ivr->ivr_addrs, addr, va_entry)do { if (((addr)->va_entry.tqe_next) != ((void *)0)) (addr
)->va_entry.tqe_next->va_entry.tqe_prev = (addr)->va_entry
.tqe_prev; else (&ivr->ivr_addrs)->tqh_last = (addr
)->va_entry.tqe_prev; *(addr)->va_entry.tqe_prev = (addr
)->va_entry.tqe_next; ; ; } while (0)
;
205 free(addr);
206 }
207
208 while ((route = TAILQ_FIRST(&ivr->ivr_routes)((&ivr->ivr_routes)->tqh_first))) {
209 vroute_doroute(env, RTF_UP0x1 | RTF_GATEWAY0x2 | RTF_STATIC0x800,
210 route->vr_flags, route->vr_rdomain, RTM_DELETE0x2,
211 (struct sockaddr *)&route->vr_dest,
212 (struct sockaddr *)&route->vr_mask,
213 NULL((void *)0), NULL((void *)0));
214 TAILQ_REMOVE(&ivr->ivr_routes, route, vr_entry)do { if (((route)->vr_entry.tqe_next) != ((void *)0)) (route
)->vr_entry.tqe_next->vr_entry.tqe_prev = (route)->vr_entry
.tqe_prev; else (&ivr->ivr_routes)->tqh_last = (route
)->vr_entry.tqe_prev; *(route)->vr_entry.tqe_prev = (route
)->vr_entry.tqe_next; ; ; } while (0)
;
215 free(route);
216 }
217
218 while ((dns = TAILQ_FIRST(&ivr->ivr_dnss)((&ivr->ivr_dnss)->tqh_first))) {
219 vroute_dodns(env, (struct sockaddr *)&dns->vd_addr, 0,
220 dns->vd_ifidx);
221 TAILQ_REMOVE(&ivr->ivr_dnss, dns, vd_entry)do { if (((dns)->vd_entry.tqe_next) != ((void *)0)) (dns)->
vd_entry.tqe_next->vd_entry.tqe_prev = (dns)->vd_entry.
tqe_prev; else (&ivr->ivr_dnss)->tqh_last = (dns)->
vd_entry.tqe_prev; *(dns)->vd_entry.tqe_prev = (dns)->vd_entry
.tqe_next; ; ; } while (0)
;
222 free(dns);
223 }
224}
225
226int
227vroute_setaddr(struct iked *env, int add, struct sockaddr *addr,
228 int mask, unsigned int ifidx)
229{
230 struct iovec iov[4];
231 int iovcnt;
232 struct sockaddr_in mask4;
233 struct sockaddr_in6 mask6;
234
235 iovcnt = 0;
236 iov[0].iov_base = addr;
237 iov[0].iov_len = addr->sa_len;
238 iovcnt++;
239
240 switch(addr->sa_family) {
241 case AF_INET2:
242 bzero(&mask, sizeof(mask));
243 mask4.sin_addr.s_addr = prefixlen2mask(mask ? mask : 32);
244 mask4.sin_family = AF_INET2;
245 mask4.sin_len = sizeof(mask4);
246
247 iov[1].iov_base = &mask4;
248 iov[1].iov_len = sizeof(mask4);
249 iovcnt++;
250 break;
251 case AF_INET624:
252 bzero(&mask6, sizeof(mask6));
253 prefixlen2mask6(mask ? mask : 128,
254 (uint32_t *)&mask6.sin6_addr.s6_addr__u6_addr.__u6_addr8);
255 mask6.sin6_family = AF_INET624;
256 mask6.sin6_len = sizeof(mask6);
257 iov[1].iov_base = &mask6;
258 iov[1].iov_len = sizeof(mask6);
259 iovcnt++;
260 break;
261 default:
262 return -1;
263 }
264
265 iov[2].iov_base = &ifidx;
266 iov[2].iov_len = sizeof(ifidx);
267 iovcnt++;
268
269 return (proc_composev(&env->sc_ps, PROC_PARENT,
270 add ? IMSG_IF_ADDADDR : IMSG_IF_DELADDR, iov, iovcnt));
271}
272
273int
274vroute_getaddr(struct iked *env, struct imsg *imsg)
275{
276 char ifname[IF_NAMESIZE16];
277 struct sockaddr *addr, *mask;
278 uint8_t *ptr;
279 size_t left;
280 int af, add;
281 unsigned int ifidx;
282
283 ptr = imsg->data;
284 left = IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr));
285
286 if (left < sizeof(*addr))
287 fatalx("bad length imsg received");
288
289 addr = (struct sockaddr *) ptr;
290 af = addr->sa_family;
291
292 if (left < addr->sa_len)
293 fatalx("bad length imsg received");
294 ptr += addr->sa_len;
295 left -= addr->sa_len;
296
297 if (left < sizeof(*mask))
298 fatalx("bad length imsg received");
299 mask = (struct sockaddr *) ptr;
300 if (mask->sa_family != af)
301 return (-1);
302
303 if (left < mask->sa_len)
304 fatalx("bad length imsg received");
305 ptr += mask->sa_len;
306 left -= mask->sa_len;
307
308 if (left != sizeof(ifidx))
309 fatalx("bad length imsg received");
310 memcpy(&ifidx, ptr, sizeof(ifidx));
311 ptr += sizeof(ifidx);
312 left -= sizeof(ifidx);
313
314 add = (imsg->hdr.type == IMSG_IF_ADDADDR);
315 /* Store address for cleanup */
316 if (add)
317 vroute_insertaddr(env, ifidx, addr, mask);
318 else
319 vroute_removeaddr(env, ifidx, addr, mask);
320
321 if_indextoname(ifidx, ifname);
322 return (vroute_doaddr(env, ifname, addr, mask, add));
323}
324
325int
326vroute_setdns(struct iked *env, int add, struct sockaddr *addr,
327 unsigned int ifidx)
328{
329 struct iovec iov[2];
330
331 iov[0].iov_base = addr;
332 iov[0].iov_len = addr->sa_len;
333
334 iov[1].iov_base = &ifidx;
335 iov[1].iov_len = sizeof(ifidx);
336
337 return (proc_composev(&env->sc_ps, PROC_PARENT,
338 add ? IMSG_VDNS_ADD: IMSG_VDNS_DEL, iov, 2));
339}
340
341int
342vroute_getdns(struct iked *env, struct imsg *imsg)
343{
344 struct sockaddr *dns;
345 uint8_t *ptr;
346 size_t left;
347 int add;
348 unsigned int ifidx;
349
350 ptr = imsg->data;
351 left = IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr));
352
353 if (left < sizeof(*dns))
354 fatalx("bad length imsg received");
355
356 dns = (struct sockaddr *) ptr;
357 if (left < dns->sa_len)
358 fatalx("bad length imsg received");
359 ptr += dns->sa_len;
360 left -= dns->sa_len;
361
362 if (left != sizeof(ifidx))
363 fatalx("bad length imsg received");
364 memcpy(&ifidx, ptr, sizeof(ifidx));
365 ptr += sizeof(ifidx);
366 left -= sizeof(ifidx);
367
368 add = (imsg->hdr.type == IMSG_VDNS_ADD);
369 if (add) {
370 vroute_insertdns(env, ifidx, dns);
371 } else {
372 vroute_removedns(env, ifidx, dns);
373 }
374
375 return (vroute_dodns(env, dns, add, ifidx));
376}
377
378void
379vroute_insertroute(struct iked *env, int rdomain, struct sockaddr *dest,
380 struct sockaddr *mask)
381{
382 struct iked_vroute_sc *ivr = env->sc_vroute;
383 struct vroute_route *route;
384
385 route = calloc(1, sizeof(*route));
386 if (route == NULL((void *)0))
387 fatalx("%s: calloc.", __func__);
388
389 if (dest != NULL((void *)0)) {
390 route->vr_flags |= RTA_DST0x1;
391 memcpy(&route->vr_dest, dest, dest->sa_len);
392 }
393 if (mask != NULL((void *)0)) {
394 route->vr_flags |= RTA_NETMASK0x4;
395 memcpy(&route->vr_mask, mask, mask->sa_len);
396 }
397 route->vr_rdomain = rdomain;
398
399 TAILQ_INSERT_TAIL(&ivr->ivr_routes, route, vr_entry)do { (route)->vr_entry.tqe_next = ((void *)0); (route)->
vr_entry.tqe_prev = (&ivr->ivr_routes)->tqh_last; *
(&ivr->ivr_routes)->tqh_last = (route); (&ivr->
ivr_routes)->tqh_last = &(route)->vr_entry.tqe_next
; } while (0)
;
400}
401
402void
403vroute_removeroute(struct iked *env, int rdomain, struct sockaddr *dest,
404 struct sockaddr *mask)
405{
406 struct iked_vroute_sc *ivr = env->sc_vroute;
407 struct vroute_route *route, *troute;
408
409 TAILQ_FOREACH_SAFE(route, &ivr->ivr_routes, vr_entry, troute)for ((route) = ((&ivr->ivr_routes)->tqh_first); (route
) != ((void *)0) && ((troute) = ((route)->vr_entry
.tqe_next), 1); (route) = (troute))
{
410 if (sockaddr_cmp(dest, (struct sockaddr *)&route->vr_dest, -1))
411 continue;
412 if (mask && !(route->vr_flags & RTA_NETMASK0x4))
413 continue;
414 if (mask &&
415 sockaddr_cmp(mask, (struct sockaddr *)&route->vr_mask, -1))
416 continue;
417 if (rdomain != route->vr_rdomain)
418 continue;
419 TAILQ_REMOVE(&ivr->ivr_routes, route, vr_entry)do { if (((route)->vr_entry.tqe_next) != ((void *)0)) (route
)->vr_entry.tqe_next->vr_entry.tqe_prev = (route)->vr_entry
.tqe_prev; else (&ivr->ivr_routes)->tqh_last = (route
)->vr_entry.tqe_prev; *(route)->vr_entry.tqe_prev = (route
)->vr_entry.tqe_next; ; ; } while (0)
;
420 free(route);
421 }
422}
423
424void
425vroute_insertdns(struct iked *env, int ifidx, struct sockaddr *addr)
426{
427 struct iked_vroute_sc *ivr = env->sc_vroute;
428 struct vroute_dns *dns;
429
430 dns = calloc(1, sizeof(*dns));
431 if (dns == NULL((void *)0))
432 fatalx("%s: calloc.", __func__);
433
434 memcpy(&dns->vd_addr, addr, addr->sa_len);
435 dns->vd_ifidx = ifidx;
436
437 TAILQ_INSERT_TAIL(&ivr->ivr_dnss, dns, vd_entry)do { (dns)->vd_entry.tqe_next = ((void *)0); (dns)->vd_entry
.tqe_prev = (&ivr->ivr_dnss)->tqh_last; *(&ivr->
ivr_dnss)->tqh_last = (dns); (&ivr->ivr_dnss)->tqh_last
= &(dns)->vd_entry.tqe_next; } while (0)
;
438}
439
440void
441vroute_removedns(struct iked *env, int ifidx, struct sockaddr *addr)
442{
443 struct iked_vroute_sc *ivr = env->sc_vroute;
444 struct vroute_dns *dns, *tdns;
445
446 TAILQ_FOREACH_SAFE(dns, &ivr->ivr_dnss, vd_entry, tdns)for ((dns) = ((&ivr->ivr_dnss)->tqh_first); (dns) !=
((void *)0) && ((tdns) = ((dns)->vd_entry.tqe_next
), 1); (dns) = (tdns))
{
447 if (ifidx != dns->vd_ifidx)
448 continue;
449 if (sockaddr_cmp(addr, (struct sockaddr *) &dns->vd_addr, -1))
450 continue;
451
452 TAILQ_REMOVE(&ivr->ivr_dnss, dns, vd_entry)do { if (((dns)->vd_entry.tqe_next) != ((void *)0)) (dns)->
vd_entry.tqe_next->vd_entry.tqe_prev = (dns)->vd_entry.
tqe_prev; else (&ivr->ivr_dnss)->tqh_last = (dns)->
vd_entry.tqe_prev; *(dns)->vd_entry.tqe_prev = (dns)->vd_entry
.tqe_next; ; ; } while (0)
;
453 free(dns);
454 }
455}
456
457void
458vroute_insertaddr(struct iked *env, int ifidx, struct sockaddr *addr,
459 struct sockaddr *mask)
460{
461 struct iked_vroute_sc *ivr = env->sc_vroute;
462 struct vroute_addr *vaddr;
463
464 vaddr = calloc(1, sizeof(*vaddr));
465 if (vaddr == NULL((void *)0))
466 fatalx("%s: calloc.", __func__);
467
468 memcpy(&vaddr->va_addr, addr, addr->sa_len);
469 memcpy(&vaddr->va_mask, mask, mask->sa_len);
470 vaddr->va_ifidx = ifidx;
471
472 TAILQ_INSERT_TAIL(&ivr->ivr_addrs, vaddr, va_entry)do { (vaddr)->va_entry.tqe_next = ((void *)0); (vaddr)->
va_entry.tqe_prev = (&ivr->ivr_addrs)->tqh_last; *(
&ivr->ivr_addrs)->tqh_last = (vaddr); (&ivr->
ivr_addrs)->tqh_last = &(vaddr)->va_entry.tqe_next;
} while (0)
;
473}
474
475void
476vroute_removeaddr(struct iked *env, int ifidx, struct sockaddr *addr,
477 struct sockaddr *mask)
478{
479 struct iked_vroute_sc *ivr = env->sc_vroute;
480 struct vroute_addr *vaddr, *tvaddr;
481
482 TAILQ_FOREACH_SAFE(vaddr, &ivr->ivr_addrs, va_entry, tvaddr)for ((vaddr) = ((&ivr->ivr_addrs)->tqh_first); (vaddr
) != ((void *)0) && ((tvaddr) = ((vaddr)->va_entry
.tqe_next), 1); (vaddr) = (tvaddr))
{
483 if (sockaddr_cmp(addr, (struct sockaddr *)&vaddr->va_addr, -1))
484 continue;
485 if (sockaddr_cmp(mask, (struct sockaddr *)&vaddr->va_mask, -1))
486 continue;
487 if (ifidx != vaddr->va_ifidx)
488 continue;
489 TAILQ_REMOVE(&ivr->ivr_addrs, vaddr, va_entry)do { if (((vaddr)->va_entry.tqe_next) != ((void *)0)) (vaddr
)->va_entry.tqe_next->va_entry.tqe_prev = (vaddr)->va_entry
.tqe_prev; else (&ivr->ivr_addrs)->tqh_last = (vaddr
)->va_entry.tqe_prev; *(vaddr)->va_entry.tqe_prev = (vaddr
)->va_entry.tqe_next; ; ; } while (0)
;
490 free(vaddr);
491 }
492}
493
494int
495vroute_setaddroute(struct iked *env, uint8_t rdomain, struct sockaddr *dst,
496 uint8_t mask, struct sockaddr *ifa)
497{
498 return (vroute_setroute(env, rdomain, dst, mask, ifa,
499 IMSG_VROUTE_ADD));
500}
501
502int
503vroute_setcloneroute(struct iked *env, uint8_t rdomain, struct sockaddr *dst,
504 uint8_t mask, struct sockaddr *addr)
505{
506 return (vroute_setroute(env, rdomain, dst, mask, addr,
507 IMSG_VROUTE_CLONE));
508}
509
510int
511vroute_setdelroute(struct iked *env, uint8_t rdomain, struct sockaddr *dst,
512 uint8_t mask, struct sockaddr *addr)
513{
514 return (vroute_setroute(env, rdomain, dst, mask, addr,
515 IMSG_VROUTE_DEL));
516}
517
518int
519vroute_setroute(struct iked *env, uint32_t rdomain, struct sockaddr *dst,
520 uint8_t mask, struct sockaddr *addr, int type)
521{
522 struct sockaddr_storage sa;
523 struct sockaddr_in *in;
524 struct sockaddr_in6 *in6;
525 struct iovec iov[5];
526 int iovcnt = 0;
527 uint8_t af;
528
529 if (addr && dst->sa_family != addr->sa_family)
530 return (-1);
531 af = dst->sa_family;
532
533 iov[iovcnt].iov_base = &rdomain;
534 iov[iovcnt].iov_len = sizeof(rdomain);
535 iovcnt++;
536
537 iov[iovcnt].iov_base = dst;
538 iov[iovcnt].iov_len = dst->sa_len;
539 iovcnt++;
540
541 if (type != IMSG_VROUTE_CLONE && addr) {
542 bzero(&sa, sizeof(sa));
543 switch(af) {
544 case AF_INET2:
545 in = (struct sockaddr_in *)&sa;
546 in->sin_addr.s_addr = prefixlen2mask(mask);
547 in->sin_family = af;
548 in->sin_len = sizeof(*in);
549 iov[iovcnt].iov_base = in;
550 iov[iovcnt].iov_len = sizeof(*in);
551 iovcnt++;
552 break;
553 case AF_INET624:
554 in6 = (struct sockaddr_in6 *)&sa;
555 prefixlen2mask6(mask,
556 (uint32_t *)in6->sin6_addr.s6_addr__u6_addr.__u6_addr8);
557 in6->sin6_family = af;
558 in6->sin6_len = sizeof(*in6);
559 iov[iovcnt].iov_base = in6;
560 iov[iovcnt].iov_len = sizeof(*in6);
561 iovcnt++;
562 break;
563 }
564
565 iov[iovcnt].iov_base = addr;
566 iov[iovcnt].iov_len = addr->sa_len;
567 iovcnt++;
568 }
569
570 return (proc_composev(&env->sc_ps, PROC_PARENT, type, iov, iovcnt));
571}
572
573int
574vroute_getroute(struct iked *env, struct imsg *imsg)
575{
576 struct sockaddr *dest, *mask = NULL((void *)0), *gateway = NULL((void *)0);
577 uint8_t *ptr;
578 size_t left;
579 int addrs = 0;
580 int type, flags;
581 uint32_t rdomain;
582
583 ptr = (uint8_t *)imsg->data;
584 left = IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr));
585
586 if (left < sizeof(rdomain))
587 return (-1);
588 rdomain = *ptr;
589 ptr += sizeof(rdomain);
590 left -= sizeof(rdomain);
591
592 if (left < sizeof(struct sockaddr))
593 return (-1);
594 dest = (struct sockaddr *)ptr;
595 if (left < dest->sa_len)
596 return (-1);
597 socket_setport(dest, 0);
598 ptr += dest->sa_len;
599 left -= dest->sa_len;
600 addrs |= RTA_DST0x1;
601
602 flags = RTF_UP0x1 | RTF_GATEWAY0x2 | RTF_STATIC0x800;
603 if (left != 0) {
604 if (left < sizeof(struct sockaddr))
605 return (-1);
606 mask = (struct sockaddr *)ptr;
607 if (left < mask->sa_len)
608 return (-1);
609 socket_setport(mask, 0);
610 ptr += mask->sa_len;
611 left -= mask->sa_len;
612 addrs |= RTA_NETMASK0x4;
613
614 if (left < sizeof(struct sockaddr))
615 return (-1);
616 gateway = (struct sockaddr *)ptr;
617 if (left < gateway->sa_len)
618 return (-1);
619 socket_setport(gateway, 0);
620 ptr += gateway->sa_len;
621 left -= gateway->sa_len;
622 addrs |= RTA_GATEWAY0x2;
623 } else {
624 flags |= RTF_HOST0x4;
625 }
626
627 switch(imsg->hdr.type) {
628 case IMSG_VROUTE_ADD:
629 type = RTM_ADD0x1;
630 break;
631 case IMSG_VROUTE_DEL:
632 type = RTM_DELETE0x2;
633 break;
634 }
635
636 if (type == RTM_ADD0x1)
637 vroute_insertroute(env, rdomain, dest, mask);
638 else
639 vroute_removeroute(env, rdomain, dest, mask);
640 return (vroute_doroute(env, flags, addrs, rdomain, type,
641 dest, mask, gateway, NULL((void *)0)));
642}
643
644int
645vroute_getcloneroute(struct iked *env, struct imsg *imsg)
646{
647 struct sockaddr *dst;
648 struct sockaddr_storage dest;
649 struct sockaddr_storage mask;
650 struct sockaddr_storage addr;
651 uint8_t *ptr;
652 size_t left;
653 uint32_t rdomain;
654 int flags;
655 int addrs;
656 int need_gw;
657
658 ptr = (uint8_t *)imsg->data;
659 left = IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr));
660
661 if (left < sizeof(rdomain))
662 return (-1);
663 rdomain = *ptr;
664 ptr += sizeof(rdomain);
665 left -= sizeof(rdomain);
666
667 bzero(&dest, sizeof(dest));
668 bzero(&mask, sizeof(mask));
669 bzero(&addr, sizeof(addr));
670
671 if (left < sizeof(struct sockaddr))
672 return (-1);
673 dst = (struct sockaddr *)ptr;
674 if (left < dst->sa_len)
675 return (-1);
676 memcpy(&dest, dst, dst->sa_len);
677 ptr += dst->sa_len;
678 left -= dst->sa_len;
Value stored to 'left' is never read
679
680 /* Get route to peer */
681 flags = RTF_UP0x1 | RTF_HOST0x4 | RTF_STATIC0x800;
682 if (vroute_doroute(env, flags, RTA_DST0x1, rdomain, RTM_GET0x4,
683 (struct sockaddr *)&dest, (struct sockaddr *)&mask,
684 (struct sockaddr *)&addr, &need_gw))
685 return (-1);
686
687 if (need_gw)
688 flags |= RTF_GATEWAY0x2;
689
690 memcpy(&dest, dst, dst->sa_len);
691 socket_setport((struct sockaddr *)&dest, 0);
692 vroute_insertroute(env, rdomain, (struct sockaddr *)&dest, NULL((void *)0));
693
694 /* Set explicit route to peer with gateway addr*/
695 addrs = RTA_DST0x1 | RTA_GATEWAY0x2 | RTA_NETMASK0x4;
696 return (vroute_doroute(env, flags, addrs, rdomain, RTM_ADD0x1,
697 (struct sockaddr *)&dest, (struct sockaddr *)&mask,
698 (struct sockaddr *)&addr, NULL((void *)0)));
699}
700
701int
702vroute_dodns(struct iked *env, struct sockaddr *dns, int add,
703 unsigned int ifidx)
704{
705 struct vroute_msg m_rtmsg;
706 struct sockaddr_in *in;
707 struct sockaddr_in6 *in6;
708 struct sockaddr_rtdns rtdns;
709 struct iked_vroute_sc *ivr = env->sc_vroute;
710 struct iovec iov[3];
711 int i;
712 long pad = 0;
713 int iovcnt = 0, padlen;
714
715 bzero(&m_rtmsg, sizeof(m_rtmsg));
716#define rtm m_rtmsg.vm_rtm
717 rtm.rtm_version = RTM_VERSION5;
718 rtm.rtm_type = RTM_PROPOSAL0x13;
719 rtm.rtm_seq = ++ivr->ivr_rtseq;
720 rtm.rtm_priority = RTP_PROPOSAL_STATIC57;
721 rtm.rtm_flags = RTF_UP0x1;
722 rtm.rtm_addrs = RTA_DNS0x1000;
723 rtm.rtm_index = ifidx;
724
725 iov[iovcnt].iov_base = &rtm;
726 iov[iovcnt].iov_len = sizeof(rtm);
727 iovcnt++;
728
729 bzero(&rtdns, sizeof(rtdns));
730 rtdns.sr_family = dns->sa_family;
731 rtdns.sr_len = 2;
732 if (add) {
733 switch(dns->sa_family) {
734 case AF_INET2:
735 rtdns.sr_family = AF_INET2;
736 rtdns.sr_len += sizeof(struct in_addr);
737 in = (struct sockaddr_in *)dns;
738 memcpy(rtdns.sr_dns, &in->sin_addr, sizeof(struct in_addr));
739 break;
740 case AF_INET624:
741 rtdns.sr_family = AF_INET624;
742 rtdns.sr_len += sizeof(struct in6_addr);
743 in6 = (struct sockaddr_in6 *)dns;
744 memcpy(rtdns.sr_dns, &in6->sin6_addr, sizeof(struct in6_addr));
745 break;
746 default:
747 return (-1);
748 }
749 }
750 iov[iovcnt].iov_base = &rtdns;
751 iov[iovcnt++].iov_len = sizeof(rtdns);
752 padlen = ROUNDUP(sizeof(rtdns))(sizeof(rtdns)>0 ? (1 + (((sizeof(rtdns)) - 1) | (sizeof(long
) - 1))) : sizeof(long))
- sizeof(rtdns);
753 if (padlen > 0) {
754 iov[iovcnt].iov_base = &pad;
755 iov[iovcnt++].iov_len = padlen;
756 }
757
758 for (i = 0; i < iovcnt; i++)
759 rtm.rtm_msglen += iov[i].iov_len;
760#undef rtm
761
762 if (writev(ivr->ivr_rtsock, iov, iovcnt) == -1)
763 log_warn("failed to send route message");
764
765 return (0);
766}
767
768int
769vroute_doroute(struct iked *env, int flags, int addrs, int rdomain, uint8_t type,
770 struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *addr, int *need_gw)
771{
772 struct vroute_msg m_rtmsg;
773 struct iovec iov[7];
774 struct iked_vroute_sc *ivr = env->sc_vroute;
775 ssize_t len;
776 int iovcnt = 0;
777 int i;
778 long pad = 0;
779 size_t padlen;
780
781 bzero(&m_rtmsg, sizeof(m_rtmsg));
782#define rtm m_rtmsg.vm_rtm
783 rtm.rtm_version = RTM_VERSION5;
784 rtm.rtm_tableid = rdomain;
785 rtm.rtm_type = type;
786 rtm.rtm_seq = ++ivr->ivr_rtseq;
787 if (type != RTM_GET0x4)
788 rtm.rtm_priority = IKED_VROUTE_PRIO6;
789 rtm.rtm_flags = flags;
790 rtm.rtm_addrs = addrs;
791
792 iov[iovcnt].iov_base = &rtm;
793 iov[iovcnt].iov_len = sizeof(rtm);
794 iovcnt++;
795
796 if (rtm.rtm_addrs & RTA_DST0x1) {
797 iov[iovcnt].iov_base = dest;
798 iov[iovcnt].iov_len = dest->sa_len;
799 iovcnt++;
800 padlen = ROUNDUP(dest->sa_len)(dest->sa_len>0 ? (1 + (((dest->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
- dest->sa_len;
801 if (padlen > 0) {
802 iov[iovcnt].iov_base = &pad;
803 iov[iovcnt].iov_len = padlen;
804 iovcnt++;
805 }
806 }
807
808 if (rtm.rtm_addrs & RTA_GATEWAY0x2) {
809 iov[iovcnt].iov_base = addr;
810 iov[iovcnt].iov_len = addr->sa_len;
811 iovcnt++;
812 padlen = ROUNDUP(addr->sa_len)(addr->sa_len>0 ? (1 + (((addr->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
- addr->sa_len;
813 if (padlen > 0) {
814 iov[iovcnt].iov_base = &pad;
815 iov[iovcnt].iov_len = padlen;
816 iovcnt++;
817 }
818 }
819
820 if (rtm.rtm_addrs & RTA_NETMASK0x4) {
821 iov[iovcnt].iov_base = mask;
822 iov[iovcnt].iov_len = mask->sa_len;
823 iovcnt++;
824 padlen = ROUNDUP(mask->sa_len)(mask->sa_len>0 ? (1 + (((mask->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
- mask->sa_len;
825 if (padlen > 0) {
826 iov[iovcnt].iov_base = &pad;
827 iov[iovcnt].iov_len = padlen;
828 iovcnt++;
829 }
830 }
831
832 for (i = 0; i < iovcnt; i++)
833 rtm.rtm_msglen += iov[i].iov_len;
834
835 log_debug("%s: len: %u type: %s rdomain: %d flags %x (%s%s)"
836 " addrs %x (dst %s mask %s gw %s)", __func__, rtm.rtm_msglen,
837 type == RTM_ADD0x1 ? "RTM_ADD" : type == RTM_DELETE0x2 ? "RTM_DELETE" :
838 type == RTM_GET0x4 ? "RTM_GET" : "unknown", rdomain,
839 flags,
840 flags & RTF_HOST0x4 ? "H" : "",
841 flags & RTF_GATEWAY0x2 ? "G" : "",
842 addrs,
843 addrs & RTA_DST0x1 ? print_addr(dest) : "<>",
844 addrs & RTA_NETMASK0x4 ? print_addr(mask) : "<>",
845 addrs & RTA_GATEWAY0x2 ? print_addr(addr) : "<>");
846
847 if (writev(ivr->ivr_rtsock, iov, iovcnt) == -1) {
848 if ((type == RTM_ADD0x1 && errno(*__errno()) != EEXIST17) ||
849 (type == RTM_DELETE0x2 && errno(*__errno()) != ESRCH3)) {
850 log_warn("%s: write %d", __func__, rtm.rtm_errno);
851 return (0);
852 }
853 }
854
855 if (type == RTM_GET0x4) {
856 do {
857 len = read(ivr->ivr_rtsock, &m_rtmsg, sizeof(m_rtmsg));
858 } while(len > 0 && (rtm.rtm_version != RTM_VERSION5 ||
859 rtm.rtm_seq != ivr->ivr_rtseq || rtm.rtm_pid != ivr->ivr_pid));
860 return (vroute_process(env, len, &m_rtmsg, dest, mask, addr, need_gw));
861 }
862#undef rtm
863
864 return (0);
865}
866
867int
868vroute_process(struct iked *env, int msglen, struct vroute_msg *m_rtmsg,
869 struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *addr, int *need_gw)
870{
871 struct sockaddr *sa;
872 char *cp;
873 int i;
874
875#define rtm m_rtmsg->vm_rtm
876 if (rtm.rtm_version != RTM_VERSION5) {
877 warnx("routing message version %u not understood",
878 rtm.rtm_version);
879 return (-1);
880 }
881 if (rtm.rtm_msglen > msglen) {
882 warnx("message length mismatch, in packet %u, returned %d",
883 rtm.rtm_msglen, msglen);
884 return (-1);
885 }
886 if (rtm.rtm_errno) {
887 warnx("RTM_GET: %s (errno %d)",
888 strerror(rtm.rtm_errno), rtm.rtm_errno);
889 return (-1);
890 }
891 cp = m_rtmsg->vm_space;
892 *need_gw = rtm.rtm_flags & RTF_GATEWAY0x2;
893 if(rtm.rtm_addrs) {
894 for (i = 1; i; i <<= 1) {
895 if (i & rtm.rtm_addrs) {
896 sa = (struct sockaddr *)cp;
897 switch(i) {
898 case RTA_DST0x1:
899 memcpy(dest, cp, sa->sa_len);
900 break;
901 case RTA_NETMASK0x4:
902 memcpy(mask, cp, sa->sa_len);
903 break;
904 case RTA_GATEWAY0x2:
905 memcpy(addr, cp, sa->sa_len);
906 break;
907 }
908 cp += ROUNDUP(sa->sa_len)(sa->sa_len>0 ? (1 + (((sa->sa_len) - 1) | (sizeof(long
) - 1))) : sizeof(long))
;
909 }
910 }
911 }
912#undef rtm
913 return (0);
914}
915
916int
917vroute_doaddr(struct iked *env, char *ifname, struct sockaddr *addr,
918 struct sockaddr *mask, int add)
919{
920 struct iked_vroute_sc *ivr = env->sc_vroute;
921 struct ifaliasreq req;
922 struct in6_aliasreq req6;
923 unsigned long ioreq;
924 int af;
925
926 af = addr->sa_family;
927 switch (af) {
928 case AF_INET2:
929 bzero(&req, sizeof(req));
930 strncpy(req.ifra_name, ifname, sizeof(req.ifra_name));
931 memcpy(&req.ifra_addrifra_ifrau.ifrau_addr, addr, sizeof(req.ifra_addrifra_ifrau.ifrau_addr));
932 if (add)
933 memcpy(&req.ifra_mask, mask, sizeof(req.ifra_addrifra_ifrau.ifrau_addr));
934
935 log_debug("%s: %s inet %s netmask %s", __func__,
936 add ? "add" : "del", print_addr(addr), print_addr(mask));
937
938 ioreq = add ? SIOCAIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifaliasreq) &
0x1fff) << 16) | ((('i')) << 8) | ((26)))
: SIOCDIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((25)))
;
939 if (ioctl(ivr->ivr_iosock, ioreq, &req) == -1) {
940 log_warn("%s: req: %lu", __func__, ioreq);
941 return (-1);
942 }
943 break;
944 case AF_INET624:
945 bzero(&req6, sizeof(req6));
946 strncpy(req6.ifra_name, ifname, sizeof(req6.ifra_name));
947 req6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME0xffffffff;
948 req6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME0xffffffff;
949
950 memcpy(&req6.ifra_addrifra_ifrau.ifrau_addr, addr, sizeof(req6.ifra_addrifra_ifrau.ifrau_addr));
951 if (add)
952 memcpy(&req6.ifra_prefixmask, mask,
953 sizeof(req6.ifra_prefixmask));
954
955 log_debug("%s: %s inet6 %s netmask %s", __func__,
956 add ? "add" : "del", print_addr(addr), print_addr(mask));
957
958 ioreq = add ? SIOCAIFADDR_IN6((unsigned long)0x80000000 | ((sizeof(struct in6_aliasreq) &
0x1fff) << 16) | ((('i')) << 8) | ((26)))
: SIOCDIFADDR_IN6((unsigned long)0x80000000 | ((sizeof(struct in6_ifreq) &
0x1fff) << 16) | ((('i')) << 8) | ((25)))
;
959 if (ioctl(ivr->ivr_iosock6, ioreq, &req6) == -1) {
960 log_warn("%s: req: %lu", __func__, ioreq);
961 return (-1);
962 }
963 break;
964 default:
965 return (-1);
966 }
967
968 return (0);
969}