Bug Summary

File:src/sbin/resolvd/resolvd.c
Warning:line 616, 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.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name resolvd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -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/lib/clang/13.0.0 -I /usr/src/sbin/resolvd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/resolvd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/resolvd/resolvd.c
1/* $OpenBSD: resolvd.c,v 1.25 2021/11/16 16:24:22 kn 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(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 errx(1, "already running");
198
199 if (!debug)
200 daemon(0, 0);
201
202#ifndef SMALL
203 if (!debug) {
204 openlog("resolvd", LOG_PID0x01|LOG_NDELAY0x08, LOG_DAEMON(3<<3));
205 logger = &syslogger;
206 }
207#endif
208
209 signal(SIGHUP1, SIG_IGN(void (*)(int))1);
210
211 if ((routesock = socket(AF_ROUTE17, SOCK_RAW3, 0)) == -1)
212 lerr(1, "route socket")logger->err((1), "route socket");
213
214 rtfilter = ROUTE_FILTER(RTM_PROPOSAL)(1 << (0x13)) | ROUTE_FILTER(RTM_IFANNOUNCE)(1 << (0xf));
215 if (setsockopt(routesock, AF_ROUTE17, ROUTE_MSGFILTER1, &rtfilter,
216 sizeof(rtfilter)) == -1)
217 lerr(1, "setsockopt(ROUTE_MSGFILTER)")logger->err((1), "setsockopt(ROUTE_MSGFILTER)");
218
219 solicit_dns_proposals(routesock);
220
221 if (unveil(_PATH_RESCONF"/etc/resolv.conf", "rwc") == -1)
222 lerr(1, "unveil " _PATH_RESCONF)logger->err((1), "unveil " "/etc/resolv.conf");
223 if (unveil(_PATH_RESCONF_NEW"/etc/resolv.conf.new", "rwc") == -1)
224 lerr(1, "unveil " _PATH_RESCONF_NEW)logger->err((1), "unveil " "/etc/resolv.conf.new");
225#ifndef SMALL
226 if (unveil(_PATH_UNWIND_SOCKET"/dev/unwind.sock", "r") == -1)
227 lerr(1, "unveil " _PATH_UNWIND_SOCKET)logger->err((1), "unveil " "/dev/unwind.sock");
228#endif
229
230 if (pledge("stdio unix rpath wpath cpath", NULL((void*)0)) == -1)
231 lerr(1, "pledge")logger->err((1), "pledge");
232
233 if ((kq = kqueue()) == -1)
234 lerr(1, "kqueue")logger->err((1), "kqueue");
235
236 for(;;) {
237 int i;
238
239#ifndef SMALL
240 if (!unwind_running && check_unwind) {
241 check_unwind = 0;
242 unwindsock = open_unwind_ctl();
243 unwind_running = unwindsock != -1;
244 if (unwind_running)
245 regen_resolvconf("new unwind");
246 }
247#endif
248
249 if (newkevent) {
250 int kevi = 0;
251
252 if (routesock != -1)
253 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)
254 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)
255 (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)
;
256 if (resolvfd != -1)
257 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)
258 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)
259 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)
260 (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)
;
261
262#ifndef SMALL
263 if (unwind_running) {
264 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)
265 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)
266 (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)
;
267 }
268#endif /* SMALL */
269
270 if (kevent(kq, kev, kevi, NULL((void*)0), 0, NULL((void*)0)) == -1)
271 lerr(1, "kevent")logger->err((1), "kevent");
272 newkevent = 0;
273 }
274
275 nready = kevent(kq, NULL((void*)0), 0, kev, KQ_TOTAL, NULL((void*)0));
276 if (nready == -1) {
277 if (errno(*__errno()) == EINTR4)
278 continue;
279 lerr(1, "kevent")logger->err((1), "kevent");
280 }
281
282 if (nready == 0)
283 continue;
284
285 for (i = 0; i < nready; i++) {
286 unsigned short fflags = kev[i].fflags;
287
288 switch ((int)(long)kev[i].udata) {
289 case KQ_ROUTE:
290 route_receive(routesock);
291 break;
292
293 case KQ_RESOLVE_CONF:
294 if (fflags & (NOTE_DELETE0x0001 | NOTE_RENAME0x0020)) {
295 close(resolvfd);
296 resolvfd = -1;
297 regen_resolvconf("file delete/rename");
298 }
299 if (fflags & (NOTE_TRUNCATE0x0080 | NOTE_WRITE0x0002)) {
300 /* some editors truncate and write */
301 if (fflags & NOTE_TRUNCATE0x0080)
302 nanosleep(&one, NULL((void*)0));
303 regen_resolvconf("file trunc/write");
304 }
305 break;
306
307#ifndef SMALL
308 case KQ_UNWIND: {
309 uint8_t buf[1024];
310 ssize_t n;
311
312 n = read(unwindsock, buf, sizeof(buf));
313 if (n == -1) {
314 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
315 continue;
316 }
317 if (n == 0 || n == -1) {
318 if (n == -1)
319 check_unwind = 1;
320 newkevent = 1;
321 close(unwindsock);
322 unwindsock = -1;
323 unwind_running = 0;
324 regen_resolvconf("unwind closed");
325 } else
326 lwarnx("read %ld from unwind ctl", n)logger->warnx("read %ld from unwind ctl", n);
327 break;
328 }
329#endif
330
331 default:
332 lwarnx("unknown kqueue event on %lu",logger->warnx("unknown kqueue event on %lu", kev[i].ident)
333 kev[i].ident)logger->warnx("unknown kqueue event on %lu", kev[i].ident);
334 }
335 }
336 }
337 return 0;
338}
339
340__dead__attribute__((__noreturn__)) void
341usage(void)
342{
343 fprintf(stderr(&__sF[2]), "usage: resolvd [-dv]\n");
344 exit(1);
345}
346
347void
348route_receive(int fd)
349{
350 uint8_t rsock_buf[ROUTE_SOCKET_BUF_SIZE16384];
351 struct sockaddr *sa, *rti_info[RTAX_MAX15];
352 struct rt_msghdr *rtm;
353 ssize_t n;
354
355 rtm = (struct rt_msghdr *) rsock_buf;
356 if ((n = read(fd, rsock_buf, sizeof(rsock_buf))) == -1) {
357 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
358 return;
359 lwarn("%s: read error", __func__)logger->warn("%s: read error", __func__);
360 return;
361 }
362
363 if (n == 0)
364 lerr(1, "routing socket closed")logger->err((1), "routing socket closed");
365
366 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
367 lwarnx("partial rtm of %zd in buffer", n)logger->warnx("partial rtm of %zd in buffer", n);
368 return;
369 }
370
371 if (rtm->rtm_version != RTM_VERSION5)
372 return;
373
374 if (rtm->rtm_pid == getpid())
375 return;
376
377 sa = (struct sockaddr *)(rsock_buf + rtm->rtm_hdrlen);
378 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
379 handle_route_message(rtm, rti_info);
380}
381
382void
383zeroslot(struct rdns_proposal *tab)
384{
385 tab->prio = 0;
386 tab->af = 0;
387 tab->if_index = 0;
388 tab->ip[0] = '\0';
389}
390
391int
392findslot(struct rdns_proposal *tab)
393{
394 int i;
395
396 for (i = 0; i < ASR_MAXNS10; i++)
397 if (tab[i].prio == 0)
398 return i;
399
400 /* New proposals might be important, so replace the last slot */
401 i = ASR_MAXNS10 - 1;
402 zeroslot(&tab[i]);
403 return i;
404}
405
406void
407handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
408{
409 struct rdns_proposal learning[nitems(learned)(sizeof((learned)) / sizeof((learned)[0]))];
410 struct sockaddr_rtdns *rtdns;
411 struct if_announcemsghdr *ifan;
412 size_t addrsz;
413 int rdns_count, af, i;
414 char *src;
415
416 memcpy(learning, learned, sizeof learned);
417
418 switch (rtm->rtm_type) {
419 case RTM_IFANNOUNCE0xf:
420 ifan = (struct if_announcemsghdr *)rtm;
421 if (ifan->ifan_what == IFAN_ARRIVAL0)
422 return;
423 /* Delete proposals learned from departing interfaces */
424 for (i = 0; i < ASR_MAXNS10; i++)
425 if (learning[i].if_index == ifan->ifan_index)
426 zeroslot(&learning[i]);
427 break;
428 case RTM_PROPOSAL0x13:
429 if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT62) {
430#ifndef SMALL
431 check_unwind = 1;
432#endif /* SMALL */
433 return;
434 }
435
436 if (!(rtm->rtm_addrs & RTA_DNS0x1000))
437 return;
438
439 rtdns = (struct sockaddr_rtdns*)rti_info[RTAX_DNS12];
440 src = rtdns->sr_dns;
441 af = rtdns->sr_family;
442
443 switch (af) {
444 case AF_INET2:
445 addrsz = sizeof(struct in_addr);
446 break;
447 case AF_INET624:
448 addrsz = sizeof(struct in6_addr);
449 break;
450 default:
451 lwarnx("ignoring invalid RTM_PROPOSAL")logger->warnx("ignoring invalid RTM_PROPOSAL");
452 return;
453 }
454
455 if ((rtdns->sr_len - 2) % addrsz != 0) {
456 lwarnx("ignoring invalid RTM_PROPOSAL")logger->warnx("ignoring invalid RTM_PROPOSAL");
457 return;
458 }
459 rdns_count = (rtdns->sr_len -
460 offsetof(struct sockaddr_rtdns, sr_dns)__builtin_offsetof(struct sockaddr_rtdns, sr_dns)) / addrsz;
461
462 /* New proposal from interface means previous proposals expire */
463 for (i = 0; i < ASR_MAXNS10; i++)
464 if (learning[i].af == af &&
465 learning[i].if_index == rtm->rtm_index)
466 zeroslot(&learning[i]);
467
468 /* Add the new proposals */
469 for (i = 0; i < rdns_count; i++) {
470 struct sockaddr_storage ss;
471 struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
472 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
473 int new, err;
474
475 memset(&ss, 0, sizeof(ss));
476 ss.ss_family = af;
477 new = findslot(learning);
478 switch (af) {
479 case AF_INET2:
480 memcpy(&sin->sin_addr, src, addrsz);
481 ss.ss_len = sizeof(*sin);
482 break;
483 case AF_INET624:
484 memcpy(&sin6->sin6_addr, src, addrsz);
485 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))
)
486 sin6->sin6_scope_id = rtm->rtm_index;
487 ss.ss_len = sizeof(*sin6);
488 break;
489 }
490 src += addrsz;
491
492 if ((err = getnameinfo((struct sockaddr *)&ss, ss.ss_len,
493 learning[new].ip, sizeof(learning[new].ip),
494 NULL((void*)0), 0, NI_NUMERICHOST1)) == 0) {
495 learning[new].prio = rtm->rtm_priority;
496 learning[new].if_index = rtm->rtm_index;
497 learning[new].af = af;
498 } else
499 lwarnx("getnameinfo: %s", gai_strerror(err))logger->warnx("getnameinfo: %s", gai_strerror(err));
500 }
501 break;
502 default:
503 return;
504 }
505
506 /* Sort proposals, based upon priority and IP */
507 qsort(learning, ASR_MAXNS10, sizeof(learning[0]), cmp);
508
509 /* Eliminate duplicates */
510 for (i = 0; i < ASR_MAXNS10 - 1; i++) {
511 if (learning[i].prio == 0)
512 continue;
513 if (learning[i].if_index == learning[i+1].if_index &&
514 strcmp(learning[i].ip, learning[i+1].ip) == 0) {
515 zeroslot(&learning[i + 1]);
516 i--; /* backup and re-check */
517 }
518 }
519
520 /* If proposal result is different, rebuild the file */
521 if (memcmp(learned, learning, sizeof(learned)) != 0) {
522 memcpy(learned, learning, sizeof(learned));
523 regen_resolvconf("route proposals");
524 }
525}
526
527#define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof
(long))
\
528 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
529
530void
531get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
532{
533 int i;
534
535 for (i = 0; i < RTAX_MAX15; i++) {
536 if (addrs & (1 << i)) {
537 rti_info[i] = sa;
538 sa = (struct sockaddr *)((char *)(sa) +
539 ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
);
540 } else
541 rti_info[i] = NULL((void*)0);
542 }
543}
544
545void
546solicit_dns_proposals(int routesock)
547{
548 struct rt_msghdr rtm;
549 struct iovec iov[1];
550 int iovcnt = 0;
551
552 memset(&rtm, 0, sizeof(rtm));
553
554 rtm.rtm_version = RTM_VERSION5;
555 rtm.rtm_type = RTM_PROPOSAL0x13;
556 rtm.rtm_msglen = sizeof(rtm);
557 rtm.rtm_tableid = 0;
558 rtm.rtm_index = 0;
559 rtm.rtm_seq = arc4random();
560 rtm.rtm_priority = RTP_PROPOSAL_SOLICIT62;
561
562 iov[iovcnt].iov_base = &rtm;
563 iov[iovcnt++].iov_len = sizeof(rtm);
564
565 if (writev(routesock, iov, iovcnt) == -1)
566 lwarn("failed to send solicitation")logger->warn("failed to send solicitation");
567}
568
569void
570regen_resolvconf(char *why)
571{
572 int i, fd;
573
574 linfo("rebuilding: %s", why)logger->info("rebuilding: %s", why);
575
576 if ((fd = open(_PATH_RESCONF_NEW"/etc/resolv.conf.new", O_CREAT0x0200|O_TRUNC0x0400|O_RDWR0x0002, 0644)) == -1) {
577 lwarn(_PATH_RESCONF_NEW)logger->warn("/etc/resolv.conf.new");
578 return;
579 }
580
581#ifndef SMALL
582 if (unwind_running)
583 dprintf(fd, "nameserver 127.0.0.1 # resolvd: unwind\n");
584
585#endif /* SMALL */
586 for (i = 0; i < ASR_MAXNS10; i++) {
587 if (learned[i].prio != 0) {
588 char ifnambuf[IF_NAMESIZE16], *ifnam;
589
590 ifnam = if_indextoname(learned[i].if_index,
591 ifnambuf);
592 dprintf(fd, "%snameserver %s # resolvd: %s\n",
593#ifndef SMALL
594 unwind_running ? "#" : "",
595#else
596 "",
597#endif
598 learned[i].ip,
599 ifnam ? ifnam : "");
600 }
601 }
602
603 /* Replay user-managed lines from old resolv.conf file */
604 if (resolvfd == -1)
605 resolvfd = open(_PATH_RESCONF"/etc/resolv.conf", O_RDWR0x0002);
606 if (resolvfd != -1) {
607 char *line = NULL((void*)0);
608 size_t linesize = 0;
609 ssize_t linelen;
610 FILE *fp;
611
612 lseek(resolvfd, 0, SEEK_SET0);
613 fp = fdopen(resolvfd, "r");
614 if (fp == NULL((void*)0))
615 goto err;
616 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'
617 char *end = strchr(line, '\n');
618 if (end)
619 *end = '\0';
620 if (strstr(line, "# resolvd: "))
621 continue;
622 dprintf(fd, "%s\n", line);
623 }
624 free(line);
625 }
626
627 if (rename(_PATH_RESCONF_NEW"/etc/resolv.conf.new", _PATH_RESCONF"/etc/resolv.conf") == -1)
628 goto err;
629
630 if (resolvfd == -1) {
631 close(fd);
632 resolvfd = open(_PATH_RESCONF"/etc/resolv.conf", O_RDWR0x0002 | O_CREAT0x0200);
633 } else {
634 dup2(fd, resolvfd);
635 close(fd);
636 }
637
638 newkevent = 1;
639 return;
640
641 err:
642 if (fd != -1)
643 close(fd);
644 unlink(_PATH_RESCONF_NEW"/etc/resolv.conf.new");
645}
646
647int
648cmp(const void *a, const void *b)
649{
650 const struct rdns_proposal *rpa = a, *rpb = b;
651
652 if (rpa->prio == rpb->prio)
653 return strcmp(rpa->ip, rpb->ip);
654 else
655 return rpa->prio < rpb->prio ? -1 : 1;
656}
657
658#ifndef SMALL
659int
660open_unwind_ctl(void)
661{
662 static struct sockaddr_un sun;
663 int s;
664
665 if (sun.sun_family == 0) {
666 sun.sun_family = AF_UNIX1;
667 strlcpy(sun.sun_path, _PATH_UNWIND_SOCKET"/dev/unwind.sock", sizeof(sun.sun_path));
668 }
669
670 if ((s = socket(AF_UNIX1, SOCK_STREAM1, 0)) != -1) {
671 if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
672 close(s);
673 s = -1;
674 }
675 }
676 newkevent = 1;
677 return s;
678}
679
680void
681syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
682{
683 char *s;
684
685 if (vasprintf(&s, fmt, ap) == -1) {
686 syslog(LOG_EMERG0, "unable to alloc in syslog_vstrerror");
687 exit(1);
688 }
689 syslog(priority, "%s: %s", s, strerror(e));
690 free(s);
691}
692
693__dead__attribute__((__noreturn__)) void
694syslog_err(int ecode, const char *fmt, ...)
695{
696 va_list ap;
697
698 va_start(ap, fmt)__builtin_va_start(ap, fmt);
699 syslog_vstrerror(errno(*__errno()), LOG_CRIT2, fmt, ap);
700 va_end(ap)__builtin_va_end(ap);
701 exit(ecode);
702}
703
704__dead__attribute__((__noreturn__)) void
705syslog_errx(int ecode, const char *fmt, ...)
706{
707 va_list ap;
708
709 va_start(ap, fmt)__builtin_va_start(ap, fmt);
710 vsyslog(LOG_CRIT2, fmt, ap);
711 va_end(ap)__builtin_va_end(ap);
712 exit(ecode);
713}
714
715void
716syslog_warn(const char *fmt, ...)
717{
718 va_list ap;
719
720 va_start(ap, fmt)__builtin_va_start(ap, fmt);
721 syslog_vstrerror(errno(*__errno()), LOG_ERR3, fmt, ap);
722 va_end(ap)__builtin_va_end(ap);
723}
724
725void
726syslog_warnx(const char *fmt, ...)
727{
728 va_list ap;
729
730 va_start(ap, fmt)__builtin_va_start(ap, fmt);
731 vsyslog(LOG_ERR3, fmt, ap);
732 va_end(ap)__builtin_va_end(ap);
733}
734
735void
736syslog_info(const char *fmt, ...)
737{
738 va_list ap;
739
740 va_start(ap, fmt)__builtin_va_start(ap, fmt);
741 vsyslog(LOG_INFO6, fmt, ap);
742 va_end(ap)__builtin_va_end(ap);
743}
744
745void
746syslog_debug(const char *fmt, ...)
747{
748 va_list ap;
749
750 va_start(ap, fmt)__builtin_va_start(ap, fmt);
751 vsyslog(LOG_DEBUG7, fmt, ap);
752 va_end(ap)__builtin_va_end(ap);
753}
754
755void
756warnx_verbose(const char *fmt, ...)
757{
758 va_list ap;
759
760 va_start(ap, fmt)__builtin_va_start(ap, fmt);
761 if (verbose)
762 vwarnx(fmt, ap);
763 va_end(ap)__builtin_va_end(ap);
764}
765
766#endif /* SMALL */