1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 #include "opt_inet.h" 31 #include "opt_inet6.h" 32 #include <sys/types.h> 33 #include <sys/eventhandler.h> 34 #include <sys/malloc.h> 35 #include <sys/socket.h> 36 #include <sys/syslog.h> 37 38 #include <net/if.h> 39 #include <net/if_llatbl.h> 40 #include <netlink/netlink.h> 41 #include <netlink/netlink_ctl.h> 42 #include <netlink/netlink_route.h> 43 #include <netlink/route/route_var.h> 44 45 #include <netinet6/in6_var.h> /* nd6.h requires this */ 46 #include <netinet6/nd6.h> /* nd6 state machine */ 47 #include <netinet6/scope6_var.h> /* scope deembedding */ 48 49 #define DEBUG_MOD_NAME nl_neigh 50 #define DEBUG_MAX_LEVEL LOG_DEBUG3 51 #include <netlink/netlink_debug.h> 52 _DECLARE_DEBUG(LOG_DEBUG); 53 54 static int lle_families[] = { AF_INET, AF_INET6 }; 55 56 static eventhandler_tag lle_event_p; 57 58 struct netlink_walkargs { 59 struct nl_writer *nw; 60 struct nlmsghdr hdr; 61 struct nlpcb *so; 62 struct ifnet *ifp; 63 int family; 64 int error; 65 int count; 66 int dumped; 67 }; 68 69 static int 70 lle_state_to_nl_state(int family, struct llentry *lle) 71 { 72 int state = lle->ln_state; 73 74 switch (family) { 75 case AF_INET: 76 if (lle->la_flags & (LLE_STATIC | LLE_IFADDR)) 77 state = 1; 78 switch (state) { 79 case 0: /* ARP_LLINFO_INCOMPLETE */ 80 return (NUD_INCOMPLETE); 81 case 1: /* ARP_LLINFO_REACHABLE */ 82 return (NUD_REACHABLE); 83 case 2: /* ARP_LLINFO_VERIFY */ 84 return (NUD_PROBE); 85 } 86 break; 87 case AF_INET6: 88 switch (state) { 89 case ND6_LLINFO_INCOMPLETE: 90 return (NUD_INCOMPLETE); 91 case ND6_LLINFO_REACHABLE: 92 return (NUD_REACHABLE); 93 case ND6_LLINFO_STALE: 94 return (NUD_STALE); 95 case ND6_LLINFO_DELAY: 96 return (NUD_DELAY); 97 case ND6_LLINFO_PROBE: 98 return (NUD_PROBE); 99 } 100 break; 101 } 102 103 return (NUD_NONE); 104 } 105 106 static uint32_t 107 lle_flags_to_nl_flags(const struct llentry *lle) 108 { 109 uint32_t nl_flags = 0; 110 111 if (lle->la_flags & LLE_IFADDR) 112 nl_flags |= NTF_SELF; 113 if (lle->la_flags & LLE_PUB) 114 nl_flags |= NTF_PROXY; 115 if (lle->la_flags & LLE_STATIC) 116 nl_flags |= NTF_STICKY; 117 if (lle->ln_router != 0) 118 nl_flags |= NTF_ROUTER; 119 120 return (nl_flags); 121 } 122 123 static int 124 dump_lle_locked(struct llentry *lle, void *arg) 125 { 126 struct netlink_walkargs *wa = (struct netlink_walkargs *)arg; 127 struct nlmsghdr *hdr = &wa->hdr; 128 struct nl_writer *nw = wa->nw; 129 struct ndmsg *ndm; 130 #if defined(INET) || defined(INET6) 131 union { 132 struct in_addr in; 133 struct in6_addr in6; 134 } addr; 135 #endif 136 137 IF_DEBUG_LEVEL(LOG_DEBUG2) { 138 char llebuf[NHOP_PRINT_BUFSIZE]; 139 llentry_print_buf_lltable(lle, llebuf, sizeof(llebuf)); 140 NL_LOG(LOG_DEBUG2, "dumping %s", llebuf); 141 } 142 143 if (!nlmsg_reply(nw, hdr, sizeof(struct ndmsg))) 144 goto enomem; 145 146 ndm = nlmsg_reserve_object(nw, struct ndmsg); 147 ndm->ndm_family = wa->family; 148 ndm->ndm_ifindex = wa->ifp->if_index; 149 ndm->ndm_state = lle_state_to_nl_state(wa->family, lle); 150 ndm->ndm_flags = lle_flags_to_nl_flags(lle); 151 152 switch (wa->family) { 153 #ifdef INET 154 case AF_INET: 155 addr.in = lle->r_l3addr.addr4; 156 nlattr_add(nw, NDA_DST, 4, &addr); 157 break; 158 #endif 159 #ifdef INET6 160 case AF_INET6: 161 addr.in6 = lle->r_l3addr.addr6; 162 in6_clearscope(&addr.in6); 163 nlattr_add(nw, NDA_DST, 16, &addr); 164 break; 165 #endif 166 } 167 168 if (lle->r_flags & RLLE_VALID) { 169 /* Has L2 */ 170 int addrlen = wa->ifp->if_addrlen; 171 nlattr_add(nw, NDA_LLADDR, addrlen, lle->ll_addr); 172 } 173 174 nlattr_add_u32(nw, NDA_PROBES, lle->la_asked); 175 176 struct nda_cacheinfo *cache; 177 cache = nlmsg_reserve_attr(nw, NDA_CACHEINFO, struct nda_cacheinfo); 178 if (cache == NULL) 179 goto enomem; 180 /* TODO: provide confirmed/updated */ 181 cache->ndm_refcnt = lle->lle_refcnt; 182 183 if (nlmsg_end(nw)) 184 return (0); 185 enomem: 186 NL_LOG(LOG_DEBUG, "unable to dump lle state (ENOMEM)"); 187 nlmsg_abort(nw); 188 return (ENOMEM); 189 } 190 191 static int 192 dump_lle(struct lltable *llt, struct llentry *lle, void *arg) 193 { 194 int error; 195 196 LLE_RLOCK(lle); 197 error = dump_lle_locked(lle, arg); 198 LLE_RUNLOCK(lle); 199 return (error); 200 } 201 202 static bool 203 dump_llt(struct lltable *llt, struct netlink_walkargs *wa) 204 { 205 lltable_foreach_lle(llt, dump_lle, wa); 206 207 return (true); 208 } 209 210 static int 211 dump_llts_iface(struct netlink_walkargs *wa, struct ifnet *ifp, int family) 212 { 213 int error = 0; 214 215 wa->ifp = ifp; 216 for (int i = 0; i < sizeof(lle_families) / sizeof(int); i++) { 217 int fam = lle_families[i]; 218 struct lltable *llt = lltable_get(ifp, fam); 219 if (llt != NULL && (family == 0 || family == fam)) { 220 wa->count++; 221 wa->family = fam; 222 if (!dump_llt(llt, wa)) { 223 error = ENOMEM; 224 break; 225 } 226 wa->dumped++; 227 } 228 } 229 return (error); 230 } 231 232 static int 233 dump_llts(struct netlink_walkargs *wa, struct ifnet *ifp, int family) 234 { 235 NL_LOG(LOG_DEBUG, "Start dump ifp=%s family=%d", ifp ? if_name(ifp) : "NULL", family); 236 237 wa->hdr.nlmsg_flags |= NLM_F_MULTI; 238 239 if (ifp != NULL) { 240 dump_llts_iface(wa, ifp, family); 241 } else { 242 CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 243 dump_llts_iface(wa, ifp, family); 244 } 245 } 246 247 NL_LOG(LOG_DEBUG, "End dump, iterated %d dumped %d", wa->count, wa->dumped); 248 249 if (!nlmsg_end_dump(wa->nw, wa->error, &wa->hdr)) { 250 NL_LOG(LOG_DEBUG, "Unable to add new message"); 251 return (ENOMEM); 252 } 253 254 return (0); 255 } 256 257 static int 258 get_lle(struct netlink_walkargs *wa, struct ifnet *ifp, int family, struct sockaddr *dst) 259 { 260 struct lltable *llt = lltable_get(ifp, family); 261 if (llt == NULL) 262 return (ESRCH); 263 264 #ifdef INET6 265 if (dst->sa_family == AF_INET6) { 266 struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst; 267 268 if (IN6_IS_SCOPE_LINKLOCAL(&dst6->sin6_addr)) 269 in6_set_unicast_scopeid(&dst6->sin6_addr, ifp->if_index); 270 } 271 #endif 272 struct llentry *lle = lla_lookup(llt, LLE_UNLOCKED, dst); 273 if (lle == NULL) 274 return (ESRCH); 275 276 wa->ifp = ifp; 277 wa->family = family; 278 279 return (dump_lle(llt, lle, wa)); 280 } 281 282 struct nl_parsed_neigh { 283 struct sockaddr *nda_dst; 284 struct ifnet *nda_ifp; 285 struct nlattr *nda_lladdr; 286 uint32_t ndm_flags; 287 uint16_t ndm_state; 288 uint8_t ndm_family; 289 }; 290 291 #define _IN(_field) offsetof(struct ndmsg, _field) 292 #define _OUT(_field) offsetof(struct nl_parsed_neigh, _field) 293 static struct nlfield_parser nlf_p_neigh[] = { 294 { .off_in = _IN(ndm_family), .off_out = _OUT(ndm_family), .cb = nlf_get_u8 }, 295 { .off_in = _IN(ndm_flags), .off_out = _OUT(ndm_flags), .cb = nlf_get_u8_u32 }, 296 { .off_in = _IN(ndm_state), .off_out = _OUT(ndm_state), .cb = nlf_get_u16 }, 297 { .off_in = _IN(ndm_ifindex), .off_out = _OUT(nda_ifp), .cb = nlf_get_ifpz }, 298 }; 299 300 static struct nlattr_parser nla_p_neigh[] = { 301 { .type = NDA_DST, .off = _OUT(nda_dst), .cb = nlattr_get_ip }, 302 { .type = NDA_LLADDR, .off = _OUT(nda_lladdr), .cb = nlattr_get_nla }, 303 { .type = NDA_IFINDEX, .off = _OUT(nda_ifp), .cb = nlattr_get_ifp }, 304 { .type = NDA_FLAGS_EXT, .off = _OUT(ndm_flags), .cb = nlattr_get_uint32 }, 305 }; 306 #undef _IN 307 #undef _OUT 308 NL_DECLARE_PARSER(ndmsg_parser, struct ndmsg, nlf_p_neigh, nla_p_neigh); 309 310 311 /* 312 * type=RTM_NEWNEIGH, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE, seq=1661941473, pid=0}, 313 * {ndm_family=AF_INET6, ndm_ifindex=if_nametoindex("enp0s31f6"), ndm_state=NUD_PERMANENT, ndm_flags=0, ndm_type=RTN_UNSPEC}, 314 * [ 315 * {{nla_len=20, nla_type=NDA_DST}, inet_pton(AF_INET6, "2a01:4f8:13a:70c::3")}, 316 * {{nla_len=10, nla_type=NDA_LLADDR}, 20:4e:71:62:ae:f2}]}, iov_len=60} 317 */ 318 319 static int 320 rtnl_handle_newneigh(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) 321 { 322 int error; 323 324 struct nl_parsed_neigh attrs = {}; 325 error = nl_parse_nlmsg(hdr, &ndmsg_parser, npt, &attrs); 326 if (error != 0) 327 return (error); 328 329 if (attrs.nda_ifp == NULL || attrs.nda_dst == NULL || attrs.nda_lladdr == NULL) { 330 if (attrs.nda_ifp == NULL) 331 NLMSG_REPORT_ERR_MSG(npt, "NDA_IFINDEX / ndm_ifindex not set"); 332 if (attrs.nda_dst == NULL) 333 NLMSG_REPORT_ERR_MSG(npt, "NDA_DST not set"); 334 if (attrs.nda_lladdr == NULL) 335 NLMSG_REPORT_ERR_MSG(npt, "NDA_LLADDR not set"); 336 return (EINVAL); 337 } 338 339 if (attrs.nda_dst->sa_family != attrs.ndm_family) { 340 NLMSG_REPORT_ERR_MSG(npt, 341 "NDA_DST family (%d) is different from ndm_family (%d)", 342 attrs.nda_dst->sa_family, attrs.ndm_family); 343 return (EINVAL); 344 } 345 346 int addrlen = attrs.nda_ifp->if_addrlen; 347 if (attrs.nda_lladdr->nla_len != sizeof(struct nlattr) + addrlen) { 348 NLMSG_REPORT_ERR_MSG(npt, 349 "NDA_LLADDR address length (%d) is different from expected (%d)", 350 (int)attrs.nda_lladdr->nla_len - (int)sizeof(struct nlattr), addrlen); 351 return (EINVAL); 352 } 353 354 if (attrs.ndm_state != NUD_PERMANENT) { 355 NLMSG_REPORT_ERR_MSG(npt, "ndm_state %d not supported", attrs.ndm_state); 356 return (ENOTSUP); 357 } 358 359 const uint16_t supported_flags = NTF_PROXY | NTF_STICKY; 360 if ((attrs.ndm_flags & supported_flags) != attrs.ndm_flags) { 361 NLMSG_REPORT_ERR_MSG(npt, "ndm_flags %X not supported", 362 attrs.ndm_flags &~ supported_flags); 363 return (ENOTSUP); 364 } 365 366 /* Replacement requires new entry creation anyway */ 367 if ((hdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_REPLACE)) == 0) 368 return (ENOTSUP); 369 370 struct lltable *llt = lltable_get(attrs.nda_ifp, attrs.ndm_family); 371 if (llt == NULL) 372 return (EAFNOSUPPORT); 373 374 375 uint8_t linkhdr[LLE_MAX_LINKHDR]; 376 size_t linkhdrsize = sizeof(linkhdr); 377 int lladdr_off = 0; 378 if (lltable_calc_llheader(attrs.nda_ifp, attrs.ndm_family, 379 (char *)(attrs.nda_lladdr + 1), linkhdr, &linkhdrsize, &lladdr_off) != 0) { 380 NLMSG_REPORT_ERR_MSG(npt, "unable to calculate lle prepend data"); 381 return (EINVAL); 382 } 383 384 int lle_flags = LLE_STATIC | ((attrs.ndm_flags & NTF_PROXY) ? LLE_PUB : 0); 385 struct llentry *lle = lltable_alloc_entry(llt, lle_flags, attrs.nda_dst); 386 if (lle == NULL) 387 return (ENOMEM); 388 lltable_set_entry_addr(attrs.nda_ifp, lle, linkhdr, linkhdrsize, lladdr_off); 389 390 /* llentry created, try to insert or update :*/ 391 IF_AFDATA_WLOCK(attrs.nda_ifp); 392 LLE_WLOCK(lle); 393 struct llentry *lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, attrs.nda_dst); 394 if (lle_tmp != NULL) { 395 if (hdr->nlmsg_flags & NLM_F_EXCL) { 396 LLE_WUNLOCK(lle_tmp); 397 lle_tmp = NULL; 398 error = EEXIST; 399 } else if (hdr->nlmsg_flags & NLM_F_REPLACE) { 400 lltable_unlink_entry(llt, lle_tmp); 401 lltable_link_entry(llt, lle); 402 } else 403 error = EEXIST; 404 } else { 405 if (hdr->nlmsg_flags & NLM_F_CREATE) 406 lltable_link_entry(llt, lle); 407 else 408 error = ENOENT; 409 } 410 IF_AFDATA_WUNLOCK(attrs.nda_ifp); 411 412 if (error != 0) { 413 if (lle != NULL) 414 llentry_free(lle); 415 return (error); 416 } 417 418 if (lle_tmp != NULL) 419 llentry_free(lle_tmp); 420 421 /* XXX: We're inside epoch */ 422 EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED); 423 LLE_WUNLOCK(lle); 424 425 return (0); 426 } 427 428 static int 429 rtnl_handle_delneigh(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) 430 { 431 int error; 432 433 struct nl_parsed_neigh attrs = {}; 434 error = nl_parse_nlmsg(hdr, &ndmsg_parser, npt, &attrs); 435 if (error != 0) 436 return (error); 437 438 if (attrs.nda_dst == NULL) { 439 NLMSG_REPORT_ERR_MSG(npt, "NDA_DST not set"); 440 return (EINVAL); 441 } 442 443 if (attrs.nda_ifp == NULL) { 444 NLMSG_REPORT_ERR_MSG(npt, "no ifindex provided"); 445 return (EINVAL); 446 } 447 448 struct lltable *llt = lltable_get(attrs.nda_ifp, attrs.ndm_family); 449 if (llt == NULL) 450 return (EAFNOSUPPORT); 451 452 IF_AFDATA_WLOCK(attrs.nda_ifp); 453 struct llentry *lle = lla_lookup(llt, LLE_EXCLUSIVE, attrs.nda_dst); 454 if (lle != NULL) { 455 if ((lle->la_flags & LLE_IFADDR) != 0) { 456 LLE_WUNLOCK(lle); 457 lle = NULL; 458 error = EPERM; 459 } else 460 lltable_unlink_entry(llt, lle); 461 } else 462 error = ENOENT; 463 IF_AFDATA_WUNLOCK(attrs.nda_ifp); 464 465 if (error == 0 && lle != NULL) 466 EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED); 467 468 if (lle != NULL) 469 llentry_free(lle); 470 471 return (error); 472 } 473 474 static int 475 rtnl_handle_getneigh(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) 476 { 477 int error; 478 479 struct nl_parsed_neigh attrs = {}; 480 error = nl_parse_nlmsg(hdr, &ndmsg_parser, npt, &attrs); 481 if (error != 0) 482 return (error); 483 484 if (attrs.nda_dst != NULL && attrs.nda_ifp == NULL) { 485 NLMSG_REPORT_ERR_MSG(npt, "has NDA_DST but no ifindex provided"); 486 return (EINVAL); 487 } 488 489 struct netlink_walkargs wa = { 490 .so = nlp, 491 .nw = npt->nw, 492 .hdr.nlmsg_pid = hdr->nlmsg_pid, 493 .hdr.nlmsg_seq = hdr->nlmsg_seq, 494 .hdr.nlmsg_flags = hdr->nlmsg_flags, 495 .hdr.nlmsg_type = NL_RTM_NEWNEIGH, 496 }; 497 498 if (attrs.nda_dst == NULL) 499 error = dump_llts(&wa, attrs.nda_ifp, attrs.ndm_family); 500 else 501 error = get_lle(&wa, attrs.nda_ifp, attrs.ndm_family, attrs.nda_dst); 502 503 return (error); 504 } 505 506 static const struct rtnl_cmd_handler cmd_handlers[] = { 507 { 508 .cmd = NL_RTM_NEWNEIGH, 509 .name = "RTM_NEWNEIGH", 510 .cb = &rtnl_handle_newneigh, 511 }, 512 { 513 .cmd = NL_RTM_DELNEIGH, 514 .name = "RTM_DELNEIGH", 515 .cb = &rtnl_handle_delneigh, 516 .priv = PRIV_NET_ROUTE, 517 }, 518 { 519 .cmd = NL_RTM_GETNEIGH, 520 .name = "RTM_GETNEIGH", 521 .cb = &rtnl_handle_getneigh, 522 .priv = PRIV_NET_ROUTE, 523 } 524 }; 525 526 static void 527 rtnl_lle_event(void *arg __unused, struct llentry *lle, int evt) 528 { 529 struct ifnet *ifp; 530 int family; 531 532 LLE_WLOCK_ASSERT(lle); 533 534 ifp = lltable_get_ifp(lle->lle_tbl); 535 family = lltable_get_af(lle->lle_tbl); 536 537 if (family != AF_INET && family != AF_INET6) 538 return; 539 540 int nlmsgs_type = evt == LLENTRY_RESOLVED ? NL_RTM_NEWNEIGH : NL_RTM_DELNEIGH; 541 542 struct nl_writer nw = {}; 543 if (!nlmsg_get_group_writer(&nw, NLMSG_SMALL, NETLINK_ROUTE, RTNLGRP_NEIGH)) { 544 NL_LOG(LOG_DEBUG, "error allocating group writer"); 545 return; 546 } 547 548 struct netlink_walkargs wa = { 549 .hdr.nlmsg_type = nlmsgs_type, 550 .nw = &nw, 551 .ifp = ifp, 552 .family = family, 553 }; 554 555 dump_lle_locked(lle, &wa); 556 nlmsg_flush(&nw); 557 } 558 559 static const struct nlhdr_parser *all_parsers[] = { &ndmsg_parser }; 560 561 void 562 rtnl_neighs_init(void) 563 { 564 NL_VERIFY_PARSERS(all_parsers); 565 rtnl_register_messages(cmd_handlers, NL_ARRAY_LEN(cmd_handlers)); 566 lle_event_p = EVENTHANDLER_REGISTER(lle_event, rtnl_lle_event, NULL, 567 EVENTHANDLER_PRI_ANY); 568 } 569 570 void 571 rtnl_neighs_destroy(void) 572 { 573 EVENTHANDLER_DEREGISTER(lle_event, lle_event_p); 574 } 575