1 /* $OpenBSD: interface.c,v 1.52 2023/03/08 04:43:13 guenther Exp $ */
2
3 /*
4 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@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/time.h>
23 #include <arpa/inet.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "ldpd.h"
28 #include "ldpe.h"
29 #include "log.h"
30
31 static struct if_addr *if_addr_new(struct kaddr *);
32 static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
33 static int if_start(struct iface *, int);
34 static int if_reset(struct iface *, int);
35 static void if_update_af(struct iface_af *, int);
36 static void if_hello_timer(int, short, void *);
37 static void if_start_hello_timer(struct iface_af *);
38 static void if_stop_hello_timer(struct iface_af *);
39 static int if_join_ipv4_group(struct iface *, struct in_addr *);
40 static int if_leave_ipv4_group(struct iface *, struct in_addr *);
41 static int if_join_ipv6_group(struct iface *, struct in6_addr *);
42 static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
43
44 struct iface *
if_new(struct kif * kif)45 if_new(struct kif *kif)
46 {
47 struct iface *iface;
48
49 if ((iface = calloc(1, sizeof(*iface))) == NULL)
50 fatal("if_new: calloc");
51
52 strlcpy(iface->name, kif->ifname, sizeof(iface->name));
53
54 /* get type */
55 if (kif->flags & IFF_POINTOPOINT)
56 iface->type = IF_TYPE_POINTOPOINT;
57 if (kif->flags & IFF_BROADCAST &&
58 kif->flags & IFF_MULTICAST)
59 iface->type = IF_TYPE_BROADCAST;
60
61 /* get index and flags */
62 LIST_INIT(&iface->addr_list);
63 iface->ifindex = kif->ifindex;
64 iface->rdomain = kif->rdomain;
65 iface->flags = kif->flags;
66 iface->linkstate = kif->link_state;
67 iface->if_type = kif->if_type;
68
69 /* ipv4 */
70 iface->ipv4.af = AF_INET;
71 iface->ipv4.iface = iface;
72 iface->ipv4.enabled = 0;
73 iface->ipv4.state = IF_STA_DOWN;
74 LIST_INIT(&iface->ipv4.adj_list);
75
76 /* ipv6 */
77 iface->ipv6.af = AF_INET6;
78 iface->ipv6.iface = iface;
79 iface->ipv6.enabled = 0;
80 iface->ipv6.state = IF_STA_DOWN;
81 LIST_INIT(&iface->ipv6.adj_list);
82
83 return (iface);
84 }
85
86 void
if_exit(struct iface * iface)87 if_exit(struct iface *iface)
88 {
89 struct if_addr *if_addr;
90
91 log_debug("%s: interface %s", __func__, iface->name);
92
93 if (iface->ipv4.state == IF_STA_ACTIVE)
94 if_reset(iface, AF_INET);
95 if (iface->ipv6.state == IF_STA_ACTIVE)
96 if_reset(iface, AF_INET6);
97
98 while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
99 LIST_REMOVE(if_addr, entry);
100 free(if_addr);
101 }
102 }
103
104 struct iface *
if_lookup(struct ldpd_conf * xconf,unsigned short ifindex)105 if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
106 {
107 struct iface *iface;
108
109 LIST_FOREACH(iface, &xconf->iface_list, entry)
110 if (iface->ifindex == ifindex)
111 return (iface);
112
113 return (NULL);
114 }
115
116 struct iface_af *
iface_af_get(struct iface * iface,int af)117 iface_af_get(struct iface *iface, int af)
118 {
119 switch (af) {
120 case AF_INET:
121 return (&iface->ipv4);
122 case AF_INET6:
123 return (&iface->ipv6);
124 default:
125 fatalx("iface_af_get: unknown af");
126 }
127 }
128
129 static struct if_addr *
if_addr_new(struct kaddr * ka)130 if_addr_new(struct kaddr *ka)
131 {
132 struct if_addr *if_addr;
133
134 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
135 fatal(__func__);
136
137 if_addr->af = ka->af;
138 if_addr->addr = ka->addr;
139 if_addr->prefixlen = ka->prefixlen;
140 if_addr->dstbrd = ka->dstbrd;
141
142 return (if_addr);
143 }
144
145 static struct if_addr *
if_addr_lookup(struct if_addr_head * addr_list,struct kaddr * ka)146 if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
147 {
148 struct if_addr *if_addr;
149 int af = ka->af;
150
151 LIST_FOREACH(if_addr, addr_list, entry)
152 if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
153 if_addr->prefixlen == ka->prefixlen &&
154 !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
155 return (if_addr);
156
157 return (NULL);
158 }
159
160 void
if_addr_add(struct kaddr * ka)161 if_addr_add(struct kaddr *ka)
162 {
163 struct iface *iface;
164 struct if_addr *if_addr;
165 struct nbr *nbr;
166
167 if (if_addr_lookup(&global.addr_list, ka) == NULL) {
168 if_addr = if_addr_new(ka);
169
170 LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
171 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
172 if (nbr->state != NBR_STA_OPER)
173 continue;
174 if (if_addr->af == AF_INET && !nbr->v4_enabled)
175 continue;
176 if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
177 continue;
178
179 send_address_single(nbr, if_addr, 0);
180 }
181 }
182
183 iface = if_lookup(leconf, ka->ifindex);
184 if (iface) {
185 if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
186 iface->linklocal = ka->addr.v6;
187
188 if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
189 if_addr = if_addr_new(ka);
190 LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
191 if_update(iface, if_addr->af);
192 }
193 }
194 }
195
196 void
if_addr_del(struct kaddr * ka)197 if_addr_del(struct kaddr *ka)
198 {
199 struct iface *iface;
200 struct if_addr *if_addr;
201 struct nbr *nbr;
202
203 iface = if_lookup(leconf, ka->ifindex);
204 if (iface) {
205 if (ka->af == AF_INET6 &&
206 IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
207 memset(&iface->linklocal, 0, sizeof(iface->linklocal));
208
209 if_addr = if_addr_lookup(&iface->addr_list, ka);
210 if (if_addr) {
211 LIST_REMOVE(if_addr, entry);
212 if_update(iface, if_addr->af);
213 free(if_addr);
214 }
215 }
216
217 if_addr = if_addr_lookup(&global.addr_list, ka);
218 if (if_addr) {
219 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
220 if (nbr->state != NBR_STA_OPER)
221 continue;
222 if (if_addr->af == AF_INET && !nbr->v4_enabled)
223 continue;
224 if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
225 continue;
226 send_address_single(nbr, if_addr, 1);
227 }
228 LIST_REMOVE(if_addr, entry);
229 free(if_addr);
230 }
231 }
232
233 static int
if_start(struct iface * iface,int af)234 if_start(struct iface *iface, int af)
235 {
236 struct iface_af *ia;
237 struct timeval now;
238
239 log_debug("%s: %s address-family %s", __func__, iface->name,
240 af_name(af));
241
242 ia = iface_af_get(iface, af);
243
244 gettimeofday(&now, NULL);
245 ia->uptime = now.tv_sec;
246
247 switch (af) {
248 case AF_INET:
249 if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
250 return (-1);
251 break;
252 case AF_INET6:
253 if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
254 return (-1);
255 break;
256 default:
257 fatalx("if_start: unknown af");
258 }
259
260 send_hello(HELLO_LINK, ia, NULL);
261
262 evtimer_set(&ia->hello_timer, if_hello_timer, ia);
263 if_start_hello_timer(ia);
264 return (0);
265 }
266
267 static int
if_reset(struct iface * iface,int af)268 if_reset(struct iface *iface, int af)
269 {
270 struct iface_af *ia;
271 struct adj *adj;
272
273 log_debug("%s: %s address-family %s", __func__, iface->name,
274 af_name(af));
275
276 ia = iface_af_get(iface, af);
277 if_stop_hello_timer(ia);
278
279 while ((adj = LIST_FIRST(&ia->adj_list)) != NULL)
280 adj_del(adj, S_SHUTDOWN);
281
282 /* try to cleanup */
283 switch (af) {
284 case AF_INET:
285 if (global.ipv4.ldp_disc_socket != -1)
286 if_leave_ipv4_group(iface, &global.mcast_addr_v4);
287 break;
288 case AF_INET6:
289 if (global.ipv6.ldp_disc_socket != -1)
290 if_leave_ipv6_group(iface, &global.mcast_addr_v6);
291 break;
292 default:
293 fatalx("if_start: unknown af");
294 }
295
296 return (0);
297 }
298
299 static void
if_update_af(struct iface_af * ia,int link_ok)300 if_update_af(struct iface_af *ia, int link_ok)
301 {
302 int addr_ok = 0, socket_ok, rtr_id_ok;
303 struct if_addr *if_addr;
304
305 switch (ia->af) {
306 case AF_INET:
307 /*
308 * NOTE: for LDPv4, each interface should have at least one
309 * valid IP address otherwise they can not be enabled.
310 */
311 LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
312 if (if_addr->af == AF_INET) {
313 addr_ok = 1;
314 break;
315 }
316 }
317 break;
318 case AF_INET6:
319 /* for IPv6 the link-local address is enough. */
320 if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
321 addr_ok = 1;
322 break;
323 default:
324 fatalx("if_update_af: unknown af");
325 }
326
327 if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
328 socket_ok = 1;
329 else
330 socket_ok = 0;
331
332 if (leconf->rtr_id.s_addr != INADDR_ANY)
333 rtr_id_ok = 1;
334 else
335 rtr_id_ok = 0;
336
337 if (ia->state == IF_STA_DOWN) {
338 if (!ia->enabled || !link_ok || !addr_ok || !socket_ok ||
339 !rtr_id_ok)
340 return;
341
342 ia->state = IF_STA_ACTIVE;
343 if_start(ia->iface, ia->af);
344 } else if (ia->state == IF_STA_ACTIVE) {
345 if (ia->enabled && link_ok && addr_ok && socket_ok && rtr_id_ok)
346 return;
347
348 ia->state = IF_STA_DOWN;
349 if_reset(ia->iface, ia->af);
350 }
351 }
352
353 void
if_update(struct iface * iface,int af)354 if_update(struct iface *iface, int af)
355 {
356 int link_ok;
357
358 link_ok = (iface->flags & IFF_UP) &&
359 LINK_STATE_IS_UP(iface->linkstate);
360
361 if (af == AF_INET || af == AF_UNSPEC)
362 if_update_af(&iface->ipv4, link_ok);
363 if (af == AF_INET6 || af == AF_UNSPEC)
364 if_update_af(&iface->ipv6, link_ok);
365 }
366
367 void
if_update_all(int af)368 if_update_all(int af)
369 {
370 struct iface *iface;
371
372 LIST_FOREACH(iface, &leconf->iface_list, entry)
373 if_update(iface, af);
374 }
375
376 /* timers */
377 static void
if_hello_timer(int fd,short event,void * arg)378 if_hello_timer(int fd, short event, void *arg)
379 {
380 struct iface_af *ia = arg;
381
382 send_hello(HELLO_LINK, ia, NULL);
383 if_start_hello_timer(ia);
384 }
385
386 static void
if_start_hello_timer(struct iface_af * ia)387 if_start_hello_timer(struct iface_af *ia)
388 {
389 struct timeval tv;
390
391 timerclear(&tv);
392 tv.tv_sec = ia->hello_interval;
393 if (evtimer_add(&ia->hello_timer, &tv) == -1)
394 fatal(__func__);
395 }
396
397 static void
if_stop_hello_timer(struct iface_af * ia)398 if_stop_hello_timer(struct iface_af *ia)
399 {
400 if (evtimer_pending(&ia->hello_timer, NULL) &&
401 evtimer_del(&ia->hello_timer) == -1)
402 fatal(__func__);
403 }
404
405 struct ctl_iface *
if_to_ctl(struct iface_af * ia)406 if_to_ctl(struct iface_af *ia)
407 {
408 static struct ctl_iface ictl;
409 struct timeval now;
410 struct adj *adj;
411
412 ictl.af = ia->af;
413 memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
414 ictl.ifindex = ia->iface->ifindex;
415 ictl.state = ia->state;
416 ictl.flags = ia->iface->flags;
417 ictl.linkstate = ia->iface->linkstate;
418 ictl.type = ia->iface->type;
419 ictl.if_type = ia->iface->if_type;
420 ictl.hello_holdtime = ia->hello_holdtime;
421 ictl.hello_interval = ia->hello_interval;
422
423 gettimeofday(&now, NULL);
424 if (ia->state != IF_STA_DOWN &&
425 ia->uptime != 0) {
426 ictl.uptime = now.tv_sec - ia->uptime;
427 } else
428 ictl.uptime = 0;
429
430 ictl.adj_cnt = 0;
431 LIST_FOREACH(adj, &ia->adj_list, ia_entry)
432 ictl.adj_cnt++;
433
434 return (&ictl);
435 }
436
437 /* multicast membership sockopts */
438 in_addr_t
if_get_ipv4_addr(struct iface * iface)439 if_get_ipv4_addr(struct iface *iface)
440 {
441 struct if_addr *if_addr;
442
443 LIST_FOREACH(if_addr, &iface->addr_list, entry)
444 if (if_addr->af == AF_INET)
445 return (if_addr->addr.v4.s_addr);
446
447 return (INADDR_ANY);
448 }
449
450 static int
if_join_ipv4_group(struct iface * iface,struct in_addr * addr)451 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
452 {
453 struct ip_mreq mreq;
454
455 log_debug("%s: interface %s addr %s", __func__, iface->name,
456 inet_ntoa(*addr));
457
458 mreq.imr_multiaddr = *addr;
459 mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
460
461 if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
462 IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) == -1) {
463 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
464 __func__, iface->name, inet_ntoa(*addr));
465 return (-1);
466 }
467 return (0);
468 }
469
470 static int
if_leave_ipv4_group(struct iface * iface,struct in_addr * addr)471 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
472 {
473 struct ip_mreq mreq;
474
475 log_debug("%s: interface %s addr %s", __func__, iface->name,
476 inet_ntoa(*addr));
477
478 mreq.imr_multiaddr = *addr;
479 mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
480
481 if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
482 IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) == -1) {
483 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
484 "address %s", __func__, iface->name, inet_ntoa(*addr));
485 return (-1);
486 }
487
488 return (0);
489 }
490
491 static int
if_join_ipv6_group(struct iface * iface,struct in6_addr * addr)492 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
493 {
494 struct ipv6_mreq mreq;
495
496 log_debug("%s: interface %s addr %s", __func__, iface->name,
497 log_in6addr(addr));
498
499 mreq.ipv6mr_multiaddr = *addr;
500 mreq.ipv6mr_interface = iface->ifindex;
501
502 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
503 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) {
504 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
505 __func__, iface->name, log_in6addr(addr));
506 return (-1);
507 }
508
509 return (0);
510 }
511
512 static int
if_leave_ipv6_group(struct iface * iface,struct in6_addr * addr)513 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
514 {
515 struct ipv6_mreq mreq;
516
517 log_debug("%s: interface %s addr %s", __func__, iface->name,
518 log_in6addr(addr));
519
520 mreq.ipv6mr_multiaddr = *addr;
521 mreq.ipv6mr_interface = iface->ifindex;
522
523 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
524 IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) == -1) {
525 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
526 __func__, iface->name, log_in6addr(addr));
527 return (-1);
528 }
529
530 return (0);
531 }
532