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