1 /* $OpenBSD: frontend.c,v 1.14 2024/07/11 13:38:03 florian Exp $ */
2
3 /*
4 * Copyright (c) 2017, 2021, 2024 Florian Obser <florian@openbsd.org>
5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/queue.h>
24 #include <sys/socket.h>
25 #include <sys/syslog.h>
26 #include <sys/uio.h>
27 #include <sys/utsname.h>
28
29 #include <net/if.h>
30 #include <net/if_dl.h>
31 #include <net/if_types.h>
32 #include <net/route.h>
33
34 #include <netinet/in.h>
35 #include <netinet/ip.h>
36
37 #include <arpa/inet.h>
38
39 #include <errno.h>
40 #include <event.h>
41 #include <ifaddrs.h>
42 #include <imsg.h>
43 #include <pwd.h>
44 #include <signal.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 #include "log.h"
51 #include "dhcp6leased.h"
52 #include "frontend.h"
53 #include "control.h"
54
55 #define ALL_DHCP_RELAY_AGENTS_AND_SERVERS "ff02::1:2"
56 #define ROUTE_SOCKET_BUF_SIZE 16384
57
58 struct iface {
59 LIST_ENTRY(iface) entries;
60 struct event udpev;
61 struct imsg_ifinfo ifinfo;
62 int send_solicit;
63 int elapsed_time;
64 uint8_t xid[XID_SIZE];
65 int serverid_len;
66 uint8_t serverid[SERVERID_SIZE];
67 struct prefix pds[MAX_IA];
68 };
69
70 __dead void frontend_shutdown(void);
71 void frontend_sig_handler(int, short, void *);
72 void frontend_startup(void);
73 void update_iface(uint32_t);
74 void route_receive(int, short, void *);
75 void handle_route_message(struct rt_msghdr *, struct sockaddr **);
76 void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
77 void udp_receive(int, short, void *);
78 int get_flags(char *);
79 struct iface *get_iface_by_id(uint32_t);
80 struct iface *get_iface_by_name(const char *);
81 void remove_iface(uint32_t);
82 void set_udpsock(int, uint32_t);
83 void iface_data_from_imsg(struct iface*, struct imsg_req_dhcp *);
84 ssize_t build_packet(uint8_t, struct iface *, char *);
85 void send_packet(uint8_t, struct iface *);
86 int iface_conf_cmp(struct iface_conf *, struct iface_conf *);
87
88 LIST_HEAD(, iface) interfaces;
89 struct dhcp6leased_conf *frontend_conf;
90 static struct imsgev *iev_main;
91 static struct imsgev *iev_engine;
92 struct event ev_route;
93 struct sockaddr_in6 dst;
94 int ioctlsock;
95
96 uint8_t dhcp_packet[1500];
97 static struct dhcp_duid duid;
98 char *vendor_class_data;
99 int vendor_class_len;
100
101 void
frontend_sig_handler(int sig,short event,void * bula)102 frontend_sig_handler(int sig, short event, void *bula)
103 {
104 /*
105 * Normal signal handler rules don't apply because libevent
106 * decouples for us.
107 */
108
109 switch (sig) {
110 case SIGINT:
111 case SIGTERM:
112 frontend_shutdown();
113 default:
114 fatalx("unexpected signal");
115 }
116 }
117
118 void
frontend(int debug,int verbose)119 frontend(int debug, int verbose)
120 {
121 struct event ev_sigint, ev_sigterm;
122 struct passwd *pw;
123 struct utsname utsname;
124
125 frontend_conf = config_new_empty();
126
127 log_init(debug, LOG_DAEMON);
128 log_setverbose(verbose);
129
130 if ((pw = getpwnam(DHCP6LEASED_USER)) == NULL)
131 fatal("getpwnam");
132
133 if (chdir("/") == -1)
134 fatal("chdir(\"/\")");
135
136 if (unveil("/", "") == -1)
137 fatal("unveil /");
138 if (unveil(NULL, NULL) == -1)
139 fatal("unveil");
140
141 setproctitle("%s", "frontend");
142 log_procinit("frontend");
143
144 if ((ioctlsock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1)
145 fatal("socket");
146
147 if (setgroups(1, &pw->pw_gid) ||
148 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
149 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
150 fatal("can't drop privileges");
151
152 if (pledge("stdio unix recvfd route", NULL) == -1)
153 fatal("pledge");
154
155 if (uname(&utsname) == -1)
156 fatal("uname");
157 vendor_class_len = asprintf(&vendor_class_data, "%s %s %s",
158 utsname.sysname, utsname.release, utsname.machine);
159 if (vendor_class_len == -1)
160 fatal("Cannot generate vendor-class-data");
161
162 memset(&dst, 0, sizeof(dst));
163 dst.sin6_family = AF_INET6;
164 if (inet_pton(AF_INET6, ALL_DHCP_RELAY_AGENTS_AND_SERVERS,
165 &dst.sin6_addr.s6_addr) != 1)
166 fatal("inet_pton");
167
168 dst.sin6_port = ntohs(SERVER_PORT);
169
170 event_init();
171
172 /* Setup signal handler. */
173 signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL);
174 signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL);
175 signal_add(&ev_sigint, NULL);
176 signal_add(&ev_sigterm, NULL);
177 signal(SIGPIPE, SIG_IGN);
178 signal(SIGHUP, SIG_IGN);
179
180 /* Setup pipe and event handler to the parent process. */
181 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
182 fatal(NULL);
183 imsg_init(&iev_main->ibuf, 3);
184 iev_main->handler = frontend_dispatch_main;
185 iev_main->events = EV_READ;
186 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
187 iev_main->handler, iev_main);
188 event_add(&iev_main->ev, NULL);
189
190 LIST_INIT(&interfaces);
191 event_dispatch();
192
193 frontend_shutdown();
194 }
195
196 __dead void
frontend_shutdown(void)197 frontend_shutdown(void)
198 {
199 /* Close pipes. */
200 msgbuf_write(&iev_engine->ibuf.w);
201 msgbuf_clear(&iev_engine->ibuf.w);
202 close(iev_engine->ibuf.fd);
203 msgbuf_write(&iev_main->ibuf.w);
204 msgbuf_clear(&iev_main->ibuf.w);
205 close(iev_main->ibuf.fd);
206
207 config_clear(frontend_conf);
208
209 free(iev_engine);
210 free(iev_main);
211
212 log_info("frontend exiting");
213 exit(0);
214 }
215
216 int
frontend_imsg_compose_main(int type,pid_t pid,void * data,uint16_t datalen)217 frontend_imsg_compose_main(int type, pid_t pid, void *data,
218 uint16_t datalen)
219 {
220 return (imsg_compose_event(iev_main, type, 0, pid, -1, data,
221 datalen));
222 }
223
224 int
frontend_imsg_compose_engine(int type,uint32_t peerid,pid_t pid,void * data,uint16_t datalen)225 frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid,
226 void *data, uint16_t datalen)
227 {
228 return (imsg_compose_event(iev_engine, type, peerid, pid, -1,
229 data, datalen));
230 }
231
232 void
frontend_dispatch_main(int fd,short event,void * bula)233 frontend_dispatch_main(int fd, short event, void *bula)
234 {
235 static struct dhcp6leased_conf *nconf;
236 static struct iface_conf *iface_conf;
237 static struct iface_ia_conf *iface_ia_conf;
238 struct iface_pd_conf *iface_pd_conf;
239 struct imsg imsg;
240 struct imsgev *iev = bula;
241 struct imsgbuf *ibuf = &iev->ibuf;
242 ssize_t n;
243 int shut = 0, udpsock, if_index;
244
245 if (event & EV_READ) {
246 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
247 fatal("imsg_read error");
248 if (n == 0) /* Connection closed. */
249 shut = 1;
250 }
251 if (event & EV_WRITE) {
252 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
253 fatal("msgbuf_write");
254 if (n == 0) /* Connection closed. */
255 shut = 1;
256 }
257
258 for (;;) {
259 if ((n = imsg_get(ibuf, &imsg)) == -1)
260 fatal("%s: imsg_get error", __func__);
261 if (n == 0) /* No more messages. */
262 break;
263
264 switch (imsg.hdr.type) {
265 case IMSG_SOCKET_IPC:
266 /*
267 * Setup pipe and event handler to the engine
268 * process.
269 */
270 if (iev_engine)
271 fatalx("%s: received unexpected imsg fd "
272 "to frontend", __func__);
273
274 if ((fd = imsg_get_fd(&imsg)) == -1)
275 fatalx("%s: expected to receive imsg fd to "
276 "frontend but didn't receive any",
277 __func__);
278
279 iev_engine = malloc(sizeof(struct imsgev));
280 if (iev_engine == NULL)
281 fatal(NULL);
282
283 imsg_init(&iev_engine->ibuf, fd);
284 iev_engine->handler = frontend_dispatch_engine;
285 iev_engine->events = EV_READ;
286
287 event_set(&iev_engine->ev, iev_engine->ibuf.fd,
288 iev_engine->events, iev_engine->handler, iev_engine);
289 event_add(&iev_engine->ev, NULL);
290 break;
291 case IMSG_UDPSOCK:
292 if ((udpsock = imsg_get_fd(&imsg)) == -1)
293 fatalx("%s: expected to receive imsg "
294 "udp fd but didn't receive any",
295 __func__);
296 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
297 fatalx("%s: IMSG_UDPSOCK wrong length: "
298 "%lu", __func__, IMSG_DATA_SIZE(imsg));
299 memcpy(&if_index, imsg.data, sizeof(if_index));
300 set_udpsock(udpsock, if_index);
301 break;
302 case IMSG_ROUTESOCK:
303 if ((fd = imsg_get_fd(&imsg)) == -1)
304 fatalx("%s: expected to receive imsg "
305 "routesocket fd but didn't receive any",
306 __func__);
307 event_set(&ev_route, fd, EV_READ | EV_PERSIST,
308 route_receive, NULL);
309 break;
310 case IMSG_UUID:
311 if (IMSG_DATA_SIZE(imsg) != sizeof(duid.uuid))
312 fatalx("%s: IMSG_UUID wrong length: "
313 "%lu", __func__, IMSG_DATA_SIZE(imsg));
314 duid.type = htons(DUID_UUID_TYPE);
315 memcpy(duid.uuid, imsg.data, sizeof(duid.uuid));
316 break;
317 case IMSG_STARTUP:
318 frontend_startup();
319 break;
320 case IMSG_RECONF_CONF:
321 if (nconf != NULL)
322 fatalx("%s: IMSG_RECONF_CONF already in "
323 "progress", __func__);
324 if (IMSG_DATA_SIZE(imsg) !=
325 sizeof(struct dhcp6leased_conf))
326 fatalx("%s: IMSG_RECONF_CONF wrong length: %lu",
327 __func__, IMSG_DATA_SIZE(imsg));
328 if ((nconf = malloc(sizeof(struct dhcp6leased_conf))) ==
329 NULL)
330 fatal(NULL);
331 memcpy(nconf, imsg.data,
332 sizeof(struct dhcp6leased_conf));
333 SIMPLEQ_INIT(&nconf->iface_list);
334 break;
335 case IMSG_RECONF_IFACE:
336 if (IMSG_DATA_SIZE(imsg) != sizeof(struct
337 iface_conf))
338 fatalx("%s: IMSG_RECONF_IFACE wrong length: "
339 "%lu", __func__, IMSG_DATA_SIZE(imsg));
340 if ((iface_conf = malloc(sizeof(struct iface_conf)))
341 == NULL)
342 fatal(NULL);
343 memcpy(iface_conf, imsg.data, sizeof(struct
344 iface_conf));
345 SIMPLEQ_INIT(&iface_conf->iface_ia_list);
346 SIMPLEQ_INSERT_TAIL(&nconf->iface_list,
347 iface_conf, entry);
348 iface_conf->ia_count = 0;
349 break;
350 case IMSG_RECONF_IFACE_IA:
351 if (IMSG_DATA_SIZE(imsg) != sizeof(struct
352 iface_ia_conf))
353 fatalx("%s: IMSG_RECONF_IFACE_IA wrong "
354 "length: %lu", __func__,
355 IMSG_DATA_SIZE(imsg));
356 if ((iface_ia_conf =
357 malloc(sizeof(struct iface_ia_conf))) == NULL)
358 fatal(NULL);
359 memcpy(iface_ia_conf, imsg.data, sizeof(struct
360 iface_ia_conf));
361 SIMPLEQ_INIT(&iface_ia_conf->iface_pd_list);
362 SIMPLEQ_INSERT_TAIL(&iface_conf->iface_ia_list,
363 iface_ia_conf, entry);
364 iface_ia_conf->id = iface_conf->ia_count++;
365 if (iface_conf->ia_count > MAX_IA)
366 fatalx("Too many prefix delegation requests.");
367 break;
368 case IMSG_RECONF_IFACE_PD:
369 if (IMSG_DATA_SIZE(imsg) != sizeof(struct
370 iface_pd_conf))
371 fatalx("%s: IMSG_RECONF_IFACE_PD wrong length: "
372 "%lu", __func__, IMSG_DATA_SIZE(imsg));
373 if ((iface_pd_conf =
374 malloc(sizeof(struct iface_pd_conf))) == NULL)
375 fatal(NULL);
376 memcpy(iface_pd_conf, imsg.data, sizeof(struct
377 iface_pd_conf));
378 SIMPLEQ_INSERT_TAIL(&iface_ia_conf->iface_pd_list,
379 iface_pd_conf, entry);
380 break;
381 case IMSG_RECONF_IFACE_IA_END:
382 iface_ia_conf = NULL;
383 break;
384 case IMSG_RECONF_IFACE_END:
385 iface_conf = NULL;
386 break;
387 case IMSG_RECONF_END: {
388 int i;
389 int *ifaces;
390 char ifnamebuf[IF_NAMESIZE], *if_name;
391
392 if (nconf == NULL)
393 fatalx("%s: IMSG_RECONF_END without "
394 "IMSG_RECONF_CONF", __func__);
395
396 ifaces = changed_ifaces(frontend_conf, nconf);
397 merge_config(frontend_conf, nconf);
398 nconf = NULL;
399 for (i = 0; ifaces[i] != 0; i++) {
400 if_index = ifaces[i];
401 if_name = if_indextoname(if_index, ifnamebuf);
402 log_debug("changed iface: %s[%d]", if_name !=
403 NULL ? if_name : "<unknown>", if_index);
404 update_iface(if_index);
405 frontend_imsg_compose_engine(
406 IMSG_REQUEST_REBOOT, 0, 0, &if_index,
407 sizeof(if_index));
408 }
409 free(ifaces);
410 break;
411 }
412 case IMSG_CONTROLFD:
413 if ((fd = imsg_get_fd(&imsg)) == -1)
414 fatalx("%s: expected to receive imsg "
415 "control fd but didn't receive any",
416 __func__);
417 /* Listen on control socket. */
418 control_listen(fd);
419 break;
420 case IMSG_CTL_END:
421 control_imsg_relay(&imsg);
422 break;
423 default:
424 log_debug("%s: error handling imsg %d", __func__,
425 imsg.hdr.type);
426 break;
427 }
428 imsg_free(&imsg);
429 }
430 if (!shut)
431 imsg_event_add(iev);
432 else {
433 /* This pipe is dead. Remove its event handler. */
434 event_del(&iev->ev);
435 event_loopexit(NULL);
436 }
437 }
438
439 void
frontend_dispatch_engine(int fd,short event,void * bula)440 frontend_dispatch_engine(int fd, short event, void *bula)
441 {
442 struct imsgev *iev = bula;
443 struct imsgbuf *ibuf = &iev->ibuf;
444 struct imsg imsg;
445 struct iface *iface;
446 ssize_t n;
447 int shut = 0;
448
449 if (event & EV_READ) {
450 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
451 fatal("imsg_read error");
452 if (n == 0) /* Connection closed. */
453 shut = 1;
454 }
455 if (event & EV_WRITE) {
456 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
457 fatal("msgbuf_write");
458 if (n == 0) /* Connection closed. */
459 shut = 1;
460 }
461
462 for (;;) {
463 if ((n = imsg_get(ibuf, &imsg)) == -1)
464 fatal("%s: imsg_get error", __func__);
465 if (n == 0) /* No more messages. */
466 break;
467
468 switch (imsg.hdr.type) {
469 case IMSG_CTL_END:
470 case IMSG_CTL_SHOW_INTERFACE_INFO:
471 control_imsg_relay(&imsg);
472 break;
473 case IMSG_SEND_SOLICIT:
474 case IMSG_SEND_REQUEST:
475 case IMSG_SEND_RENEW:
476 case IMSG_SEND_REBIND: {
477 struct imsg_req_dhcp imsg_req_dhcp;
478 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_dhcp))
479 fatalx("%s: IMSG_SEND_DISCOVER wrong "
480 "length: %lu", __func__,
481 IMSG_DATA_SIZE(imsg));
482 memcpy(&imsg_req_dhcp, imsg.data,
483 sizeof(imsg_req_dhcp));
484
485 iface = get_iface_by_id(imsg_req_dhcp.if_index);
486
487 if (iface == NULL)
488 break;
489
490 iface_data_from_imsg(iface, &imsg_req_dhcp);
491 switch (imsg.hdr.type) {
492 case IMSG_SEND_SOLICIT:
493 send_packet(DHCPSOLICIT, iface);
494 break;
495 case IMSG_SEND_REQUEST:
496 send_packet(DHCPREQUEST, iface);
497 break;
498 case IMSG_SEND_RENEW:
499 send_packet(DHCPRENEW, iface);
500 break;
501 case IMSG_SEND_REBIND:
502 send_packet(DHCPREBIND, iface);
503 break;
504 }
505 break;
506 }
507 default:
508 log_debug("%s: error handling imsg %d", __func__,
509 imsg.hdr.type);
510 break;
511 }
512 imsg_free(&imsg);
513 }
514 if (!shut)
515 imsg_event_add(iev);
516 else {
517 /* This pipe is dead. Remove its event handler. */
518 event_del(&iev->ev);
519 event_loopexit(NULL);
520 }
521 }
522
523 int
get_flags(char * if_name)524 get_flags(char *if_name)
525 {
526 struct ifreq ifr;
527
528 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
529 if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
530 log_warn("SIOCGIFFLAGS");
531 return -1;
532 }
533 return ifr.ifr_flags;
534 }
535
536 void
update_iface(uint32_t if_index)537 update_iface(uint32_t if_index)
538 {
539 struct ifaddrs *ifap, *ifa;
540 struct iface *iface;
541 struct imsg_ifinfo ifinfo;
542 int flags;
543 char ifnamebuf[IF_NAMESIZE], *if_name;
544
545 if (getifaddrs(&ifap) != 0)
546 fatal("getifaddrs");
547
548 if ((if_name = if_indextoname(if_index, ifnamebuf)) == NULL)
549 return;
550
551 if ((flags = get_flags(if_name)) == -1)
552 return;
553
554 if (find_iface_conf(&frontend_conf->iface_list, if_name) == NULL)
555 return;
556
557 memset(&ifinfo, 0, sizeof(ifinfo));
558 ifinfo.if_index = if_index;
559 ifinfo.link_state = -1;
560 ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) ==
561 (IFF_UP | IFF_RUNNING);
562
563 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
564 if (strcmp(if_name, ifa->ifa_name) != 0)
565 continue;
566 if (ifa->ifa_addr == NULL)
567 continue;
568
569 switch (ifa->ifa_addr->sa_family) {
570 case AF_LINK: {
571 struct if_data *if_data;
572
573 if_data = (struct if_data *)ifa->ifa_data;
574 ifinfo.link_state = if_data->ifi_link_state;
575 ifinfo.rdomain = if_data->ifi_rdomain;
576 goto out;
577 }
578 default:
579 break;
580 }
581 }
582 out:
583 freeifaddrs(ifap);
584 iface = get_iface_by_id(if_index);
585 if (iface == NULL) {
586 if ((iface = calloc(1, sizeof(*iface))) == NULL)
587 fatal("calloc");
588 memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo));
589 LIST_INSERT_HEAD(&interfaces, iface, entries);
590 frontend_imsg_compose_main(IMSG_OPEN_UDPSOCK, 0,
591 &if_index, sizeof(if_index));
592 } else
593 /* XXX check rdomain changed ?*/
594 memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo));
595
596 frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &iface->ifinfo,
597 sizeof(iface->ifinfo));
598 }
599
600 void
frontend_startup(void)601 frontend_startup(void)
602 {
603 if (!event_initialized(&ev_route))
604 fatalx("%s: did not receive a route socket from the main "
605 "process", __func__);
606
607 event_add(&ev_route, NULL);
608 }
609
610 void
route_receive(int fd,short events,void * arg)611 route_receive(int fd, short events, void *arg)
612 {
613 static uint8_t *buf;
614
615 struct rt_msghdr *rtm;
616 struct sockaddr *sa, *rti_info[RTAX_MAX];
617 ssize_t n;
618
619 if (buf == NULL) {
620 buf = malloc(ROUTE_SOCKET_BUF_SIZE);
621 if (buf == NULL)
622 fatal("malloc");
623 }
624 rtm = (struct rt_msghdr *)buf;
625 if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) {
626 if (errno == EAGAIN || errno == EINTR)
627 return;
628 log_warn("dispatch_rtmsg: read error");
629 return;
630 }
631
632 if (n == 0)
633 fatal("routing socket closed");
634
635 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
636 log_warnx("partial rtm of %zd in buffer", n);
637 return;
638 }
639
640 if (rtm->rtm_version != RTM_VERSION)
641 return;
642
643 sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
644 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
645
646 handle_route_message(rtm, rti_info);
647 }
648
649 void
handle_route_message(struct rt_msghdr * rtm,struct sockaddr ** rti_info)650 handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
651 {
652 struct if_announcemsghdr *ifan;
653 uint32_t if_index;
654
655 switch (rtm->rtm_type) {
656 case RTM_IFINFO:
657 if_index = ((struct if_msghdr *)rtm)->ifm_index;
658 update_iface(if_index);
659 break;
660 case RTM_IFANNOUNCE:
661 ifan = (struct if_announcemsghdr *)rtm;
662 if_index = ifan->ifan_index;
663 if (ifan->ifan_what == IFAN_DEPARTURE) {
664 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
665 &if_index, sizeof(if_index));
666 remove_iface(if_index);
667 }
668 break;
669 default:
670 log_debug("unexpected RTM: %d", rtm->rtm_type);
671 break;
672 }
673 }
674
675 #define ROUNDUP(a) \
676 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
677
678 void
get_rtaddrs(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)679 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
680 {
681 int i;
682
683 for (i = 0; i < RTAX_MAX; i++) {
684 if (addrs & (1 << i)) {
685 rti_info[i] = sa;
686 sa = (struct sockaddr *)((char *)(sa) +
687 ROUNDUP(sa->sa_len));
688 } else
689 rti_info[i] = NULL;
690 }
691 }
692
693 void
udp_receive(int fd,short events,void * arg)694 udp_receive(int fd, short events, void *arg)
695 {
696 struct imsg_dhcp imsg_dhcp;
697 struct iface *iface;
698 ssize_t len;
699
700 iface = (struct iface *)arg;
701 memset(&imsg_dhcp, 0, sizeof(imsg_dhcp));
702
703 if ((len = read(fd, imsg_dhcp.packet, 1500)) == -1) {
704 log_warn("%s: read", __func__);
705 return;
706 }
707
708 if (len == 0)
709 fatal("%s len == 0", __func__);
710
711 imsg_dhcp.if_index = iface->ifinfo.if_index;
712 imsg_dhcp.len = len;
713 frontend_imsg_compose_engine(IMSG_DHCP, 0, 0, &imsg_dhcp,
714 sizeof(imsg_dhcp));
715 }
716
717 void
iface_data_from_imsg(struct iface * iface,struct imsg_req_dhcp * imsg)718 iface_data_from_imsg(struct iface* iface, struct imsg_req_dhcp *imsg)
719 {
720 memcpy(iface->xid, imsg->xid, sizeof(iface->xid));
721 iface->elapsed_time = imsg->elapsed_time;
722 iface->serverid_len = imsg->serverid_len;
723 memcpy(iface->serverid, imsg->serverid, SERVERID_SIZE);
724 memcpy(iface->pds, imsg->pds, sizeof(iface->pds));
725 }
726
727 ssize_t
build_packet(uint8_t message_type,struct iface * iface,char * if_name)728 build_packet(uint8_t message_type, struct iface *iface, char *if_name)
729 {
730 struct iface_conf *iface_conf;
731 struct iface_ia_conf *ia_conf;
732 struct dhcp_hdr hdr;
733 struct dhcp_option_hdr opt_hdr;
734 struct dhcp_iapd iapd;
735 struct dhcp_iaprefix iaprefix;
736 struct dhcp_vendor_class vendor_class;
737 size_t i;
738 ssize_t len;
739 uint16_t request_option_code, elapsed_time;
740 const uint16_t options[] = {DHO_SOL_MAX_RT,
741 DHO_INF_MAX_RT};
742 uint8_t *p;
743
744 switch (message_type) {
745 case DHCPSOLICIT:
746 case DHCPREQUEST:
747 case DHCPRENEW:
748 case DHCPREBIND:
749 break;
750 default:
751 fatalx("%s: %s not implemented", __func__,
752 dhcp_message_type2str(message_type));
753 }
754
755 iface_conf = find_iface_conf(&frontend_conf->iface_list, if_name);
756
757 memset(dhcp_packet, 0, sizeof(dhcp_packet));
758
759 p = dhcp_packet;
760 hdr.msg_type = message_type;
761 memcpy(hdr.xid, iface->xid, sizeof(hdr.xid));
762 memcpy(p, &hdr, sizeof(struct dhcp_hdr));
763 p += sizeof(struct dhcp_hdr);
764
765 opt_hdr.code = htons(DHO_CLIENTID);
766 opt_hdr.len = htons(sizeof(struct dhcp_duid));
767 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
768 p += sizeof(struct dhcp_option_hdr);
769 memcpy(p, &duid, sizeof(struct dhcp_duid));
770 p += sizeof(struct dhcp_duid);
771
772 switch (message_type) {
773 case DHCPSOLICIT:
774 case DHCPREBIND:
775 break;
776 case DHCPREQUEST:
777 case DHCPRENEW:
778 opt_hdr.code = htons(DHO_SERVERID);
779 opt_hdr.len = htons(iface->serverid_len);
780 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
781 p += sizeof(struct dhcp_option_hdr);
782 memcpy(p, iface->serverid, iface->serverid_len);
783 p += iface->serverid_len;
784 break;
785 default:
786 fatalx("%s: %s not implemented", __func__,
787 dhcp_message_type2str(message_type));
788 }
789 SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) {
790 struct prefix *pd;
791
792 opt_hdr.code = htons(DHO_IA_PD);
793 opt_hdr.len = htons(sizeof(struct dhcp_iapd) +
794 sizeof(struct dhcp_option_hdr) +
795 sizeof(struct dhcp_iaprefix));
796 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
797 p += sizeof(struct dhcp_option_hdr);
798 iapd.iaid = htonl(ia_conf->id);
799 iapd.t1 = 0;
800 iapd.t2 = 0;
801 memcpy(p, &iapd, sizeof(struct dhcp_iapd));
802 p += sizeof(struct dhcp_iapd);
803
804 opt_hdr.code = htons(DHO_IA_PREFIX);
805 opt_hdr.len = htons(sizeof(struct dhcp_iaprefix));
806 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
807 p += sizeof(struct dhcp_option_hdr);
808
809 memset(&iaprefix, 0, sizeof(struct dhcp_iaprefix));
810
811 switch (message_type) {
812 case DHCPSOLICIT:
813 iaprefix.prefix_len = ia_conf->prefix_len;
814 break;
815 case DHCPREQUEST:
816 case DHCPRENEW:
817 case DHCPREBIND:
818 pd = &iface->pds[ia_conf->id];
819 if (pd->prefix_len > 0) {
820 iaprefix.prefix_len = pd->prefix_len;
821 memcpy(&iaprefix.prefix, &pd->prefix,
822 sizeof(struct in6_addr));
823 } else
824 iaprefix.prefix_len = ia_conf->prefix_len;
825 break;
826 default:
827 fatalx("%s: %s not implemented", __func__,
828 dhcp_message_type2str(message_type));
829 }
830 memcpy(p, &iaprefix, sizeof(struct dhcp_iaprefix));
831 p += sizeof(struct dhcp_iaprefix);
832 }
833
834 opt_hdr.code = htons(DHO_ORO);
835 opt_hdr.len = htons(sizeof(request_option_code) * nitems(options));
836 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
837 p += sizeof(struct dhcp_option_hdr);
838 for (i = 0; i < nitems(options); i++) {
839 request_option_code = htons(options[i]);
840 memcpy(p, &request_option_code, sizeof(uint16_t));
841 p += sizeof(uint16_t);
842 }
843
844 opt_hdr.code = htons(DHO_ELAPSED_TIME);
845 opt_hdr.len = htons(2);
846 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
847 p += sizeof(struct dhcp_option_hdr);
848 elapsed_time = htons(iface->elapsed_time);
849 memcpy(p, &elapsed_time, sizeof(uint16_t));
850 p += sizeof(uint16_t);
851
852 if (message_type == DHCPSOLICIT && frontend_conf->rapid_commit) {
853 opt_hdr.code = htons(DHO_RAPID_COMMIT);
854 opt_hdr.len = htons(0);
855 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
856 p += sizeof(struct dhcp_option_hdr);
857 }
858
859 opt_hdr.code = htons(DHO_VENDOR_CLASS);
860 opt_hdr.len = htons(sizeof(struct dhcp_vendor_class) +
861 vendor_class_len);
862 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
863 p += sizeof(struct dhcp_option_hdr);
864 vendor_class.enterprise_number = htonl(OPENBSD_ENTERPRISENO);
865 vendor_class.vendor_class_len = htons(vendor_class_len);
866 memcpy(p, &vendor_class, sizeof(struct dhcp_vendor_class));
867 p += sizeof(struct dhcp_vendor_class);
868 /* Not a C-string, leave out \0 */
869 memcpy(p, vendor_class_data, vendor_class_len);
870 p += vendor_class_len;
871
872 len = p - dhcp_packet;
873 return (len);
874 }
875
876 void
send_packet(uint8_t message_type,struct iface * iface)877 send_packet(uint8_t message_type, struct iface *iface)
878 {
879 ssize_t pkt_len;
880 char ifnamebuf[IF_NAMESIZE], *if_name, *message_name;
881
882 if (!event_initialized(&iface->udpev)) {
883 iface->send_solicit = 1;
884 return;
885 }
886
887 iface->send_solicit = 0;
888
889 if ((if_name = if_indextoname(iface->ifinfo.if_index, ifnamebuf))
890 == NULL)
891 return; /* iface went away, nothing to do */
892
893 switch (message_type) {
894 case DHCPSOLICIT:
895 message_name = "Soliciting";
896 break;
897 case DHCPREQUEST:
898 message_name = "Requesting";
899 break;
900 case DHCPRENEW:
901 message_name = "Renewing";
902 break;
903 case DHCPREBIND:
904 message_name = "Rebinding";
905 break;
906 default:
907 message_name = NULL;
908 break;
909 }
910
911 if (message_name)
912 log_info("%s lease on %s", message_name, if_name);
913
914 pkt_len = build_packet(message_type, iface, if_name);
915
916 dst.sin6_scope_id = iface->ifinfo.if_index;
917
918 if (sendto(EVENT_FD(&iface->udpev), dhcp_packet, pkt_len, 0,
919 (struct sockaddr *)&dst, sizeof(dst)) == -1)
920 log_warn("sendto");
921 }
922
923 struct iface*
get_iface_by_id(uint32_t if_index)924 get_iface_by_id(uint32_t if_index)
925 {
926 struct iface *iface;
927
928 LIST_FOREACH (iface, &interfaces, entries) {
929 if (iface->ifinfo.if_index == if_index)
930 return (iface);
931 }
932
933 return (NULL);
934 }
935
936 struct iface*
get_iface_by_name(const char * if_name)937 get_iface_by_name(const char *if_name)
938 {
939 uint32_t ifidx = if_nametoindex(if_name);
940
941 if (ifidx == 0)
942 return (NULL);
943 return get_iface_by_id(ifidx);
944 }
945
946 void
remove_iface(uint32_t if_index)947 remove_iface(uint32_t if_index)
948 {
949 struct iface *iface;
950
951 iface = get_iface_by_id(if_index);
952
953 if (iface == NULL)
954 return;
955
956 LIST_REMOVE(iface, entries);
957 if (event_initialized(&iface->udpev)) {
958 event_del(&iface->udpev);
959 close(EVENT_FD(&iface->udpev));
960 }
961 free(iface);
962 }
963
964 void
set_udpsock(int udpsock,uint32_t if_index)965 set_udpsock(int udpsock, uint32_t if_index)
966 {
967 struct iface *iface;
968
969 iface = get_iface_by_id(if_index);
970
971 if (iface == NULL) {
972 /*
973 * The interface disappeared while we were waiting for the
974 * parent process to open the udp socket.
975 */
976 close(udpsock);
977 } else if (event_initialized(&iface->udpev)) {
978 /*
979 * XXX
980 * The autoconf flag is flapping and we have multiple udp
981 * sockets in flight. We don't need this one because we already
982 * got one.
983 */
984 close(udpsock);
985 } else {
986 event_set(&iface->udpev, udpsock, EV_READ |
987 EV_PERSIST, udp_receive, iface);
988 event_add(&iface->udpev, NULL);
989 if (iface->send_solicit)
990 send_packet(DHCPSOLICIT, iface);
991 }
992 }
993
994 struct iface_conf*
find_iface_conf(struct iface_conf_head * head,char * if_name)995 find_iface_conf(struct iface_conf_head *head, char *if_name)
996 {
997 struct iface_conf *iface_conf;
998
999 if (if_name == NULL)
1000 return (NULL);
1001
1002 SIMPLEQ_FOREACH(iface_conf, head, entry) {
1003 if (strcmp(iface_conf->name, if_name) == 0)
1004 return iface_conf;
1005 }
1006 return (NULL);
1007 }
1008
1009 int*
changed_ifaces(struct dhcp6leased_conf * oconf,struct dhcp6leased_conf * nconf)1010 changed_ifaces(struct dhcp6leased_conf *oconf, struct dhcp6leased_conf *nconf)
1011 {
1012 struct iface_conf *iface_conf, *oiface_conf;
1013 int *ret, if_index, count = 0, i = 0;
1014
1015 /*
1016 * Worst case: All old interfaces replaced with new interfaces.
1017 * This should still be a small number
1018 */
1019 SIMPLEQ_FOREACH(iface_conf, &oconf->iface_list, entry)
1020 count++;
1021 SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry)
1022 count++;
1023
1024 ret = calloc(count + 1, sizeof(int));
1025
1026 SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry) {
1027 if ((if_index = if_nametoindex(iface_conf->name)) == 0)
1028 continue;
1029 oiface_conf = find_iface_conf(&oconf->iface_list,
1030 iface_conf->name);
1031 if (oiface_conf == NULL) {
1032 /* new interface added to config */
1033 ret[i++] = if_index;
1034 } else if (iface_conf_cmp(iface_conf, oiface_conf) != 0) {
1035 /* interface conf changed */
1036 ret[i++] = if_index;
1037 }
1038 }
1039 SIMPLEQ_FOREACH(oiface_conf, &oconf->iface_list, entry) {
1040 if ((if_index = if_nametoindex(oiface_conf->name)) == 0)
1041 continue;
1042 if (find_iface_conf(&nconf->iface_list, oiface_conf->name) ==
1043 NULL) {
1044 /* interface removed from config */
1045 ret[i++] = if_index;
1046 }
1047 }
1048 return ret;
1049 }
1050
1051 int
iface_conf_cmp(struct iface_conf * a,struct iface_conf * b)1052 iface_conf_cmp(struct iface_conf *a, struct iface_conf *b)
1053 {
1054 return 0;
1055 }
1056