1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 Alexander V. Chernikov 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_inet.h" 29 #include "opt_inet6.h" 30 31 #include <sys/types.h> 32 #include <sys/ck.h> 33 #include <sys/lock.h> 34 #include <sys/socket.h> 35 #include <sys/vnode.h> 36 37 #include <net/if.h> 38 #include <net/if_dl.h> 39 #include <net/route.h> 40 #include <net/route/nhop.h> 41 #include <net/route/route_ctl.h> 42 #include <netlink/netlink.h> 43 #include <netlink/netlink_ctl.h> 44 #include <netlink/netlink_linux.h> 45 #include <netlink/netlink_var.h> 46 #include <netlink/netlink_route.h> 47 48 #include <compat/linux/linux.h> 49 #include <compat/linux/linux_common.h> 50 #include <compat/linux/linux_util.h> 51 52 #define DEBUG_MOD_NAME nl_linux 53 #define DEBUG_MAX_LEVEL LOG_DEBUG3 54 #include <netlink/netlink_debug.h> 55 _DECLARE_DEBUG(LOG_INFO); 56 57 static bool 58 valid_rta_size(const struct rtattr *rta, int sz) 59 { 60 return (NL_RTA_DATA_LEN(rta) == sz); 61 } 62 63 static bool 64 valid_rta_u32(const struct rtattr *rta) 65 { 66 return (valid_rta_size(rta, sizeof(uint32_t))); 67 } 68 69 static uint32_t 70 _rta_get_uint32(const struct rtattr *rta) 71 { 72 return (*((const uint32_t *)NL_RTA_DATA_CONST(rta))); 73 } 74 75 static int 76 rtnl_neigh_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) 77 { 78 struct ndmsg *ndm = (struct ndmsg *)(hdr + 1); 79 sa_family_t f; 80 81 if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + sizeof(struct ndmsg)) 82 return (EBADMSG); 83 if ((f = linux_to_bsd_domain(ndm->ndm_family)) == AF_UNKNOWN) 84 return (EPFNOSUPPORT); 85 86 ndm->ndm_family = f; 87 88 return (0); 89 } 90 91 static int 92 rtnl_ifaddr_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) 93 { 94 struct ifaddrmsg *ifam = (struct ifaddrmsg *)(hdr + 1); 95 sa_family_t f; 96 97 if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + 98 offsetof(struct ifaddrmsg, ifa_family) + sizeof(ifam->ifa_family)) 99 return (EBADMSG); 100 if ((f = linux_to_bsd_domain(ifam->ifa_family)) == AF_UNKNOWN) 101 return (EPFNOSUPPORT); 102 103 ifam->ifa_family = f; 104 105 return (0); 106 } 107 108 /* 109 * XXX: in case of error state of hdr is inconsistent. 110 */ 111 static int 112 rtnl_route_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) 113 { 114 /* Tweak address families and default fib only */ 115 struct rtmsg *rtm = (struct rtmsg *)(hdr + 1); 116 struct nlattr *nla, *nla_head; 117 int attrs_len; 118 sa_family_t f; 119 120 if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + sizeof(struct rtmsg)) 121 return (EBADMSG); 122 if ((f = linux_to_bsd_domain(rtm->rtm_family)) == AF_UNKNOWN) 123 return (EPFNOSUPPORT); 124 rtm->rtm_family = f; 125 126 if (rtm->rtm_table == 254) 127 rtm->rtm_table = 0; 128 129 attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr); 130 attrs_len -= NETLINK_ALIGN(sizeof(struct rtmsg)); 131 nla_head = (struct nlattr *)((char *)rtm + NETLINK_ALIGN(sizeof(struct rtmsg))); 132 133 NLA_FOREACH(nla, nla_head, attrs_len) { 134 RT_LOG(LOG_DEBUG3, "GOT type %d len %d total %d", 135 nla->nla_type, nla->nla_len, attrs_len); 136 struct rtattr *rta = (struct rtattr *)nla; 137 if (rta->rta_len < sizeof(struct rtattr)) { 138 break; 139 } 140 switch (rta->rta_type) { 141 case NL_RTA_TABLE: 142 if (!valid_rta_u32(rta)) 143 return (EBADMSG); 144 rtm->rtm_table = 0; 145 uint32_t fibnum = _rta_get_uint32(rta); 146 RT_LOG(LOG_DEBUG3, "GET RTABLE: %u", fibnum); 147 if (fibnum == 254) { 148 *((uint32_t *)NL_RTA_DATA(rta)) = 0; 149 } 150 break; 151 } 152 } 153 154 return (0); 155 } 156 157 static int 158 rtnl_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) 159 { 160 161 switch (hdr->nlmsg_type) { 162 case NL_RTM_GETROUTE: 163 case NL_RTM_NEWROUTE: 164 case NL_RTM_DELROUTE: 165 return (rtnl_route_from_linux(hdr, npt)); 166 case NL_RTM_GETNEIGH: 167 return (rtnl_neigh_from_linux(hdr, npt)); 168 case NL_RTM_GETADDR: 169 return (rtnl_ifaddr_from_linux(hdr, npt)); 170 /* Silence warning for the messages where no translation is required */ 171 case NL_RTM_NEWLINK: 172 case NL_RTM_DELLINK: 173 case NL_RTM_GETLINK: 174 break; 175 default: 176 RT_LOG(LOG_DEBUG, "Passing message type %d untranslated", 177 hdr->nlmsg_type); 178 /* XXXGL: maybe return error? */ 179 } 180 181 return (0); 182 } 183 184 static int 185 nlmsg_from_linux(int netlink_family, struct nlmsghdr **hdr, 186 struct nl_pstate *npt) 187 { 188 switch (netlink_family) { 189 case NETLINK_ROUTE: 190 return (rtnl_from_linux(*hdr, npt)); 191 } 192 193 return (0); 194 } 195 196 197 /************************************************************ 198 * Kernel -> Linux 199 ************************************************************/ 200 201 static bool 202 handle_default_out(struct nlmsghdr *hdr, struct nl_writer *nw) 203 { 204 char *out_hdr; 205 out_hdr = nlmsg_reserve_data(nw, NLMSG_ALIGN(hdr->nlmsg_len), char); 206 207 if (out_hdr != NULL) { 208 memcpy(out_hdr, hdr, hdr->nlmsg_len); 209 nw->num_messages++; 210 return (true); 211 } 212 return (false); 213 } 214 215 static bool 216 nlmsg_copy_header(struct nlmsghdr *hdr, struct nl_writer *nw) 217 { 218 return (nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, hdr->nlmsg_type, 219 hdr->nlmsg_flags, 0)); 220 } 221 222 static void * 223 _nlmsg_copy_next_header(struct nlmsghdr *hdr, struct nl_writer *nw, int sz) 224 { 225 void *next_hdr = nlmsg_reserve_data(nw, sz, void); 226 memcpy(next_hdr, hdr + 1, NLMSG_ALIGN(sz)); 227 228 return (next_hdr); 229 } 230 #define nlmsg_copy_next_header(_hdr, _ns, _t) \ 231 ((_t *)(_nlmsg_copy_next_header(_hdr, _ns, sizeof(_t)))) 232 233 static bool 234 nlmsg_copy_nla(const struct nlattr *nla_orig, struct nl_writer *nw) 235 { 236 struct nlattr *nla = nlmsg_reserve_data(nw, nla_orig->nla_len, struct nlattr); 237 if (nla != NULL) { 238 memcpy(nla, nla_orig, nla_orig->nla_len); 239 return (true); 240 } 241 return (false); 242 } 243 244 /* 245 * Translate a FreeBSD interface name to a Linux interface name. 246 */ 247 static bool 248 nlmsg_translate_ifname_nla(struct nlattr *nla, struct nl_writer *nw) 249 { 250 char ifname[LINUX_IFNAMSIZ]; 251 252 if (nw->ifp == NULL) 253 return (false); 254 (void)ifname_bsd_to_linux_ifp(nw->ifp, ifname, sizeof(ifname)); 255 return (nlattr_add_string(nw, IFLA_IFNAME, ifname)); 256 } 257 258 #define LINUX_NLA_UNHANDLED -1 259 /* 260 * Translate a FreeBSD attribute to a Linux attribute. 261 * Returns LINUX_NLA_UNHANDLED when the attribute is not processed 262 * and the caller must take care of it, otherwise the result is returned. 263 */ 264 static int 265 nlmsg_translate_all_nla(struct nlmsghdr *hdr, struct nlattr *nla, 266 struct nl_writer *nw) 267 { 268 269 switch (hdr->nlmsg_type) { 270 case NL_RTM_NEWLINK: 271 case NL_RTM_DELLINK: 272 case NL_RTM_GETLINK: 273 switch (nla->nla_type) { 274 case IFLA_IFNAME: 275 return (nlmsg_translate_ifname_nla(nla, nw)); 276 default: 277 break; 278 } 279 default: 280 break; 281 } 282 return (LINUX_NLA_UNHANDLED); 283 } 284 285 static bool 286 nlmsg_copy_all_nla(struct nlmsghdr *hdr, int raw_hdrlen, struct nl_writer *nw) 287 { 288 struct nlattr *nla; 289 int ret; 290 291 int hdrlen = NETLINK_ALIGN(raw_hdrlen); 292 int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; 293 struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen); 294 295 NLA_FOREACH(nla, nla_head, attrs_len) { 296 RT_LOG(LOG_DEBUG3, "reading attr %d len %d", nla->nla_type, nla->nla_len); 297 if (nla->nla_len < sizeof(struct nlattr)) { 298 return (false); 299 } 300 ret = nlmsg_translate_all_nla(hdr, nla, nw); 301 if (ret == LINUX_NLA_UNHANDLED) 302 ret = nlmsg_copy_nla(nla, nw); 303 if (!ret) 304 return (false); 305 } 306 return (true); 307 } 308 #undef LINUX_NLA_UNHANDLED 309 310 static unsigned int 311 rtnl_if_flags_to_linux(unsigned int if_flags) 312 { 313 unsigned int result = 0; 314 315 for (int i = 0; i < 31; i++) { 316 unsigned int flag = 1 << i; 317 if (!(flag & if_flags)) 318 continue; 319 switch (flag) { 320 case IFF_UP: 321 case IFF_BROADCAST: 322 case IFF_DEBUG: 323 case IFF_LOOPBACK: 324 case IFF_POINTOPOINT: 325 case IFF_DRV_RUNNING: 326 case IFF_NOARP: 327 case IFF_PROMISC: 328 case IFF_ALLMULTI: 329 result |= flag; 330 break; 331 case IFF_NEEDSEPOCH: 332 case IFF_DRV_OACTIVE: 333 case IFF_SIMPLEX: 334 case IFF_LINK0: 335 case IFF_LINK1: 336 case IFF_LINK2: 337 case IFF_CANTCONFIG: 338 case IFF_PPROMISC: 339 case IFF_MONITOR: 340 case IFF_STATICARP: 341 case IFF_STICKYARP: 342 case IFF_DYING: 343 /* No Linux analogue */ 344 break; 345 case IFF_LOWER_UP: /* IFF_NETLINK_1 */ 346 result |= LINUX_IFF_LOWER_UP; 347 break; 348 case IFF_MULTICAST: 349 result |= LINUX_IFF_MULTICAST; 350 } 351 } 352 return (result); 353 } 354 355 static bool 356 rtnl_newlink_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, 357 struct nl_writer *nw) 358 { 359 if (!nlmsg_copy_header(hdr, nw)) 360 return (false); 361 362 struct ifinfomsg *ifinfo; 363 ifinfo = nlmsg_copy_next_header(hdr, nw, struct ifinfomsg); 364 365 ifinfo->ifi_family = bsd_to_linux_domain(ifinfo->ifi_family); 366 /* Convert interface type */ 367 switch (ifinfo->ifi_type) { 368 case IFT_ETHER: 369 ifinfo->ifi_type = LINUX_ARPHRD_ETHER; 370 break; 371 } 372 ifinfo->ifi_flags = rtnl_if_flags_to_linux(ifinfo->ifi_flags); 373 374 /* Copy attributes unchanged */ 375 if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifinfomsg), nw)) 376 return (false); 377 378 /* make ip(8) happy */ 379 if (!nlattr_add_string(nw, IFLA_QDISC, "noqueue")) 380 return (false); 381 382 if (!nlattr_add_u32(nw, IFLA_TXQLEN, 1000)) 383 return (false); 384 385 nlmsg_end(nw); 386 RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); 387 return (true); 388 } 389 390 static bool 391 rtnl_newaddr_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, 392 struct nl_writer *nw) 393 { 394 if (!nlmsg_copy_header(hdr, nw)) 395 return (false); 396 397 struct ifaddrmsg *ifamsg; 398 ifamsg = nlmsg_copy_next_header(hdr, nw, struct ifaddrmsg); 399 400 ifamsg->ifa_family = bsd_to_linux_domain(ifamsg->ifa_family); 401 /* XXX: fake ifa_flags? */ 402 403 /* Copy attributes unchanged */ 404 if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifaddrmsg), nw)) 405 return (false); 406 407 nlmsg_end(nw); 408 RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); 409 return (true); 410 } 411 412 static bool 413 rtnl_newneigh_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, 414 struct nl_writer *nw) 415 { 416 if (!nlmsg_copy_header(hdr, nw)) 417 return (false); 418 419 struct ndmsg *ndm; 420 ndm = nlmsg_copy_next_header(hdr, nw, struct ndmsg); 421 422 ndm->ndm_family = bsd_to_linux_domain(ndm->ndm_family); 423 424 /* Copy attributes unchanged */ 425 if (!nlmsg_copy_all_nla(hdr, sizeof(struct ndmsg), nw)) 426 return (false); 427 428 nlmsg_end(nw); 429 RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); 430 return (true); 431 } 432 433 static bool 434 rtnl_newroute_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, 435 struct nl_writer *nw) 436 { 437 if (!nlmsg_copy_header(hdr, nw)) 438 return (false); 439 440 struct rtmsg *rtm; 441 rtm = nlmsg_copy_next_header(hdr, nw, struct rtmsg); 442 rtm->rtm_family = bsd_to_linux_domain(rtm->rtm_family); 443 444 struct nlattr *nla; 445 446 int hdrlen = NETLINK_ALIGN(sizeof(struct rtmsg)); 447 int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; 448 struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen); 449 450 NLA_FOREACH(nla, nla_head, attrs_len) { 451 struct rtattr *rta = (struct rtattr *)nla; 452 //RT_LOG(LOG_DEBUG, "READING attr %d len %d", nla->nla_type, nla->nla_len); 453 if (rta->rta_len < sizeof(struct rtattr)) { 454 break; 455 } 456 457 switch (rta->rta_type) { 458 case NL_RTA_TABLE: 459 { 460 uint32_t fibnum; 461 fibnum = _rta_get_uint32(rta); 462 if (fibnum == 0) 463 fibnum = 254; 464 RT_LOG(LOG_DEBUG3, "XFIBNUM %u", fibnum); 465 if (!nlattr_add_u32(nw, NL_RTA_TABLE, fibnum)) 466 return (false); 467 } 468 break; 469 default: 470 if (!nlmsg_copy_nla(nla, nw)) 471 return (false); 472 break; 473 } 474 } 475 476 nlmsg_end(nw); 477 RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); 478 return (true); 479 } 480 481 static bool 482 rtnl_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) 483 { 484 RT_LOG(LOG_DEBUG2, "Got message type %d", hdr->nlmsg_type); 485 486 switch (hdr->nlmsg_type) { 487 case NL_RTM_NEWLINK: 488 case NL_RTM_DELLINK: 489 case NL_RTM_GETLINK: 490 return (rtnl_newlink_to_linux(hdr, nlp, nw)); 491 case NL_RTM_NEWADDR: 492 case NL_RTM_DELADDR: 493 return (rtnl_newaddr_to_linux(hdr, nlp, nw)); 494 case NL_RTM_NEWROUTE: 495 case NL_RTM_DELROUTE: 496 return (rtnl_newroute_to_linux(hdr, nlp, nw)); 497 case NL_RTM_NEWNEIGH: 498 case NL_RTM_DELNEIGH: 499 case NL_RTM_GETNEIGH: 500 return (rtnl_newneigh_to_linux(hdr, nlp, nw)); 501 default: 502 RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated", 503 hdr->nlmsg_type); 504 return (handle_default_out(hdr, nw)); 505 } 506 } 507 508 static bool 509 nlmsg_error_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) 510 { 511 if (!nlmsg_copy_header(hdr, nw)) 512 return (false); 513 514 struct nlmsgerr *nlerr; 515 nlerr = nlmsg_copy_next_header(hdr, nw, struct nlmsgerr); 516 nlerr->error = bsd_to_linux_errno(nlerr->error); 517 518 int copied_len = sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr); 519 if (hdr->nlmsg_len == copied_len) { 520 nlmsg_end(nw); 521 return (true); 522 } 523 524 /* 525 * CAP_ACK was not set. Original request needs to be translated. 526 * XXX: implement translation of the original message 527 */ 528 RT_LOG(LOG_DEBUG, "[WARN] Passing ack message type %d untranslated", 529 nlerr->msg.nlmsg_type); 530 char *dst_payload, *src_payload; 531 int copy_len = hdr->nlmsg_len - copied_len; 532 dst_payload = nlmsg_reserve_data(nw, NLMSG_ALIGN(copy_len), char); 533 534 src_payload = (char *)hdr + copied_len; 535 536 memcpy(dst_payload, src_payload, copy_len); 537 nlmsg_end(nw); 538 539 return (true); 540 } 541 542 static bool 543 nlmsg_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) 544 { 545 if (hdr->nlmsg_type < NLMSG_MIN_TYPE) { 546 switch (hdr->nlmsg_type) { 547 case NLMSG_ERROR: 548 return (nlmsg_error_to_linux(hdr, nlp, nw)); 549 case NLMSG_NOOP: 550 case NLMSG_DONE: 551 case NLMSG_OVERRUN: 552 return (handle_default_out(hdr, nw)); 553 default: 554 RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated", 555 hdr->nlmsg_type); 556 return (handle_default_out(hdr, nw)); 557 } 558 } 559 560 switch (nlp->nl_proto) { 561 case NETLINK_ROUTE: 562 return (rtnl_to_linux(hdr, nlp, nw)); 563 default: 564 return (handle_default_out(hdr, nw)); 565 } 566 } 567 568 static struct nl_buf * 569 nlmsgs_to_linux(struct nl_buf *orig, struct nlpcb *nlp, const struct ifnet *ifp) 570 { 571 struct nl_writer nw; 572 u_int offset, msglen; 573 574 if (__predict_false(!nl_writer_unicast(&nw, 575 orig->datalen + SCRATCH_BUFFER_SIZE, nlp, false))) 576 return (NULL); 577 578 nw.ifp = ifp; 579 /* Assume correct headers. Buffer IS mutable */ 580 for (offset = 0; 581 offset + sizeof(struct nlmsghdr) <= orig->datalen; 582 offset += msglen) { 583 struct nlmsghdr *hdr = (struct nlmsghdr *)&orig->data[offset]; 584 585 msglen = NLMSG_ALIGN(hdr->nlmsg_len); 586 if (!nlmsg_to_linux(hdr, nlp, &nw)) { 587 RT_LOG(LOG_DEBUG, "failed to process msg type %d", 588 hdr->nlmsg_type); 589 nl_buf_free(nw.buf); 590 return (NULL); 591 } 592 } 593 594 RT_LOG(LOG_DEBUG3, "%p: in %u bytes %u messages", __func__, 595 nw.buf->datalen, nw.num_messages); 596 597 return (nw.buf); 598 } 599 600 static struct linux_netlink_provider linux_netlink_v1 = { 601 .msgs_to_linux = nlmsgs_to_linux, 602 .msg_from_linux = nlmsg_from_linux, 603 }; 604 605 void 606 linux_netlink_register(void) 607 { 608 linux_netlink_p = &linux_netlink_v1; 609 } 610 611 void 612 linux_netlink_deregister(void) 613 { 614 linux_netlink_p = NULL; 615 } 616