File: | src/usr.sbin/dvmrpd/dvmrpd.c |
Warning: | line 140, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: dvmrpd.c,v 1.27 2021/01/19 12:29:46 claudio Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> |
5 | * Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org> |
6 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> |
7 | * |
8 | * Permission to use, copy, modify, and distribute this software for any |
9 | * purpose with or without fee is hereby granted, provided that the above |
10 | * copyright notice and this permission notice appear in all copies. |
11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 | */ |
20 | |
21 | #include <sys/types.h> |
22 | #include <sys/socket.h> |
23 | #include <sys/queue.h> |
24 | #include <sys/time.h> |
25 | #include <sys/stat.h> |
26 | #include <sys/sysctl.h> |
27 | #include <sys/wait.h> |
28 | |
29 | #include <netinet/in.h> |
30 | #include <arpa/inet.h> |
31 | |
32 | #include <event.h> |
33 | #include <err.h> |
34 | #include <errno(*__errno()).h> |
35 | #include <pwd.h> |
36 | #include <stdio.h> |
37 | #include <stdlib.h> |
38 | #include <string.h> |
39 | #include <signal.h> |
40 | #include <unistd.h> |
41 | #include <util.h> |
42 | |
43 | #include "igmp.h" |
44 | #include "dvmrpd.h" |
45 | #include "dvmrp.h" |
46 | #include "dvmrpe.h" |
47 | #include "control.h" |
48 | #include "log.h" |
49 | #include "rde.h" |
50 | |
51 | void main_sig_handler(int, short, void *); |
52 | __dead__attribute__((__noreturn__)) void usage(void); |
53 | __dead__attribute__((__noreturn__)) void dvmrpd_shutdown(void); |
54 | |
55 | void main_dispatch_dvmrpe(int, short, void *); |
56 | void main_dispatch_rde(int, short, void *); |
57 | void main_imsg_compose_dvmrpe(int, pid_t, void *, u_int16_t); |
58 | void main_imsg_compose_rde(int, pid_t, void *, u_int16_t); |
59 | |
60 | int pipe_parent2dvmrpe[2]; |
61 | int pipe_parent2rde[2]; |
62 | int pipe_dvmrpe2rde[2]; |
63 | |
64 | struct dvmrpd_conf *conf = NULL((void *)0); |
65 | static struct imsgev *iev_dvmrpe; |
66 | static struct imsgev *iev_rde; |
67 | |
68 | pid_t dvmrpe_pid; |
69 | pid_t rde_pid; |
70 | |
71 | void |
72 | main_sig_handler(int sig, short event, void *arg) |
73 | { |
74 | /* signal handler rules don't apply, libevent decouples for us */ |
75 | switch (sig) { |
76 | case SIGTERM15: |
77 | case SIGINT2: |
78 | dvmrpd_shutdown(); |
79 | /* NOTREACHED */ |
80 | case SIGHUP1: |
81 | /* reconfigure */ |
82 | /* ... */ |
83 | break; |
84 | default: |
85 | fatalx("unexpected signal"); |
86 | /* NOTREACHED */ |
87 | } |
88 | } |
89 | |
90 | __dead__attribute__((__noreturn__)) void |
91 | usage(void) |
92 | { |
93 | extern char *__progname; |
94 | |
95 | fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-f file]\n", __progname); |
96 | exit(1); |
97 | } |
98 | |
99 | int |
100 | main(int argc, char *argv[]) |
101 | { |
102 | struct event ev_sigint, ev_sigterm, ev_sighup; |
103 | char *conffile; |
104 | int ch, opts = 0; |
105 | int debug = 0; |
106 | int ipmforwarding; |
107 | int mib[4]; |
108 | size_t len; |
109 | |
110 | conffile = CONF_FILE"/etc/dvmrpd.conf"; |
111 | log_procname = "parent"; |
112 | |
113 | log_init(1); /* log to stderr until daemonized */ |
114 | log_verbose(1); |
115 | |
116 | while ((ch = getopt(argc, argv, "df:nv")) != -1) { |
117 | switch (ch) { |
118 | case 'd': |
119 | debug = 1; |
120 | break; |
121 | case 'f': |
122 | conffile = optarg; |
123 | break; |
124 | case 'n': |
125 | opts |= DVMRPD_OPT_NOACTION0x00000004; |
126 | break; |
127 | case 'v': |
128 | if (opts & DVMRPD_OPT_VERBOSE0x00000001) |
129 | opts |= DVMRPD_OPT_VERBOSE20x00000002; |
130 | opts |= DVMRPD_OPT_VERBOSE0x00000001; |
131 | log_verbose(1); |
132 | break; |
133 | default: |
134 | usage(); |
135 | /* NOTREACHED */ |
136 | } |
137 | } |
138 | |
139 | argc -= optind; |
140 | argv += optind; |
Value stored to 'argv' is never read | |
141 | if (argc > 0) |
142 | usage(); |
143 | |
144 | log_init(debug); |
145 | log_verbose(opts & DVMRPD_OPT_VERBOSE0x00000001); |
146 | |
147 | /* multicast IP forwarding must be enabled */ |
148 | mib[0] = CTL_NET4; |
149 | mib[1] = PF_INET2; |
150 | mib[2] = IPPROTO_IP0; |
151 | mib[3] = IPCTL_MFORWARDING31; |
152 | len = sizeof(ipmforwarding); |
153 | if (sysctl(mib, 4, &ipmforwarding, &len, NULL((void *)0), 0) == -1) |
154 | err(1, "sysctl"); |
155 | |
156 | if (!ipmforwarding) |
157 | errx(1, "multicast IP forwarding not enabled"); |
158 | |
159 | /* fetch interfaces early */ |
160 | kif_init(); |
161 | |
162 | /* parse config file */ |
163 | if ((conf = parse_config(conffile, opts)) == NULL((void *)0) ) |
164 | exit(1); |
165 | |
166 | if (conf->opts & DVMRPD_OPT_NOACTION0x00000004) { |
167 | if (conf->opts & DVMRPD_OPT_VERBOSE0x00000001) |
168 | print_config(conf); |
169 | else |
170 | fprintf(stderr(&__sF[2]), "configuration OK\n"); |
171 | exit(0); |
172 | } |
173 | |
174 | /* check for root privileges */ |
175 | if (geteuid()) |
176 | errx(1, "need root privileges"); |
177 | |
178 | /* check for dvmrpd user */ |
179 | if (getpwnam(DVMRPD_USER"_dvmrpd") == NULL((void *)0)) |
180 | errx(1, "unknown user %s", DVMRPD_USER"_dvmrpd"); |
181 | |
182 | /* start logging */ |
183 | log_init(1); |
184 | |
185 | if (!debug) |
186 | daemon(1, 0); |
187 | |
188 | log_info("startup"); |
189 | |
190 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
191 | PF_UNSPEC0, pipe_parent2dvmrpe) == -1) |
192 | fatal("socketpair"); |
193 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
194 | PF_UNSPEC0, pipe_parent2rde) == -1) |
195 | fatal("socketpair"); |
196 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
197 | PF_UNSPEC0, pipe_dvmrpe2rde) == -1) |
198 | fatal("socketpair"); |
199 | |
200 | /* start children */ |
201 | rde_pid = rde(conf, pipe_parent2rde, pipe_dvmrpe2rde, |
202 | pipe_parent2dvmrpe); |
203 | dvmrpe_pid = dvmrpe(conf, pipe_parent2dvmrpe, pipe_dvmrpe2rde, |
204 | pipe_parent2rde); |
205 | |
206 | /* create the raw ip socket */ |
207 | if ((conf->mroute_socket = socket(AF_INET2, |
208 | SOCK_RAW3 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
209 | IPPROTO_IGMP2)) == -1) |
210 | fatal("error creating raw socket"); |
211 | |
212 | if_set_recvbuf(conf->mroute_socket); |
213 | |
214 | if (mrt_init(conf->mroute_socket)) |
215 | fatal("multicast routing not enabled in kernel"); |
216 | |
217 | event_init(); |
218 | |
219 | /* setup signal handler */ |
220 | signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void *)0)); |
221 | signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, ( (void *)0)); |
222 | signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL)event_set(&ev_sighup, 1, 0x08|0x10, main_sig_handler, ((void *)0)); |
223 | signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0)); |
224 | signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0)); |
225 | signal_add(&ev_sighup, NULL)event_add(&ev_sighup, ((void *)0)); |
226 | signal(SIGPIPE13, SIG_IGN(void (*)(int))1); |
227 | |
228 | /* setup pipes to children */ |
229 | close(pipe_parent2dvmrpe[1]); |
230 | close(pipe_parent2rde[1]); |
231 | close(pipe_dvmrpe2rde[0]); |
232 | close(pipe_dvmrpe2rde[1]); |
233 | |
234 | if ((iev_dvmrpe = malloc(sizeof(struct imsgev))) == NULL((void *)0) || |
235 | (iev_rde = malloc(sizeof(struct imsgev))) == NULL((void *)0)) |
236 | fatal(NULL((void *)0)); |
237 | imsg_init(&iev_dvmrpe->ibuf, pipe_parent2dvmrpe[0]); |
238 | imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]); |
239 | iev_dvmrpe->handler = main_dispatch_dvmrpe; |
240 | iev_rde->handler = main_dispatch_rde; |
241 | |
242 | /* setup event handler */ |
243 | iev_dvmrpe->events = EV_READ0x02; |
244 | event_set(&iev_dvmrpe->ev, iev_dvmrpe->ibuf.fd, iev_dvmrpe->events, |
245 | iev_dvmrpe->handler, iev_dvmrpe); |
246 | event_add(&iev_dvmrpe->ev, NULL((void *)0)); |
247 | |
248 | iev_rde->events = EV_READ0x02; |
249 | event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, |
250 | iev_rde->handler, iev_rde); |
251 | event_add(&iev_rde->ev, NULL((void *)0)); |
252 | |
253 | if (kmr_init(!(conf->flags & DVMRPD_FLAG_NO_FIB_UPDATE0x0001)) == -1) |
254 | dvmrpd_shutdown(); |
255 | if (kr_init() == -1) |
256 | dvmrpd_shutdown(); |
257 | |
258 | event_set(&conf->ev, conf->mroute_socket, EV_READ0x02|EV_PERSIST0x10, |
259 | kmr_recv_msg, conf); |
260 | event_add(&conf->ev, NULL((void *)0)); |
261 | |
262 | event_dispatch(); |
263 | |
264 | dvmrpd_shutdown(); |
265 | /* NOTREACHED */ |
266 | return (0); |
267 | } |
268 | |
269 | __dead__attribute__((__noreturn__)) void |
270 | dvmrpd_shutdown(void) |
271 | { |
272 | struct iface *iface; |
273 | pid_t pid; |
274 | int status; |
275 | |
276 | /* close pipes */ |
277 | msgbuf_clear(&iev_dvmrpe->ibuf.w); |
278 | close(iev_dvmrpe->ibuf.fd); |
279 | msgbuf_clear(&iev_rde->ibuf.w); |
280 | close(iev_rde->ibuf.fd); |
281 | |
282 | control_cleanup(); |
283 | kmr_shutdown(); |
284 | kr_shutdown(); |
285 | LIST_FOREACH(iface, &conf->iface_list, entry)for((iface) = ((&conf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) { |
286 | if_del(iface); |
287 | } |
288 | mrt_done(conf->mroute_socket); |
289 | |
290 | log_debug("waiting for children to terminate"); |
291 | do { |
292 | pid = wait(&status); |
293 | if (pid == -1) { |
294 | if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10) |
295 | fatal("wait"); |
296 | } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177 ) != 0)) |
297 | log_warnx("%s terminated; signal %d", |
298 | (pid == rde_pid) ? "route decision engine" : |
299 | "dvmrp engine", WTERMSIG(status)(((status) & 0177))); |
300 | } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4)); |
301 | |
302 | free(iev_dvmrpe); |
303 | free(iev_rde); |
304 | |
305 | log_info("terminating"); |
306 | exit(0); |
307 | } |
308 | |
309 | /* imsg handling */ |
310 | void |
311 | main_dispatch_dvmrpe(int fd, short event, void *bula) |
312 | { |
313 | struct imsgev *iev = bula; |
314 | struct imsgbuf *ibuf = &iev->ibuf; |
315 | struct imsg imsg; |
316 | ssize_t n; |
317 | int shut = 0, verbose; |
318 | |
319 | if (event & EV_READ0x02) { |
320 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) |
321 | fatal("imsg_read error"); |
322 | if (n == 0) /* connection closed */ |
323 | shut = 1; |
324 | } |
325 | if (event & EV_WRITE0x04) { |
326 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) |
327 | fatal("msgbuf_write"); |
328 | if (n == 0) /* connection closed */ |
329 | shut = 1; |
330 | } |
331 | |
332 | for (;;) { |
333 | if ((n = imsg_get(ibuf, &imsg)) == -1) |
334 | fatal("imsg_get"); |
335 | |
336 | if (n == 0) |
337 | break; |
338 | |
339 | switch (imsg.hdr.type) { |
340 | case IMSG_CTL_RELOAD: |
341 | log_debug("main_dispatch_dvmrpe: IMSG_CTL_RELOAD"); |
342 | /* reconfig */ |
343 | break; |
344 | case IMSG_CTL_MFC_COUPLE: |
345 | kmr_mfc_couple(); |
346 | break; |
347 | case IMSG_CTL_MFC_DECOUPLE: |
348 | kmr_mfc_decouple(); |
349 | break; |
350 | case IMSG_CTL_LOG_VERBOSE: |
351 | /* already checked by dvmrpe */ |
352 | memcpy(&verbose, imsg.data, sizeof(verbose)); |
353 | log_verbose(verbose); |
354 | break; |
355 | default: |
356 | log_debug("main_dispatch_dvmrpe: error handling " |
357 | "imsg %d", imsg.hdr.type); |
358 | break; |
359 | } |
360 | imsg_free(&imsg); |
361 | } |
362 | if (!shut) |
363 | imsg_event_add(iev); |
364 | else { |
365 | /* this pipe is dead, so remove the event handler */ |
366 | event_del(&iev->ev); |
367 | event_loopexit(NULL((void *)0)); |
368 | } |
369 | } |
370 | |
371 | void |
372 | main_dispatch_rde(int fd, short event, void *bula) |
373 | { |
374 | struct mfc mfc; |
375 | struct imsgev *iev = bula; |
376 | struct imsgbuf *ibuf = &iev->ibuf; |
377 | struct imsg imsg; |
378 | ssize_t n; |
379 | int shut = 0; |
380 | |
381 | if (event & EV_READ0x02) { |
382 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) |
383 | fatal("imsg_read error"); |
384 | if (n == 0) /* connection closed */ |
385 | shut = 1; |
386 | } |
387 | if (event & EV_WRITE0x04) { |
388 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) |
389 | fatal("msgbuf_write"); |
390 | if (n == 0) /* connection closed */ |
391 | shut = 1; |
392 | } |
393 | |
394 | for (;;) { |
395 | if ((n = imsg_get(ibuf, &imsg)) == -1) |
396 | fatal("imsg_get"); |
397 | |
398 | if (n == 0) |
399 | break; |
400 | |
401 | switch (imsg.hdr.type) { |
402 | case IMSG_MFC_ADD: |
403 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != sizeof(mfc)) |
404 | fatalx("invalid size of RDE request"); |
405 | memcpy(&mfc, imsg.data, sizeof(mfc)); |
406 | |
407 | /* add to MFC */ |
408 | mrt_add_mfc(conf->mroute_socket, &mfc); |
409 | break; |
410 | case IMSG_MFC_DEL: |
411 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != sizeof(mfc)) |
412 | fatalx("invalid size of RDE request"); |
413 | memcpy(&mfc, imsg.data, sizeof(mfc)); |
414 | |
415 | /* remove from MFC */ |
416 | mrt_del_mfc(conf->mroute_socket, &mfc); |
417 | break; |
418 | default: |
419 | log_debug("main_dispatch_rde: error handling imsg %d", |
420 | imsg.hdr.type); |
421 | break; |
422 | } |
423 | imsg_free(&imsg); |
424 | } |
425 | if (!shut) |
426 | imsg_event_add(iev); |
427 | else { |
428 | /* this pipe is dead, so remove the event handler */ |
429 | event_del(&iev->ev); |
430 | event_loopexit(NULL((void *)0)); |
431 | } |
432 | } |
433 | |
434 | void |
435 | main_imsg_compose_dvmrpe(int type, pid_t pid, void *data, u_int16_t datalen) |
436 | { |
437 | imsg_compose_event(iev_dvmrpe, type, 0, pid, -1, data, datalen); |
438 | } |
439 | |
440 | void |
441 | main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen) |
442 | { |
443 | imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen); |
444 | } |
445 | |
446 | void |
447 | imsg_event_add(struct imsgev *iev) |
448 | { |
449 | iev->events = EV_READ0x02; |
450 | if (iev->ibuf.w.queued) |
451 | iev->events |= EV_WRITE0x04; |
452 | |
453 | event_del(&iev->ev); |
454 | event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); |
455 | event_add(&iev->ev, NULL((void *)0)); |
456 | } |
457 | |
458 | int |
459 | imsg_compose_event(struct imsgev *iev, u_int16_t type, |
460 | u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen) |
461 | { |
462 | int ret; |
463 | |
464 | if ((ret = imsg_compose(&iev->ibuf, type, peerid, |
465 | pid, fd, data, datalen)) != -1) |
466 | imsg_event_add(iev); |
467 | return (ret); |
468 | } |