1 /* $OpenBSD: interface.c,v 1.13 2024/08/21 09:18:47 florian Exp $ */
2
3 /*
4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #include <sys/time.h>
23 #include <sys/socket.h>
24
25 #include <netinet/in.h>
26 #include <netinet/ip_mroute.h>
27 #include <arpa/inet.h>
28 #include <net/if.h>
29 #include <net/if_types.h>
30
31 #include <ctype.h>
32 #include <err.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <event.h>
38
39 #include "igmp.h"
40 #include "dvmrpd.h"
41 #include "dvmrp.h"
42 #include "log.h"
43 #include "dvmrpe.h"
44
45 extern struct dvmrpd_conf *conf;
46
47 void if_probe_timer(int, short, void *);
48 int if_start_probe_timer(struct iface *);
49 int if_stop_probe_timer(struct iface *);
50 void if_query_timer(int, short, void *);
51 int if_start_query_timer(struct iface *);
52 int if_stop_query_timer(struct iface *);
53 void if_querier_present_timer(int, short, void *);
54 int if_start_querier_present_timer(struct iface *);
55 int if_stop_querier_present_timer(struct iface *);
56 int if_reset_querier_present_timer(struct iface *);
57 int if_act_start(struct iface *);
58 int if_act_query_seen(struct iface *);
59 int if_act_reset(struct iface *);
60
61 struct {
62 int state;
63 enum iface_event event;
64 enum iface_action action;
65 int new_state;
66 } iface_fsm[] = {
67 /* current state event that happened action to take resulting state */
68 {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0},
69 {IF_STA_ACTIVE, IF_EVT_QRECVD, IF_ACT_QPRSNT, 0},
70 {IF_STA_NONQUERIER, IF_EVT_QPRSNTTMOUT, IF_ACT_STRT, 0},
71 {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN},
72 {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0},
73 };
74
75 const char * const if_action_names[] = {
76 "NOTHING",
77 "START",
78 "QPRSNT",
79 "RESET"
80 };
81
82 static const char * const if_event_names[] = {
83 "NOTHING",
84 "UP",
85 "QTMOUT",
86 "QRECVD",
87 "QPRSNTTMOUT",
88 "DOWN"
89 };
90
91 int
if_fsm(struct iface * iface,enum iface_event event)92 if_fsm(struct iface *iface, enum iface_event event)
93 {
94 int old_state;
95 int new_state = 0;
96 int i, ret = 0;
97
98 old_state = iface->state;
99
100 for (i = 0; iface_fsm[i].state != -1; i++)
101 if ((iface_fsm[i].state & old_state) &&
102 (iface_fsm[i].event == event)) {
103 new_state = iface_fsm[i].new_state;
104 break;
105 }
106
107 if (iface_fsm[i].state == -1) {
108 /* XXX event outside of the defined fsm, ignore it. */
109 log_debug("fsm_if: interface %s, "
110 "event '%s' not expected in state '%s'", iface->name,
111 if_event_name(event), if_state_name(old_state));
112 return (0);
113 }
114
115 switch (iface_fsm[i].action) {
116 case IF_ACT_STRT:
117 ret = if_act_start(iface);
118 break;
119 case IF_ACT_QPRSNT:
120 ret = if_act_query_seen(iface);
121 break;
122 case IF_ACT_RST:
123 ret = if_act_reset(iface);
124 break;
125 case IF_ACT_NOTHING:
126 /* do nothing */
127 break;
128 }
129
130 if (ret) {
131 log_debug("fsm_if: error changing state for interface %s, "
132 "event '%s', state '%s'", iface->name, if_event_name(event),
133 if_state_name(old_state));
134 return (-1);
135 }
136
137 if (new_state != 0)
138 iface->state = new_state;
139
140 log_debug("fsm_if: event '%s' resulted in action '%s' and changing "
141 "state for interface %s from '%s' to '%s'",
142 if_event_name(event), if_action_name(iface_fsm[i].action),
143 iface->name, if_state_name(old_state), if_state_name(iface->state));
144
145 return (ret);
146 }
147
148 struct iface *
if_find_index(u_short ifindex)149 if_find_index(u_short ifindex)
150 {
151 struct iface *iface;
152
153 LIST_FOREACH(iface, &conf->iface_list, entry) {
154 if (iface->ifindex == ifindex)
155 return (iface);
156 }
157
158 return (NULL);
159 }
160
161 struct iface *
if_new(struct kif * kif)162 if_new(struct kif *kif)
163 {
164 struct sockaddr_in *sain;
165 struct iface *iface;
166 struct ifreq *ifr;
167 int s;
168
169 if ((iface = calloc(1, sizeof(*iface))) == NULL)
170 err(1, "if_new: calloc");
171
172 iface->state = IF_STA_DOWN;
173 iface->passive = 1;
174
175 LIST_INIT(&iface->nbr_list);
176 TAILQ_INIT(&iface->group_list);
177 TAILQ_INIT(&iface->rde_group_list);
178 strlcpy(iface->name, kif->ifname, sizeof(iface->name));
179
180 if ((ifr = calloc(1, sizeof(*ifr))) == NULL)
181 err(1, "if_new: calloc");
182
183 /* set up ifreq */
184 strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name));
185 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
186 err(1, "if_new: socket");
187
188 /* get type */
189 if ((kif->flags & IFF_POINTOPOINT))
190 iface->type = IF_TYPE_POINTOPOINT;
191 if ((kif->flags & IFF_BROADCAST) &&
192 (kif->flags & IFF_MULTICAST))
193 iface->type = IF_TYPE_BROADCAST;
194
195 /* get mtu, index and flags */
196 iface->mtu = kif->mtu;
197 iface->ifindex = kif->ifindex;
198 iface->flags = kif->flags;
199 iface->linkstate = kif->link_state;
200 iface->if_type = kif->if_type;
201 iface->baudrate = kif->baudrate;
202
203 /* get address */
204 if (ioctl(s, SIOCGIFADDR, (caddr_t)ifr) == -1)
205 err(1, "if_new: cannot get address");
206 sain = (struct sockaddr_in *) &ifr->ifr_addr;
207 iface->addr = sain->sin_addr;
208
209 /* get mask */
210 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)ifr) == -1)
211 err(1, "if_new: cannot get mask");
212 sain = (struct sockaddr_in *) &ifr->ifr_addr;
213 iface->mask = sain->sin_addr;
214
215 /* get p2p dst address */
216 if (iface->type == IF_TYPE_POINTOPOINT) {
217 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)ifr) == -1)
218 err(1, "if_new: cannot get dst addr");
219 sain = (struct sockaddr_in *) &ifr->ifr_addr;
220 iface->dst = sain->sin_addr;
221 }
222
223 free(ifr);
224 close(s);
225
226 return (iface);
227 }
228
229 void
if_init(struct dvmrpd_conf * xconf,struct iface * iface)230 if_init(struct dvmrpd_conf *xconf, struct iface *iface)
231 {
232 /* set event handlers for interface */
233 evtimer_set(&iface->probe_timer, if_probe_timer, iface);
234 evtimer_set(&iface->query_timer, if_query_timer, iface);
235 evtimer_set(&iface->querier_present_timer, if_querier_present_timer,
236 iface);
237
238 TAILQ_INIT(&iface->rr_list);
239
240 iface->fd = xconf->dvmrp_socket;
241 iface->gen_id = xconf->gen_id;
242 }
243
244 int
if_del(struct iface * iface)245 if_del(struct iface *iface)
246 {
247 struct nbr *nbr = NULL;
248
249 /* clear lists etc */
250 while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) {
251 LIST_REMOVE(nbr, entry);
252 nbr_del(nbr);
253 }
254 group_list_clr(iface);
255
256 return (-1);
257 }
258
259 int
if_nbr_list_empty(struct iface * iface)260 if_nbr_list_empty(struct iface *iface)
261 {
262 return (LIST_EMPTY(&iface->nbr_list));
263 }
264
265 /* timers */
266 void
if_probe_timer(int fd,short event,void * arg)267 if_probe_timer(int fd, short event, void *arg)
268 {
269 struct iface *iface = arg;
270 struct timeval tv;
271
272 send_probe(iface);
273
274 /* reschedule probe_timer */
275 if (!iface->passive) {
276 timerclear(&tv);
277 tv.tv_sec = iface->probe_interval;
278 evtimer_add(&iface->probe_timer, &tv);
279 }
280 }
281
282 int
if_start_probe_timer(struct iface * iface)283 if_start_probe_timer(struct iface *iface)
284 {
285 struct timeval tv;
286
287 timerclear(&tv);
288 return (evtimer_add(&iface->probe_timer, &tv));
289 }
290
291 int
if_stop_probe_timer(struct iface * iface)292 if_stop_probe_timer(struct iface *iface)
293 {
294 return (evtimer_del(&iface->probe_timer));
295 }
296
297 void
if_query_timer(int fd,short event,void * arg)298 if_query_timer(int fd, short event, void *arg)
299 {
300 struct iface *iface = arg;
301 struct timeval tv;
302
303 /* send a general query */
304 send_igmp_query(iface, NULL);
305
306 /* reschedule query_timer */
307 if (!iface->passive) {
308 timerclear(&tv);
309 if (iface->startup_query_counter != 0) {
310 tv.tv_sec = iface->startup_query_interval;
311 iface->startup_query_counter--;
312 } else
313 tv.tv_sec = iface->query_interval;
314
315 evtimer_add(&iface->query_timer, &tv);
316 }
317 }
318
319 int
if_start_query_timer(struct iface * iface)320 if_start_query_timer(struct iface *iface)
321 {
322 struct timeval tv;
323
324 timerclear(&tv);
325 return (evtimer_add(&iface->query_timer, &tv));
326 }
327
328 int
if_stop_query_timer(struct iface * iface)329 if_stop_query_timer(struct iface *iface)
330 {
331 return (evtimer_del(&iface->query_timer));
332 }
333
334 void
if_querier_present_timer(int fd,short event,void * arg)335 if_querier_present_timer(int fd, short event, void *arg)
336 {
337 struct iface *iface = arg;
338
339 if_fsm(iface, IF_EVT_QPRSNTTMOUT);
340 }
341
342 int
if_start_querier_present_timer(struct iface * iface)343 if_start_querier_present_timer(struct iface *iface)
344 {
345 struct timeval tv;
346
347 /* Other Querier Present Interval */
348 timerclear(&tv);
349 tv.tv_sec = iface->robustness * iface->query_interval +
350 (iface->query_resp_interval / 2);
351
352 return (evtimer_add(&iface->querier_present_timer, &tv));
353 }
354
355 int
if_stop_querier_present_timer(struct iface * iface)356 if_stop_querier_present_timer(struct iface *iface)
357 {
358 return (evtimer_del(&iface->querier_present_timer));
359 }
360
361 int
if_reset_querier_present_timer(struct iface * iface)362 if_reset_querier_present_timer(struct iface *iface)
363 {
364 struct timeval tv;
365
366 /* Other Querier Present Interval */
367 timerclear(&tv);
368 tv.tv_sec = iface->robustness * iface->query_interval +
369 (iface->query_resp_interval / 2);
370
371 return (evtimer_add(&iface->querier_present_timer, &tv));
372 }
373
374 /* actions */
375 int
if_act_start(struct iface * iface)376 if_act_start(struct iface *iface)
377 {
378 struct in_addr addr;
379 struct timeval now;
380
381 if (iface->passive) {
382 log_debug("if_act_start: cannot start passive interface %s",
383 iface->name);
384 return (-1);
385 }
386
387 if (!((iface->flags & IFF_UP) && LINK_STATE_IS_UP(iface->linkstate))) {
388 log_debug("if_act_start: interface %s link down",
389 iface->name);
390 return (0);
391 }
392
393 gettimeofday(&now, NULL);
394 iface->uptime = now.tv_sec;
395
396 switch (iface->type) {
397 case IF_TYPE_POINTOPOINT:
398 case IF_TYPE_BROADCAST:
399 inet_pton(AF_INET, AllSystems, &addr);
400 if (if_join_group(iface, &addr)) {
401 log_warnx("if_act_start: error joining group %s, "
402 "interface %s", inet_ntoa(addr), iface->name);
403 return (-1);
404 }
405 inet_pton(AF_INET, AllRouters, &addr);
406 if (if_join_group(iface, &addr)) {
407 log_warnx("if_act_start: error joining group %s, "
408 "interface %s", inet_ntoa(addr), iface->name);
409 return (-1);
410 }
411 inet_pton(AF_INET, AllDVMRPRouters, &addr);
412 if (if_join_group(iface, &addr)) {
413 log_warnx("if_act_start: error joining group %s, "
414 "interface %s", inet_ntoa(addr), iface->name);
415 return (-1);
416 }
417
418 iface->state = IF_STA_QUERIER;
419 if_start_query_timer(iface);
420 if_start_probe_timer(iface);
421 iface->startup_query_counter = iface->startup_query_cnt;
422 break;
423 default:
424 fatalx("if_act_start: unknown type");
425 }
426
427 return (0);
428 }
429
430 int
if_act_query_seen(struct iface * iface)431 if_act_query_seen(struct iface *iface)
432 {
433 log_debug("if_act_query_seen: interface %s", iface->name);
434
435 switch (iface->type) {
436 case IF_TYPE_POINTOPOINT:
437 case IF_TYPE_BROADCAST:
438 iface->state = IF_STA_NONQUERIER;
439 if_stop_query_timer(iface);
440 if_reset_querier_present_timer(iface);
441 break;
442 default:
443 fatalx("if_act_querier_seen: unknown type");
444 }
445
446 return (0);
447 }
448
449 int
if_act_reset(struct iface * iface)450 if_act_reset(struct iface *iface)
451 {
452 struct in_addr addr;
453 struct nbr *nbr;
454
455 switch (iface->type) {
456 case IF_TYPE_POINTOPOINT:
457 case IF_TYPE_BROADCAST:
458 inet_pton(AF_INET, AllSystems, &addr);
459 if (if_leave_group(iface, &addr)) {
460 log_warnx("if_act_reset: error leaving group %s, "
461 "interface %s", inet_ntoa(addr), iface->name);
462 return (-1);
463 }
464 inet_pton(AF_INET, AllRouters, &addr);
465 if (if_leave_group(iface, &addr)) {
466 log_warnx("if_act_reset: error leaving group %s, "
467 "interface %s", inet_ntoa(addr), iface->name);
468 return (-1);
469 }
470 inet_pton(AF_INET, AllDVMRPRouters, &addr);
471 if (if_leave_group(iface, &addr)) {
472 log_warnx("if_act_reset: error leaving group %s, "
473 "interface %s", inet_ntoa(addr), iface->name);
474 return (-1);
475 }
476
477 iface->state = IF_STA_DOWN;
478 iface->gen_id++;
479 if_stop_query_timer(iface);
480 if_stop_querier_present_timer(iface);
481 /* XXX clear nbr list? */
482 break;
483 default:
484 fatalx("if_act_reset: unknown type");
485 }
486
487 LIST_FOREACH(nbr, &iface->nbr_list, entry) {
488 if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) {
489 log_debug("if_act_reset: error killing neighbor %s",
490 inet_ntoa(nbr->id));
491 }
492 }
493
494 group_list_clr(iface); /* XXX clear group list? */
495
496 return (0);
497 }
498
499 const char *
if_event_name(int event)500 if_event_name(int event)
501 {
502 return (if_event_names[event]);
503 }
504
505 const char *
if_action_name(int action)506 if_action_name(int action)
507 {
508 return (if_action_names[action]);
509 }
510
511 /* misc */
512 int
if_set_mcast_ttl(int fd,u_int8_t ttl)513 if_set_mcast_ttl(int fd, u_int8_t ttl)
514 {
515 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
516 (char *)&ttl, sizeof(ttl)) == -1) {
517 log_warn("if_set_mcast_ttl: error setting "
518 "IP_MULTICAST_TTL to %d", ttl);
519 return (-1);
520 }
521
522 return (0);
523 }
524
525 int
if_set_tos(int fd,int tos)526 if_set_tos(int fd, int tos)
527 {
528 if (setsockopt(fd, IPPROTO_IP, IP_TOS,
529 (int *)&tos, sizeof(tos)) == -1) {
530 log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos);
531 return (-1);
532 }
533
534 return (0);
535 }
536
537 void
if_set_recvbuf(int fd)538 if_set_recvbuf(int fd)
539 {
540 int bsize;
541
542 bsize = 65535;
543 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
544 sizeof(bsize)) == -1)
545 bsize /= 2;
546 }
547
548 int
if_join_group(struct iface * iface,struct in_addr * addr)549 if_join_group(struct iface *iface, struct in_addr *addr)
550 {
551 struct ip_mreq mreq;
552
553 switch (iface->type) {
554 case IF_TYPE_POINTOPOINT:
555 case IF_TYPE_BROADCAST:
556 mreq.imr_multiaddr.s_addr = addr->s_addr;
557 mreq.imr_interface.s_addr = iface->addr.s_addr;
558
559 if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
560 (void *)&mreq, sizeof(mreq)) == -1) {
561 log_debug("if_join_group: error IP_ADD_MEMBERSHIP, "
562 "interface %s", iface->name);
563 return (-1);
564 }
565 break;
566 default:
567 fatalx("if_join_group: unknown interface type");
568 }
569
570 return (0);
571 }
572
573 int
if_leave_group(struct iface * iface,struct in_addr * addr)574 if_leave_group(struct iface *iface, struct in_addr *addr)
575 {
576 struct ip_mreq mreq;
577
578 switch (iface->type) {
579 case IF_TYPE_POINTOPOINT:
580 case IF_TYPE_BROADCAST:
581 mreq.imr_multiaddr.s_addr = addr->s_addr;
582 mreq.imr_interface.s_addr = iface->addr.s_addr;
583
584 if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
585 (void *)&mreq, sizeof(mreq)) == -1) {
586 log_debug("if_leave_group: error IP_DROP_MEMBERSHIP, "
587 "interface %s", iface->name);
588 return (-1);
589 }
590 break;
591 default:
592 fatalx("if_leave_group: unknown interface type");
593 }
594
595 return (0);
596 }
597
598 int
if_set_mcast(struct iface * iface)599 if_set_mcast(struct iface *iface)
600 {
601 switch (iface->type) {
602 case IF_TYPE_POINTOPOINT:
603 case IF_TYPE_BROADCAST:
604 if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF,
605 (char *)&iface->addr.s_addr,
606 sizeof(iface->addr.s_addr)) == -1) {
607 log_debug("if_set_mcast: error setting "
608 "IP_MULTICAST_IF, interface %s", iface->name);
609 return (-1);
610 }
611 break;
612 default:
613 fatalx("if_set_mcast: unknown interface type");
614 }
615
616 return (0);
617 }
618
619 int
if_set_mcast_loop(int fd)620 if_set_mcast_loop(int fd)
621 {
622 u_int8_t loop = 0;
623
624 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
625 (char *)&loop, sizeof(loop)) == -1) {
626 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP");
627 return (-1);
628 }
629
630 return (0);
631 }
632
633 struct ctl_iface *
if_to_ctl(struct iface * iface)634 if_to_ctl(struct iface *iface)
635 {
636 static struct ctl_iface ictl;
637 struct timeval tv, now, res;
638
639 memcpy(ictl.name, iface->name, sizeof(ictl.name));
640 memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr));
641 memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask));
642 memcpy(&ictl.querier, &iface->querier, sizeof(ictl.querier));
643
644 ictl.ifindex = iface->ifindex;
645 ictl.state = iface->state;
646 ictl.mtu = iface->mtu;
647 ictl.nbr_cnt = iface->nbr_cnt;
648 ictl.adj_cnt = iface->adj_cnt;
649
650 ictl.gen_id = iface->gen_id;
651 ictl.group_cnt = iface->group_cnt;
652 ictl.probe_interval = iface->probe_interval;
653 ictl.query_interval = iface->query_interval;
654 ictl.query_resp_interval = iface->query_resp_interval;
655 ictl.recv_query_resp_interval = iface->recv_query_resp_interval;
656 ictl.group_member_interval = iface->group_member_interval;
657 ictl.querier_present_interval = iface->querier_present_interval;
658 ictl.startup_query_interval = iface->startup_query_interval;
659 ictl.startup_query_cnt = iface->startup_query_cnt;
660 ictl.last_member_query_interval = iface->last_member_query_interval;
661 ictl.last_member_query_cnt = iface->last_member_query_cnt;
662 ictl.last_member_query_time = iface->last_member_query_time;
663 ictl.v1_querier_present_tmout = iface->v1_querier_present_tmout;
664 ictl.v1_host_present_interval = iface->v1_host_present_interval;
665 ictl.dead_interval = iface->dead_interval;
666
667 ictl.baudrate = iface->baudrate;
668 ictl.flags = iface->flags;
669 ictl.metric = iface->metric;
670 ictl.type = iface->type;
671 ictl.robustness = iface->robustness;
672 ictl.linkstate = iface->linkstate;
673 ictl.passive = iface->passive;
674 ictl.igmp_version = iface->igmp_version;
675 ictl.if_type = iface->if_type;
676
677 gettimeofday(&now, NULL);
678 if (evtimer_pending(&iface->probe_timer, &tv)) {
679 timersub(&tv, &now, &res);
680 ictl.probe_timer = res.tv_sec;
681 } else
682 ictl.probe_timer = -1;
683
684 if (evtimer_pending(&iface->query_timer, &tv)) {
685 timersub(&tv, &now, &res);
686 ictl.query_timer = res.tv_sec;
687 } else
688 ictl.query_timer = -1;
689
690 if (evtimer_pending(&iface->querier_present_timer, &tv)) {
691 timersub(&tv, &now, &res);
692 ictl.querier_present_timer = res.tv_sec;
693 } else
694 ictl.querier_present_timer = -1;
695
696 if (iface->state != IF_STA_DOWN) {
697 ictl.uptime = now.tv_sec - iface->uptime;
698 } else
699 ictl.uptime = 0;
700
701 return (&ictl);
702 }
703