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 nlmsghdr *hdr, struct nlattr *nla, 249 struct nl_writer *nw) 250 { 251 struct ifinfomsg *ifinfo; 252 char ifname[LINUX_IFNAMSIZ]; 253 254 ifinfo = (struct ifinfomsg *)(hdr + 1); 255 if (ifname_bsd_to_linux_idx(ifinfo->ifi_index, ifname, 256 sizeof(ifname)) <= 0) 257 return (nlmsg_copy_nla(nla, nw)); 258 return (nlattr_add_string(nw, IFLA_IFNAME, ifname)); 259 } 260 261 #define LINUX_NLA_UNHANDLED -1 262 /* 263 * Translate a FreeBSD attribute to a Linux attribute. 264 * Returns LINUX_NLA_UNHANDLED when the attribute is not processed 265 * and the caller must take care of it, otherwise the result is returned. 266 */ 267 static int 268 nlmsg_translate_all_nla(struct nlmsghdr *hdr, struct nlattr *nla, 269 struct nl_writer *nw) 270 { 271 272 switch (hdr->nlmsg_type) { 273 case NL_RTM_NEWLINK: 274 case NL_RTM_DELLINK: 275 case NL_RTM_GETLINK: 276 switch (nla->nla_type) { 277 case IFLA_IFNAME: 278 return (nlmsg_translate_ifname_nla(hdr, nla, nw)); 279 default: 280 break; 281 } 282 default: 283 break; 284 } 285 return (LINUX_NLA_UNHANDLED); 286 } 287 288 static bool 289 nlmsg_copy_all_nla(struct nlmsghdr *hdr, int raw_hdrlen, struct nl_writer *nw) 290 { 291 struct nlattr *nla; 292 int ret; 293 294 int hdrlen = NETLINK_ALIGN(raw_hdrlen); 295 int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; 296 struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen); 297 298 NLA_FOREACH(nla, nla_head, attrs_len) { 299 RT_LOG(LOG_DEBUG3, "reading attr %d len %d", nla->nla_type, nla->nla_len); 300 if (nla->nla_len < sizeof(struct nlattr)) { 301 return (false); 302 } 303 ret = nlmsg_translate_all_nla(hdr, nla, nw); 304 if (ret == LINUX_NLA_UNHANDLED) 305 ret = nlmsg_copy_nla(nla, nw); 306 if (!ret) 307 return (false); 308 } 309 return (true); 310 } 311 #undef LINUX_NLA_UNHANDLED 312 313 static unsigned int 314 rtnl_if_flags_to_linux(unsigned int if_flags) 315 { 316 unsigned int result = 0; 317 318 for (int i = 0; i < 31; i++) { 319 unsigned int flag = 1 << i; 320 if (!(flag & if_flags)) 321 continue; 322 switch (flag) { 323 case IFF_UP: 324 case IFF_BROADCAST: 325 case IFF_DEBUG: 326 case IFF_LOOPBACK: 327 case IFF_POINTOPOINT: 328 case IFF_DRV_RUNNING: 329 case IFF_NOARP: 330 case IFF_PROMISC: 331 case IFF_ALLMULTI: 332 result |= flag; 333 break; 334 case IFF_NEEDSEPOCH: 335 case IFF_DRV_OACTIVE: 336 case IFF_SIMPLEX: 337 case IFF_LINK0: 338 case IFF_LINK1: 339 case IFF_LINK2: 340 case IFF_CANTCONFIG: 341 case IFF_PPROMISC: 342 case IFF_MONITOR: 343 case IFF_STATICARP: 344 case IFF_STICKYARP: 345 case IFF_DYING: 346 /* No Linux analogue */ 347 break; 348 case IFF_LOWER_UP: /* IFF_NETLINK_1 */ 349 result |= LINUX_IFF_LOWER_UP; 350 break; 351 case IFF_MULTICAST: 352 result |= LINUX_IFF_MULTICAST; 353 } 354 } 355 return (result); 356 } 357 358 static bool 359 rtnl_newlink_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, 360 struct nl_writer *nw) 361 { 362 if (!nlmsg_copy_header(hdr, nw)) 363 return (false); 364 365 struct ifinfomsg *ifinfo; 366 ifinfo = nlmsg_copy_next_header(hdr, nw, struct ifinfomsg); 367 368 ifinfo->ifi_family = bsd_to_linux_domain(ifinfo->ifi_family); 369 /* Convert interface type */ 370 switch (ifinfo->ifi_type) { 371 case IFT_ETHER: 372 case IFT_BRIDGE: 373 case IFT_L2VLAN: 374 ifinfo->ifi_type = LINUX_ARPHRD_ETHER; 375 break; 376 case IFT_LOOP: 377 ifinfo->ifi_type = LINUX_ARPHRD_LOOPBACK; 378 break; 379 case IFT_STF: 380 ifinfo->ifi_type = LINUX_ARPHRD_SIT; 381 break; 382 } 383 ifinfo->ifi_flags = rtnl_if_flags_to_linux(ifinfo->ifi_flags); 384 385 /* Copy attributes unchanged */ 386 if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifinfomsg), nw)) 387 return (false); 388 389 /* make ip(8) happy */ 390 if (!nlattr_add_string(nw, IFLA_QDISC, "noqueue")) 391 return (false); 392 393 if (!nlattr_add_u32(nw, IFLA_TXQLEN, 1000)) 394 return (false); 395 396 nlmsg_end(nw); 397 RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); 398 return (true); 399 } 400 401 static bool 402 rtnl_newaddr_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, 403 struct nl_writer *nw) 404 { 405 if (!nlmsg_copy_header(hdr, nw)) 406 return (false); 407 408 struct ifaddrmsg *ifamsg; 409 ifamsg = nlmsg_copy_next_header(hdr, nw, struct ifaddrmsg); 410 411 ifamsg->ifa_family = bsd_to_linux_domain(ifamsg->ifa_family); 412 /* XXX: fake ifa_flags? */ 413 414 /* Copy attributes unchanged */ 415 if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifaddrmsg), nw)) 416 return (false); 417 418 nlmsg_end(nw); 419 RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); 420 return (true); 421 } 422 423 static bool 424 rtnl_newneigh_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, 425 struct nl_writer *nw) 426 { 427 if (!nlmsg_copy_header(hdr, nw)) 428 return (false); 429 430 struct ndmsg *ndm; 431 ndm = nlmsg_copy_next_header(hdr, nw, struct ndmsg); 432 433 ndm->ndm_family = bsd_to_linux_domain(ndm->ndm_family); 434 435 /* Copy attributes unchanged */ 436 if (!nlmsg_copy_all_nla(hdr, sizeof(struct ndmsg), nw)) 437 return (false); 438 439 nlmsg_end(nw); 440 RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); 441 return (true); 442 } 443 444 static bool 445 rtnl_newroute_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, 446 struct nl_writer *nw) 447 { 448 if (!nlmsg_copy_header(hdr, nw)) 449 return (false); 450 451 struct rtmsg *rtm; 452 rtm = nlmsg_copy_next_header(hdr, nw, struct rtmsg); 453 rtm->rtm_family = bsd_to_linux_domain(rtm->rtm_family); 454 455 struct nlattr *nla; 456 457 int hdrlen = NETLINK_ALIGN(sizeof(struct rtmsg)); 458 int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; 459 struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen); 460 461 NLA_FOREACH(nla, nla_head, attrs_len) { 462 struct rtattr *rta = (struct rtattr *)nla; 463 //RT_LOG(LOG_DEBUG, "READING attr %d len %d", nla->nla_type, nla->nla_len); 464 if (rta->rta_len < sizeof(struct rtattr)) { 465 break; 466 } 467 468 switch (rta->rta_type) { 469 case NL_RTA_TABLE: 470 { 471 uint32_t fibnum; 472 fibnum = _rta_get_uint32(rta); 473 if (fibnum == 0) 474 fibnum = 254; 475 RT_LOG(LOG_DEBUG3, "XFIBNUM %u", fibnum); 476 if (!nlattr_add_u32(nw, NL_RTA_TABLE, fibnum)) 477 return (false); 478 } 479 break; 480 default: 481 if (!nlmsg_copy_nla(nla, nw)) 482 return (false); 483 break; 484 } 485 } 486 487 nlmsg_end(nw); 488 RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); 489 return (true); 490 } 491 492 static bool 493 rtnl_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) 494 { 495 RT_LOG(LOG_DEBUG2, "Got message type %d", hdr->nlmsg_type); 496 497 switch (hdr->nlmsg_type) { 498 case NL_RTM_NEWLINK: 499 case NL_RTM_DELLINK: 500 case NL_RTM_GETLINK: 501 return (rtnl_newlink_to_linux(hdr, nlp, nw)); 502 case NL_RTM_NEWADDR: 503 case NL_RTM_DELADDR: 504 return (rtnl_newaddr_to_linux(hdr, nlp, nw)); 505 case NL_RTM_NEWROUTE: 506 case NL_RTM_DELROUTE: 507 return (rtnl_newroute_to_linux(hdr, nlp, nw)); 508 case NL_RTM_NEWNEIGH: 509 case NL_RTM_DELNEIGH: 510 case NL_RTM_GETNEIGH: 511 return (rtnl_newneigh_to_linux(hdr, nlp, nw)); 512 default: 513 RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated", 514 hdr->nlmsg_type); 515 return (handle_default_out(hdr, nw)); 516 } 517 } 518 519 static bool 520 nlmsg_error_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) 521 { 522 if (!nlmsg_copy_header(hdr, nw)) 523 return (false); 524 525 struct nlmsgerr *nlerr; 526 nlerr = nlmsg_copy_next_header(hdr, nw, struct nlmsgerr); 527 nlerr->error = bsd_to_linux_errno(nlerr->error); 528 529 int copied_len = sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr); 530 if (hdr->nlmsg_len == copied_len) { 531 nlmsg_end(nw); 532 return (true); 533 } 534 535 /* 536 * CAP_ACK was not set. Original request needs to be translated. 537 * XXX: implement translation of the original message 538 */ 539 RT_LOG(LOG_DEBUG, "[WARN] Passing ack message type %d untranslated", 540 nlerr->msg.nlmsg_type); 541 char *dst_payload, *src_payload; 542 int copy_len = hdr->nlmsg_len - copied_len; 543 dst_payload = nlmsg_reserve_data(nw, NLMSG_ALIGN(copy_len), char); 544 545 src_payload = (char *)hdr + copied_len; 546 547 memcpy(dst_payload, src_payload, copy_len); 548 nlmsg_end(nw); 549 550 return (true); 551 } 552 553 static bool 554 nlmsg_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) 555 { 556 if (hdr->nlmsg_type < NLMSG_MIN_TYPE) { 557 switch (hdr->nlmsg_type) { 558 case NLMSG_ERROR: 559 return (nlmsg_error_to_linux(hdr, nlp, nw)); 560 case NLMSG_NOOP: 561 case NLMSG_DONE: 562 case NLMSG_OVERRUN: 563 return (handle_default_out(hdr, nw)); 564 default: 565 RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated", 566 hdr->nlmsg_type); 567 return (handle_default_out(hdr, nw)); 568 } 569 } 570 571 switch (nlp->nl_proto) { 572 case NETLINK_ROUTE: 573 return (rtnl_to_linux(hdr, nlp, nw)); 574 default: 575 return (handle_default_out(hdr, nw)); 576 } 577 } 578 579 static struct nl_buf * 580 nlmsgs_to_linux(struct nl_buf *orig, struct nlpcb *nlp, const struct ifnet *ifp) 581 { 582 struct nl_writer nw; 583 u_int offset, msglen; 584 585 if (__predict_false(!nl_writer_unicast(&nw, 586 orig->datalen + SCRATCH_BUFFER_SIZE, nlp, false))) 587 return (NULL); 588 589 nw.ifp = ifp; 590 /* Assume correct headers. Buffer IS mutable */ 591 for (offset = 0; 592 offset + sizeof(struct nlmsghdr) <= orig->datalen; 593 offset += msglen) { 594 struct nlmsghdr *hdr = (struct nlmsghdr *)&orig->data[offset]; 595 596 msglen = NLMSG_ALIGN(hdr->nlmsg_len); 597 if (!nlmsg_to_linux(hdr, nlp, &nw)) { 598 RT_LOG(LOG_DEBUG, "failed to process msg type %d", 599 hdr->nlmsg_type); 600 nl_buf_free(nw.buf); 601 return (NULL); 602 } 603 } 604 605 RT_LOG(LOG_DEBUG3, "%p: in %u bytes %u messages", __func__, 606 nw.buf->datalen, nw.num_messages); 607 608 return (nw.buf); 609 } 610 611 static struct linux_netlink_provider linux_netlink_v1 = { 612 .msgs_to_linux = nlmsgs_to_linux, 613 .msg_from_linux = nlmsg_from_linux, 614 }; 615 616 void 617 linux_netlink_register(void) 618 { 619 linux_netlink_p = &linux_netlink_v1; 620 } 621 622 void 623 linux_netlink_deregister(void) 624 { 625 linux_netlink_p = NULL; 626 } 627