Bug Summary

File:src/sbin/resolvd/resolvd.c
Warning:line 647, column 11
Although the value stored to 'linelen' is used in the enclosing expression, the value is never actually read from 'linelen'

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 resolvd.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/resolvd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sbin/resolvd -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/resolvd/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/resolvd/resolvd.c
1/* $OpenBSD: resolvd.c,v 1.32 2022/12/09 18:22:35 tb Exp $ */
2/*
3 * Copyright (c) 2021 Florian Obser <florian@openbsd.org>
4 * Copyright (c) 2021 Theo de Raadt <deraadt@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/types.h>
20#include <sys/event.h>
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/syslog.h>
24#include <sys/time.h>
25#include <sys/un.h>
26#include <netdb.h>
27
28#include <arpa/inet.h>
29#include <netinet/in.h>
30#include <net/if.h>
31#include <net/route.h>
32
33#include <err.h>
34#include <errno(*__errno()).h>
35#include <fcntl.h>
36#include <event.h>
37#include <signal.h>
38#include <stddef.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
44#define ROUTE_SOCKET_BUF_SIZE16384 16384
45#define ASR_MAXNS10 10
46#define _PATH_LOCKFILE"/dev/resolvd.lock" "/dev/resolvd.lock"
47#define _PATH_UNWIND_SOCKET"/dev/unwind.sock" "/dev/unwind.sock"
48#define _PATH_RESCONF"/etc/resolv.conf" "/etc/resolv.conf"
49#define _PATH_RESCONF_NEW"/etc/resolv.conf.new" "/etc/resolv.conf.new"
50
51#ifndef nitems
52#define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0]))
53#endif
54
55__dead__attribute__((__noreturn__)) void usage(void);
56
57struct rdns_proposal {
58 uint32_t if_index;
59 int af;
60 int prio;
61 char ip[INET6_ADDRSTRLEN46];
62};
63
64void route_receive(int);
65void handle_route_message(struct rt_msghdr *, struct sockaddr **);
66void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
67void solicit_dns_proposals(int);
68void regen_resolvconf(const char *reason);
69int cmp(const void *, const void *);
70int findslot(struct rdns_proposal *);
71void zeroslot(struct rdns_proposal *);
72
73struct rdns_proposal learned[ASR_MAXNS10];
74int resolvfd = -1;
75int newkevent = 1;
76
77#ifndef SMALL
78int open_unwind_ctl(void);
79int check_unwind = 1, unwind_running = 0;
80
81struct loggers {
82 __dead__attribute__((__noreturn__)) void (*err)(int, const char *, ...)
83 __attribute__((__format__ (printf, 2, 3)));
84 __dead__attribute__((__noreturn__)) void (*errx)(int, const char *, ...)
85 __attribute__((__format__ (printf, 2, 3)));
86 void (*warn)(const char *, ...)
87 __attribute__((__format__ (printf, 1, 2)));
88 void (*warnx)(const char *, ...)
89 __attribute__((__format__ (printf, 1, 2)));
90 void (*info)(const char *, ...)
91 __attribute__((__format__ (printf, 1, 2)));
92 void (*debug)(const char *, ...)
93 __attribute__((__format__ (printf, 1, 2)));
94};
95
96void warnx_verbose(const char *, ...)
97 __attribute__((__format__ (printf, 1, 2)));
98
99const struct loggers conslogger = {
100 err,
101 errx,
102 warn,
103 warnx,
104 warnx_verbose, /* info */
105 warnx_verbose /* debug */
106};
107
108__dead__attribute__((__noreturn__)) void syslog_err(int, const char *, ...)
109 __attribute__((__format__ (printf, 2, 3)));
110__dead__attribute__((__noreturn__)) void syslog_errx(int, const char *, ...)
111 __attribute__((__format__ (printf, 2, 3)));
112void syslog_warn(const char *, ...)
113 __attribute__((__format__ (printf, 1, 2)));
114void syslog_warnx(const char *, ...)
115 __attribute__((__format__ (printf, 1, 2)));
116void syslog_info(const char *, ...)
117 __attribute__((__format__ (printf, 1, 2)));
118void syslog_debug(const char *, ...)
119 __attribute__((__format__ (printf, 1, 2)));
120void syslog_vstrerror(int, int, const char *, va_list)
121 __attribute__((__format__ (printf, 3, 0)));
122
123int verbose = 0;
124
125const struct loggers syslogger = {
126 syslog_err,
127 syslog_errx,
128 syslog_warn,
129 syslog_warnx,
130 syslog_info,
131 syslog_debug
132};
133
134const struct loggers *logger = &conslogger;
135
136#define lerr(_e, _f...)logger->err((_e), _f...) logger->err((_e), _f)
137#define lerrx(_e, _f...)logger->errx((_e), _f...) logger->errx((_e), _f)
138#define lwarn(_f...)logger->warn(_f...) logger->warn(_f)
139#define lwarnx(_f...)logger->warnx(_f...) logger->warnx(_f)
140#define linfo(_f...)logger->info(_f...) logger->info(_f)
141#define ldebug(_f...)logger->debug(_f...) logger->debug(_f)
142#else
143#define lerr(x...)logger->err((x...), ) do {} while(0)
144#define lerrx(x...)logger->errx((x...), ) do {} while(0)
145#define lwarn(x...)logger->warn(x...) do {} while(0)
146#define lwarnx(x...)logger->warnx(x...) do {} while(0)
147#define linfo(x...)logger->info(x...) do {} while(0)
148#define ldebug(x...)logger->debug(x...) do {} while(0)
149#endif /* SMALL */
150
151enum {
152 KQ_ROUTE,
153 KQ_RESOLVE_CONF,
154#ifndef SMALL
155 KQ_UNWIND,
156#endif
157 KQ_TOTAL
158};
159
160int
161main(int argc, char *argv[])
162{
163 struct timespec one = {1, 0};
164 int kq, ch, debug = 0, routesock;
165 int rtfilter, nready, lockfd;
166 struct kevent kev[KQ_TOTAL];
167#ifndef SMALL
168 int unwindsock = -1;
169#endif
170
171 while ((ch = getopt(argc, argv, "dv")) != -1) {
172 switch (ch) {
173 case 'd':
174 debug = 1;
175 break;
176 case 'v':
177#ifndef SMALL
178 verbose++;
179#endif
180 break;
181 default:
182 usage();
183 }
184 }
185
186 argc -= optind;
187 argv += optind;
188 if (argc > 0)
189 usage();
190
191 /* Check for root privileges. */
192 if (geteuid())
193 errx(1, "need root privileges");
194
195 lockfd = open(_PATH_LOCKFILE"/dev/resolvd.lock", O_CREAT0x0200|O_RDWR0x0002|O_EXLOCK0x0020|O_NONBLOCK0x0004, 0600);
196 if (lockfd == -1) {
197 if (errno(*__errno()) == EAGAIN35)
198 errx(1, "already running");
199 err(1, "%s", _PATH_LOCKFILE"/dev/resolvd.lock");
200 }
201
202 if (!debug)
203 daemon(0, 0);
204
205#ifndef SMALL
206 if (!debug) {
207 openlog("resolvd", LOG_PID0x01|LOG_NDELAY0x08, LOG_DAEMON(3<<3));
208 logger = &syslogger;
209 }
210#endif
211
212 signal(SIGHUP1, SIG_IGN(void (*)(int))1);
213
214 if ((routesock = socket(AF_ROUTE17, SOCK_RAW3, 0)) == -1)
215 lerr(1, "route socket")logger->err((1), "route socket");
216
217 rtfilter = ROUTE_FILTER(RTM_PROPOSAL)(1 << (0x13)) | ROUTE_FILTER(RTM_IFANNOUNCE)(1 << (0xf));
218 if (setsockopt(routesock, AF_ROUTE17, ROUTE_MSGFILTER1, &rtfilter,
219 sizeof(rtfilter)) == -1)
220 lerr(1, "setsockopt(ROUTE_MSGFILTER)")logger->err((1), "setsockopt(ROUTE_MSGFILTER)");
221
222 solicit_dns_proposals(routesock);
223
224 if (unveil(_PATH_RESCONF"/etc/resolv.conf", "rwc") == -1)
225 lerr(1, "unveil " _PATH_RESCONF)logger->err((1), "unveil " "/etc/resolv.conf");
226 if (unveil(_PATH_RESCONF_NEW"/etc/resolv.conf.new", "rwc") == -1)
227 lerr(1, "unveil " _PATH_RESCONF_NEW)logger->err((1), "unveil " "/etc/resolv.conf.new");
228#ifndef SMALL
229 if (unveil(_PATH_UNWIND_SOCKET"/dev/unwind.sock", "w") == -1)
230 lerr(1, "unveil " _PATH_UNWIND_SOCKET)logger->err((1), "unveil " "/dev/unwind.sock");
231#endif
232
233 if (pledge("stdio unix rpath wpath cpath", NULL((void *)0)) == -1)
234 lerr(1, "pledge")logger->err((1), "pledge");
235
236 if ((kq = kqueue()) == -1)
237 lerr(1, "kqueue")logger->err((1), "kqueue");
238
239 for(;;) {
240 int i;
241
242#ifndef SMALL
243 if (!unwind_running && check_unwind) {
244 check_unwind = 0;
245 unwindsock = open_unwind_ctl();
246 unwind_running = unwindsock != -1;
247 if (unwind_running)
248 regen_resolvconf("new unwind");
249 }
250#endif
251
252 if (newkevent) {
253 int kevi = 0;
254
255 if (routesock != -1)
256 EV_SET(&kev[kevi++], routesock, EVFILT_READ,do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (routesock); (__kevp)->filter = ((-1)); (__kevp)->
flags = (0x0001); (__kevp)->fflags = (0); (__kevp)->data
= (0); (__kevp)->udata = ((void *)KQ_ROUTE); } while(0)
257 EV_ADD, 0, 0,do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (routesock); (__kevp)->filter = ((-1)); (__kevp)->
flags = (0x0001); (__kevp)->fflags = (0); (__kevp)->data
= (0); (__kevp)->udata = ((void *)KQ_ROUTE); } while(0)
258 (void *)KQ_ROUTE)do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (routesock); (__kevp)->filter = ((-1)); (__kevp)->
flags = (0x0001); (__kevp)->fflags = (0); (__kevp)->data
= (0); (__kevp)->udata = ((void *)KQ_ROUTE); } while(0)
;
259 if (resolvfd != -1)
260 EV_SET(&kev[kevi++], resolvfd, EVFILT_VNODE,do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (resolvfd); (__kevp)->filter = ((-4)); (__kevp)->
flags = (0x0001 | 0x0020); (__kevp)->fflags = (0x0001 | 0x0020
| 0x0080 | 0x0002); (__kevp)->data = (0); (__kevp)->udata
= ((void *)KQ_RESOLVE_CONF); } while(0)
261 EV_ADD | EV_CLEAR,do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (resolvfd); (__kevp)->filter = ((-4)); (__kevp)->
flags = (0x0001 | 0x0020); (__kevp)->fflags = (0x0001 | 0x0020
| 0x0080 | 0x0002); (__kevp)->data = (0); (__kevp)->udata
= ((void *)KQ_RESOLVE_CONF); } while(0)
262 NOTE_DELETE | NOTE_RENAME | NOTE_TRUNCATE | NOTE_WRITE, 0,do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (resolvfd); (__kevp)->filter = ((-4)); (__kevp)->
flags = (0x0001 | 0x0020); (__kevp)->fflags = (0x0001 | 0x0020
| 0x0080 | 0x0002); (__kevp)->data = (0); (__kevp)->udata
= ((void *)KQ_RESOLVE_CONF); } while(0)
263 (void *)KQ_RESOLVE_CONF)do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (resolvfd); (__kevp)->filter = ((-4)); (__kevp)->
flags = (0x0001 | 0x0020); (__kevp)->fflags = (0x0001 | 0x0020
| 0x0080 | 0x0002); (__kevp)->data = (0); (__kevp)->udata
= ((void *)KQ_RESOLVE_CONF); } while(0)
;
264
265#ifndef SMALL
266 if (unwind_running) {
267 EV_SET(&kev[kevi++], unwindsock, EVFILT_READ,do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (unwindsock); (__kevp)->filter = ((-1)); (__kevp)->
flags = (0x0001); (__kevp)->fflags = (0); (__kevp)->data
= (0); (__kevp)->udata = ((void *)KQ_UNWIND); } while(0)
268 EV_ADD, 0, 0,do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (unwindsock); (__kevp)->filter = ((-1)); (__kevp)->
flags = (0x0001); (__kevp)->fflags = (0); (__kevp)->data
= (0); (__kevp)->udata = ((void *)KQ_UNWIND); } while(0)
269 (void *)KQ_UNWIND)do { struct kevent *__kevp = (&kev[kevi++]); (__kevp)->
ident = (unwindsock); (__kevp)->filter = ((-1)); (__kevp)->
flags = (0x0001); (__kevp)->fflags = (0); (__kevp)->data
= (0); (__kevp)->udata = ((void *)KQ_UNWIND); } while(0)
;
270 }
271#endif /* SMALL */
272
273 if (kevent(kq, kev, kevi, NULL((void *)0), 0, NULL((void *)0)) == -1)
274 lerr(1, "kevent")logger->err((1), "kevent");
275 newkevent = 0;
276 }
277
278 nready = kevent(kq, NULL((void *)0), 0, kev, KQ_TOTAL, NULL((void *)0));
279 if (nready == -1) {
280 if (errno(*__errno()) == EINTR4)
281 continue;
282 lerr(1, "kevent")logger->err((1), "kevent");
283 }
284
285 if (nready == 0)
286 continue;
287
288 for (i = 0; i < nready; i++) {
289 unsigned short fflags = kev[i].fflags;
290
291 switch ((int)(long)kev[i].udata) {
292 case KQ_ROUTE:
293 route_receive(routesock);
294 break;
295
296 case KQ_RESOLVE_CONF:
297 if (fflags & (NOTE_DELETE0x0001 | NOTE_RENAME0x0020)) {
298 close(resolvfd);
299 resolvfd = -1;
300 regen_resolvconf("file delete/rename");
301 }
302 if (fflags & (NOTE_TRUNCATE0x0080 | NOTE_WRITE0x0002)) {
303 /* some editors truncate and write */
304 if (fflags & NOTE_TRUNCATE0x0080)
305 nanosleep(&one, NULL((void *)0));
306 regen_resolvconf("file trunc/write");
307 }
308 break;
309
310#ifndef SMALL
311 case KQ_UNWIND: {
312 uint8_t buf[1024];
313 ssize_t n;
314
315 n = read(unwindsock, buf, sizeof(buf));
316 if (n == -1) {
317 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
318 continue;
319 }
320 if (n == 0 || n == -1) {
321 if (n == -1)
322 check_unwind = 1;
323 newkevent = 1;
324 close(unwindsock);
325 unwindsock = -1;
326 unwind_running = 0;
327 regen_resolvconf("unwind closed");
328 } else
329 lwarnx("read %ld from unwind ctl", n)logger->warnx("read %ld from unwind ctl", n);
330 break;
331 }
332#endif
333
334 default:
335 lwarnx("unknown kqueue event on %lu",logger->warnx("unknown kqueue event on %lu", kev[i].ident)
336 kev[i].ident)logger->warnx("unknown kqueue event on %lu", kev[i].ident);
337 }
338 }
339 }
340 return 0;
341}
342
343__dead__attribute__((__noreturn__)) void
344usage(void)
345{
346 fprintf(stderr(&__sF[2]), "usage: resolvd [-dv]\n");
347 exit(1);
348}
349
350void
351route_receive(int fd)
352{
353 uint8_t rsock_buf[ROUTE_SOCKET_BUF_SIZE16384];
354 struct sockaddr *sa, *rti_info[RTAX_MAX15];
355 struct rt_msghdr *rtm;
356 ssize_t n;
357
358 rtm = (struct rt_msghdr *) rsock_buf;
359 if ((n = read(fd, rsock_buf, sizeof(rsock_buf))) == -1) {
360 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
361 return;
362 lwarn("%s: read error", __func__)logger->warn("%s: read error", __func__);
363 return;
364 }
365
366 if (n == 0)
367 lerr(1, "routing socket closed")logger->err((1), "routing socket closed");
368
369 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
370 lwarnx("partial rtm of %zd in buffer", n)logger->warnx("partial rtm of %zd in buffer", n);
371 return;
372 }
373
374 if (rtm->rtm_version != RTM_VERSION5)
375 return;
376
377 if (rtm->rtm_pid == getpid())
378 return;
379
380 sa = (struct sockaddr *)(rsock_buf + rtm->rtm_hdrlen);
381 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
382 handle_route_message(rtm, rti_info);
383}
384
385void
386zeroslot(struct rdns_proposal *tab)
387{
388 tab->prio = 0;
389 tab->af = 0;
390 tab->if_index = 0;
391 tab->ip[0] = '\0';
392}
393
394int
395findslot(struct rdns_proposal *tab)
396{
397 int i;
398
399 for (i = 0; i < ASR_MAXNS10; i++)
400 if (tab[i].prio == 0)
401 return i;
402
403 /* New proposals might be important, so replace the last slot */
404 i = ASR_MAXNS10 - 1;
405 zeroslot(&tab[i]);
406 return i;
407}
408
409void
410handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
411{
412 struct rdns_proposal learning[nitems(learned)(sizeof((learned)) / sizeof((learned)[0]))];
413 struct sockaddr_rtdns *rtdns;
414 struct if_announcemsghdr *ifan;
415 size_t addrsz;
416 int rdns_count, af, i;
417 char *src;
418
419 memcpy(learning, learned, sizeof learned);
420
421 switch (rtm->rtm_type) {
422 case RTM_IFANNOUNCE0xf:
423 ifan = (struct if_announcemsghdr *)rtm;
424 if (ifan->ifan_what == IFAN_ARRIVAL0)
425 return;
426 /* Delete proposals learned from departing interfaces */
427 for (i = 0; i < ASR_MAXNS10; i++)
428 if (learning[i].if_index == ifan->ifan_index)
429 zeroslot(&learning[i]);
430 break;
431 case RTM_PROPOSAL0x13:
432 if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT62) {
433#ifndef SMALL
434 check_unwind = 1;
435#endif /* SMALL */
436 return;
437 }
438
439 if (!(rtm->rtm_addrs & RTA_DNS0x1000))
440 return;
441
442 rtdns = (struct sockaddr_rtdns*)rti_info[RTAX_DNS12];
443 src = rtdns->sr_dns;
444 af = rtdns->sr_family;
445
446 switch (af) {
447 case AF_INET2:
448 addrsz = sizeof(struct in_addr);
449 break;
450 case AF_INET624:
451 addrsz = sizeof(struct in6_addr);
452 break;
453 default:
454 lwarnx("ignoring invalid RTM_PROPOSAL")logger->warnx("ignoring invalid RTM_PROPOSAL");
455 return;
456 }
457
458 if ((rtdns->sr_len - 2) % addrsz != 0) {
459 lwarnx("ignoring invalid RTM_PROPOSAL")logger->warnx("ignoring invalid RTM_PROPOSAL");
460 return;
461 }
462 rdns_count = (rtdns->sr_len -
463 offsetof(struct sockaddr_rtdns, sr_dns)__builtin_offsetof(struct sockaddr_rtdns, sr_dns)) / addrsz;
464
465 /* New proposal from interface means previous proposals expire */
466 for (i = 0; i < ASR_MAXNS10; i++)
467 if (learning[i].af == af &&
468 learning[i].if_index == rtm->rtm_index)
469 zeroslot(&learning[i]);
470
471 /* Add the new proposals */
472 for (i = 0; i < rdns_count; i++) {
473 struct sockaddr_storage ss;
474 struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
475 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
476 int new, err;
477
478 memset(&ss, 0, sizeof(ss));
479 ss.ss_family = af;
480 new = findslot(learning);
481 switch (af) {
482 case AF_INET2:
483 memcpy(&sin->sin_addr, src, addrsz);
484 ss.ss_len = sizeof(*sin);
485 break;
486 case AF_INET624:
487 memcpy(&sin6->sin6_addr, src, addrsz);
488 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)(((&sin6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xfe
) && (((&sin6->sin6_addr)->__u6_addr.__u6_addr8
[1] & 0xc0) == 0x80))
)
489 sin6->sin6_scope_id = rtm->rtm_index;
490 ss.ss_len = sizeof(*sin6);
491 break;
492 }
493 src += addrsz;
494
495 if ((err = getnameinfo((struct sockaddr *)&ss, ss.ss_len,
496 learning[new].ip, sizeof(learning[new].ip),
497 NULL((void *)0), 0, NI_NUMERICHOST1)) == 0) {
498 learning[new].prio = rtm->rtm_priority;
499 learning[new].if_index = rtm->rtm_index;
500 learning[new].af = af;
501 } else
502 lwarnx("getnameinfo: %s", gai_strerror(err))logger->warnx("getnameinfo: %s", gai_strerror(err));
503 }
504 break;
505 default:
506 return;
507 }
508
509 /* Sort proposals, based upon priority */
510 if (mergesort(learning, ASR_MAXNS10, sizeof(learning[0]), cmp) == -1) {
511 lwarn("mergesort")logger->warn("mergesort");
512 return;
513 }
514
515 /* Eliminate duplicate IPs per interface */
516 for (i = 0; i < ASR_MAXNS10 - 1; i++) {
517 int j;
518
519 if (learning[i].prio == 0)
520 continue;
521
522 for (j = i + 1; j < ASR_MAXNS10; j++) {
523 if (learning[i].if_index == learning[j].if_index &&
524 strcmp(learning[i].ip, learning[j].ip) == 0) {
525 zeroslot(&learning[j]);
526 }
527 }
528 }
529
530 /* If proposal result is different, rebuild the file */
531 if (memcmp(learned, learning, sizeof(learned)) != 0) {
532 memcpy(learned, learning, sizeof(learned));
533 regen_resolvconf("route proposals");
534 }
535}
536
537#define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof
(long))
\
538 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
539
540void
541get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
542{
543 int i;
544
545 for (i = 0; i < RTAX_MAX15; i++) {
546 if (addrs & (1 << i)) {
547 rti_info[i] = sa;
548 sa = (struct sockaddr *)((char *)(sa) +
549 ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
);
550 } else
551 rti_info[i] = NULL((void *)0);
552 }
553}
554
555void
556solicit_dns_proposals(int routesock)
557{
558 struct rt_msghdr rtm;
559 struct iovec iov[1];
560 int iovcnt = 0;
561
562 memset(&rtm, 0, sizeof(rtm));
563
564 rtm.rtm_version = RTM_VERSION5;
565 rtm.rtm_type = RTM_PROPOSAL0x13;
566 rtm.rtm_msglen = sizeof(rtm);
567 rtm.rtm_tableid = 0;
568 rtm.rtm_index = 0;
569 rtm.rtm_seq = arc4random();
570 rtm.rtm_priority = RTP_PROPOSAL_SOLICIT62;
571
572 iov[iovcnt].iov_base = &rtm;
573 iov[iovcnt++].iov_len = sizeof(rtm);
574
575 if (writev(routesock, iov, iovcnt) == -1)
576 lwarn("failed to send solicitation")logger->warn("failed to send solicitation");
577}
578
579void
580regen_resolvconf(const char *why)
581{
582 struct iovec iov[UIO_MAXIOV1024];
583 int i, fd, len, iovcnt = 0;
584
585 linfo("rebuilding: %s", why)logger->info("rebuilding: %s", why);
586
587 if ((fd = open(_PATH_RESCONF_NEW"/etc/resolv.conf.new", O_CREAT0x0200|O_TRUNC0x0400|O_RDWR0x0002, 0644)) == -1) {
588 lwarn(_PATH_RESCONF_NEW)logger->warn("/etc/resolv.conf.new");
589 return;
590 }
591
592 memset(iov, 0, sizeof(iov));
593
594#ifndef SMALL
595 if (unwind_running) {
596 len = asprintf((char **)&iov[iovcnt].iov_base,
597 "nameserver 127.0.0.1 # resolvd: unwind\n");
598 if (len < 0) {
599 lwarn("asprintf")logger->warn("asprintf");
600 goto err;
601 }
602 iov[iovcnt++].iov_len = len;
603 }
604
605#endif /* SMALL */
606 for (i = 0; i < ASR_MAXNS10; i++) {
607 if (learned[i].prio != 0) {
608 char ifnambuf[IF_NAMESIZE16], *ifnam;
609
610 ifnam = if_indextoname(learned[i].if_index,
611 ifnambuf);
612 len = asprintf((char **)&iov[iovcnt].iov_base,
613 "%snameserver %s # resolvd: %s\n",
614#ifndef SMALL
615 unwind_running ? "#" : "",
616#else
617 "",
618#endif
619 learned[i].ip,
620 ifnam ? ifnam : "");
621 if (len < 0) {
622 lwarn("asprintf")logger->warn("asprintf");
623 goto err;
624 }
625 iov[iovcnt++].iov_len = len;
626 }
627 }
628
629 /* Replay user-managed lines from old resolv.conf file */
630 if (resolvfd == -1)
631 resolvfd = open(_PATH_RESCONF"/etc/resolv.conf", O_RDWR0x0002);
632 if (resolvfd != -1) {
633 char *line = NULL((void *)0);
634 size_t linesize = 0;
635 ssize_t linelen;
636 FILE *fp;
637 int fd2;
638
639 if ((fd2 = dup(resolvfd)) == -1)
640 goto err;
641 lseek(fd2, 0, SEEK_SET0);
642 fp = fdopen(fd2, "r");
643 if (fp == NULL((void *)0)) {
644 close(fd2);
645 goto err;
646 }
647 while ((linelen = getline(&line, &linesize, fp)) != -1) {
Although the value stored to 'linelen' is used in the enclosing expression, the value is never actually read from 'linelen'
648 char *end = strchr(line, '\n');
649 if (end)
650 *end = '\0';
651 if (strstr(line, "# resolvd: "))
652 continue;
653 len = asprintf((char **)&iov[iovcnt].iov_base, "%s\n",
654 line);
655 if (len < 0) {
656 lwarn("asprintf")logger->warn("asprintf");
657 free(line);
658 fclose(fp);
659 goto err;
660 }
661 iov[iovcnt++].iov_len = len;
662 if (iovcnt >= UIO_MAXIOV1024) {
663 lwarnx("too many user-managed lines")logger->warnx("too many user-managed lines");
664 free(line);
665 fclose(fp);
666 goto err;
667 }
668 }
669 free(line);
670 fclose(fp);
671 }
672
673 if (iovcnt > 0) {
674 if (writev(fd, iov, iovcnt) == -1) {
675 lwarn("writev")logger->warn("writev");
676 goto err;
677 }
678 }
679
680 if (fsync(fd) == -1) {
681 lwarn("fsync")logger->warn("fsync");
682 goto err;
683 }
684 if (rename(_PATH_RESCONF_NEW"/etc/resolv.conf.new", _PATH_RESCONF"/etc/resolv.conf") == -1)
685 goto err;
686
687 if (resolvfd == -1) {
688 close(fd);
689 resolvfd = open(_PATH_RESCONF"/etc/resolv.conf", O_RDWR0x0002);
690 } else {
691 dup2(fd, resolvfd);
692 close(fd);
693 }
694
695 newkevent = 1;
696 goto out;
697
698 err:
699 if (fd != -1)
700 close(fd);
701 unlink(_PATH_RESCONF_NEW"/etc/resolv.conf.new");
702 out:
703 for (i = 0; i < iovcnt; i++)
704 free(iov[i].iov_base);
705
706}
707
708int
709cmp(const void *a, const void *b)
710{
711 const struct rdns_proposal *rpa = a, *rpb = b;
712
713 return (rpa->prio < rpb->prio) ? -1 : (rpa->prio > rpb->prio);
714}
715
716#ifndef SMALL
717int
718open_unwind_ctl(void)
719{
720 static struct sockaddr_un sun;
721 int s;
722
723 if (sun.sun_family == 0) {
724 sun.sun_family = AF_UNIX1;
725 strlcpy(sun.sun_path, _PATH_UNWIND_SOCKET"/dev/unwind.sock", sizeof(sun.sun_path));
726 }
727
728 if ((s = socket(AF_UNIX1, SOCK_STREAM1, 0)) != -1) {
729 if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
730 close(s);
731 s = -1;
732 }
733 }
734 newkevent = 1;
735 return s;
736}
737
738void
739syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
740{
741 char *s;
742
743 if (vasprintf(&s, fmt, ap) == -1) {
744 syslog(LOG_EMERG0, "unable to alloc in syslog_vstrerror");
745 exit(1);
746 }
747 syslog(priority, "%s: %s", s, strerror(e));
748 free(s);
749}
750
751__dead__attribute__((__noreturn__)) void
752syslog_err(int ecode, const char *fmt, ...)
753{
754 va_list ap;
755
756 va_start(ap, fmt)__builtin_va_start((ap), fmt);
757 syslog_vstrerror(errno(*__errno()), LOG_CRIT2, fmt, ap);
758 va_end(ap)__builtin_va_end((ap));
759 exit(ecode);
760}
761
762__dead__attribute__((__noreturn__)) void
763syslog_errx(int ecode, const char *fmt, ...)
764{
765 va_list ap;
766
767 va_start(ap, fmt)__builtin_va_start((ap), fmt);
768 vsyslog(LOG_CRIT2, fmt, ap);
769 va_end(ap)__builtin_va_end((ap));
770 exit(ecode);
771}
772
773void
774syslog_warn(const char *fmt, ...)
775{
776 va_list ap;
777
778 va_start(ap, fmt)__builtin_va_start((ap), fmt);
779 syslog_vstrerror(errno(*__errno()), LOG_ERR3, fmt, ap);
780 va_end(ap)__builtin_va_end((ap));
781}
782
783void
784syslog_warnx(const char *fmt, ...)
785{
786 va_list ap;
787
788 va_start(ap, fmt)__builtin_va_start((ap), fmt);
789 vsyslog(LOG_ERR3, fmt, ap);
790 va_end(ap)__builtin_va_end((ap));
791}
792
793void
794syslog_info(const char *fmt, ...)
795{
796 va_list ap;
797
798 va_start(ap, fmt)__builtin_va_start((ap), fmt);
799 vsyslog(LOG_INFO6, fmt, ap);
800 va_end(ap)__builtin_va_end((ap));
801}
802
803void
804syslog_debug(const char *fmt, ...)
805{
806 va_list ap;
807
808 va_start(ap, fmt)__builtin_va_start((ap), fmt);
809 vsyslog(LOG_DEBUG7, fmt, ap);
810 va_end(ap)__builtin_va_end((ap));
811}
812
813void
814warnx_verbose(const char *fmt, ...)
815{
816 va_list ap;
817
818 va_start(ap, fmt)__builtin_va_start((ap), fmt);
819 if (verbose)
820 vwarnx(fmt, ap);
821 va_end(ap)__builtin_va_end((ap));
822}
823
824#endif /* SMALL */