1 /* $NetBSD: npf_inet.c,v 1.17 2012/09/16 13:47:41 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This material is based upon work partially supported by The 8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Various procotol related helper routines. 34 * 35 * This layer manipulates npf_cache_t structure i.e. caches requested headers 36 * and stores which information was cached in the information bit field. 37 * It is also responsibility of this layer to update or invalidate the cache 38 * on rewrites (e.g. by translation routines). 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.17 2012/09/16 13:47:41 rmind Exp $"); 43 44 #include <sys/param.h> 45 #include <sys/types.h> 46 47 #include <net/pfil.h> 48 #include <net/if.h> 49 #include <net/ethertypes.h> 50 #include <net/if_ether.h> 51 52 #include <netinet/in_systm.h> 53 #include <netinet/in.h> 54 #include <netinet/ip.h> 55 #include <netinet/ip6.h> 56 #include <netinet/tcp.h> 57 #include <netinet/udp.h> 58 #include <netinet/ip_icmp.h> 59 60 #include "npf_impl.h" 61 62 /* 63 * npf_fixup{16,32}_cksum: update IPv4 checksum. 64 */ 65 66 uint16_t 67 npf_fixup16_cksum(uint16_t cksum, uint16_t odatum, uint16_t ndatum) 68 { 69 uint32_t sum; 70 71 /* 72 * RFC 1624: 73 * HC' = ~(~HC + ~m + m') 74 */ 75 sum = ~ntohs(cksum) & 0xffff; 76 sum += (~ntohs(odatum) & 0xffff) + ntohs(ndatum); 77 sum = (sum >> 16) + (sum & 0xffff); 78 sum += (sum >> 16); 79 80 return htons(~sum & 0xffff); 81 } 82 83 uint16_t 84 npf_fixup32_cksum(uint16_t cksum, uint32_t odatum, uint32_t ndatum) 85 { 86 87 cksum = npf_fixup16_cksum(cksum, odatum & 0xffff, ndatum & 0xffff); 88 cksum = npf_fixup16_cksum(cksum, odatum >> 16, ndatum >> 16); 89 return cksum; 90 } 91 92 /* 93 * npf_addr_cksum: calculate checksum of the address, either IPv4 or IPv6. 94 */ 95 uint16_t 96 npf_addr_cksum(uint16_t cksum, int sz, npf_addr_t *oaddr, npf_addr_t *naddr) 97 { 98 uint32_t *oip32 = (uint32_t *)oaddr, *nip32 = (uint32_t *)naddr; 99 100 KASSERT(sz % sizeof(uint32_t) == 0); 101 do { 102 cksum = npf_fixup32_cksum(cksum, *oip32++, *nip32++); 103 sz -= sizeof(uint32_t); 104 } while (sz); 105 106 return cksum; 107 } 108 109 /* 110 * npf_addr_sum: provide IP address as a summed (if needed) 32-bit integer. 111 * Note: used for hash function. 112 */ 113 uint32_t 114 npf_addr_sum(const int sz, const npf_addr_t *a1, const npf_addr_t *a2) 115 { 116 uint32_t mix = 0; 117 int i; 118 119 KASSERT(sz > 0 && a1 != NULL && a2 != NULL); 120 121 for (i = 0; i < (sz >> 2); i++) { 122 mix += a1->s6_addr32[i]; 123 mix += a2->s6_addr32[i]; 124 } 125 return mix; 126 } 127 128 /* 129 * npf_addr_mask: apply the mask to a given address and store the result. 130 */ 131 void 132 npf_addr_mask(const npf_addr_t *addr, const npf_netmask_t mask, 133 const int alen, npf_addr_t *out) 134 { 135 const int nwords = alen >> 2; 136 uint_fast8_t length = mask; 137 138 /* Note: maximum length is 32 for IPv4 and 128 for IPv6. */ 139 KASSERT(length <= NPF_MAX_NETMASK); 140 141 for (int i = 0; i < nwords; i++) { 142 uint32_t wordmask; 143 144 if (length >= 32) { 145 wordmask = htonl(0xffffffff); 146 length -= 32; 147 } else if (length) { 148 wordmask = htonl(0xffffffff << (32 - length)); 149 length = 0; 150 } else { 151 wordmask = 0; 152 } 153 out->s6_addr32[i] = addr->s6_addr32[i] & wordmask; 154 } 155 } 156 157 /* 158 * npf_addr_cmp: compare two addresses, either IPv4 or IPv6. 159 * 160 * => Return 0 if equal and negative/positive if less/greater accordingly. 161 * => Ignore the mask, if NPF_NO_NETMASK is specified. 162 */ 163 int 164 npf_addr_cmp(const npf_addr_t *addr1, const npf_netmask_t mask1, 165 const npf_addr_t *addr2, const npf_netmask_t mask2, const int alen) 166 { 167 npf_addr_t realaddr1, realaddr2; 168 169 if (mask1 != NPF_NO_NETMASK) { 170 npf_addr_mask(addr1, mask1, alen, &realaddr1); 171 addr1 = &realaddr1; 172 } 173 if (mask2 != NPF_NO_NETMASK) { 174 npf_addr_mask(addr2, mask2, alen, &realaddr2); 175 addr2 = &realaddr2; 176 } 177 return memcmp(addr1, addr2, alen); 178 } 179 180 /* 181 * npf_tcpsaw: helper to fetch SEQ, ACK, WIN and return TCP data length. 182 * 183 * => Returns all values in host byte-order. 184 */ 185 int 186 npf_tcpsaw(const npf_cache_t *npc, tcp_seq *seq, tcp_seq *ack, uint32_t *win) 187 { 188 const struct tcphdr *th = &npc->npc_l4.tcp; 189 u_int thlen; 190 191 KASSERT(npf_iscached(npc, NPC_TCP)); 192 193 *seq = ntohl(th->th_seq); 194 *ack = ntohl(th->th_ack); 195 *win = (uint32_t)ntohs(th->th_win); 196 thlen = th->th_off << 2; 197 198 if (npf_iscached(npc, NPC_IP4)) { 199 const struct ip *ip = &npc->npc_ip.v4; 200 return ntohs(ip->ip_len) - npf_cache_hlen(npc) - thlen; 201 } else if (npf_iscached(npc, NPC_IP6)) { 202 const struct ip6_hdr *ip6 = &npc->npc_ip.v6; 203 return ntohs(ip6->ip6_plen) - thlen; 204 } 205 return 0; 206 } 207 208 /* 209 * npf_fetch_tcpopts: parse and return TCP options. 210 */ 211 bool 212 npf_fetch_tcpopts(const npf_cache_t *npc, nbuf_t *nbuf, 213 uint16_t *mss, int *wscale) 214 { 215 void *n_ptr = nbuf_dataptr(nbuf); 216 const struct tcphdr *th = &npc->npc_l4.tcp; 217 int topts_len, step; 218 uint16_t val16; 219 uint8_t val; 220 221 KASSERT(npf_iscached(npc, NPC_IP46)); 222 KASSERT(npf_iscached(npc, NPC_TCP)); 223 224 /* Determine if there are any TCP options, get their length. */ 225 topts_len = (th->th_off << 2) - sizeof(struct tcphdr); 226 if (topts_len <= 0) { 227 /* No options. */ 228 return false; 229 } 230 KASSERT(topts_len <= MAX_TCPOPTLEN); 231 232 /* First step: IP and TCP header up to options. */ 233 step = npf_cache_hlen(npc) + sizeof(struct tcphdr); 234 next: 235 if (nbuf_advfetch(&nbuf, &n_ptr, step, sizeof(val), &val)) { 236 return false; 237 } 238 239 switch (val) { 240 case TCPOPT_EOL: 241 /* Done. */ 242 return true; 243 case TCPOPT_NOP: 244 topts_len--; 245 step = 1; 246 break; 247 case TCPOPT_MAXSEG: 248 /* 249 * XXX: clean this mess. 250 */ 251 if (mss && *mss) { 252 val16 = *mss; 253 if (nbuf_advstore(&nbuf, &n_ptr, 2, 254 sizeof(val16), &val16)) 255 return false; 256 } else if (nbuf_advfetch(&nbuf, &n_ptr, 2, 257 sizeof(val16), &val16)) { 258 return false; 259 } 260 if (mss) { 261 *mss = val16; 262 } 263 topts_len -= TCPOLEN_MAXSEG; 264 step = sizeof(val16); 265 break; 266 case TCPOPT_WINDOW: 267 /* TCP Window Scaling (RFC 1323). */ 268 if (nbuf_advfetch(&nbuf, &n_ptr, 2, sizeof(val), &val)) { 269 return false; 270 } 271 *wscale = (val > TCP_MAX_WINSHIFT) ? TCP_MAX_WINSHIFT : val; 272 topts_len -= TCPOLEN_WINDOW; 273 step = sizeof(val); 274 break; 275 default: 276 if (nbuf_advfetch(&nbuf, &n_ptr, 1, sizeof(val), &val)) { 277 return false; 278 } 279 if (val < 2 || val > topts_len) { 280 return false; 281 } 282 topts_len -= val; 283 step = val - 1; 284 } 285 286 /* Any options left? */ 287 if (__predict_true(topts_len > 0)) { 288 goto next; 289 } 290 return true; 291 } 292 293 /* 294 * npf_fetch_ip: fetch, check and cache IP header. 295 */ 296 bool 297 npf_fetch_ip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) 298 { 299 uint8_t ver; 300 301 if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &ver)) { 302 return false; 303 } 304 305 switch (ver >> 4) { 306 case IPVERSION: { 307 struct ip *ip = &npc->npc_ip.v4; 308 309 /* Fetch IPv4 header. */ 310 if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(struct ip), ip)) { 311 return false; 312 } 313 314 /* Check header length and fragment offset. */ 315 if ((u_int)(ip->ip_hl << 2) < sizeof(struct ip)) { 316 return false; 317 } 318 if (ip->ip_off & ~htons(IP_DF | IP_RF)) { 319 /* Note fragmentation. */ 320 npc->npc_info |= NPC_IPFRAG; 321 } 322 323 /* Cache: layer 3 - IPv4. */ 324 npc->npc_alen = sizeof(struct in_addr); 325 npc->npc_srcip = (npf_addr_t *)&ip->ip_src; 326 npc->npc_dstip = (npf_addr_t *)&ip->ip_dst; 327 npc->npc_info |= NPC_IP4; 328 npc->npc_hlen = ip->ip_hl << 2; 329 npc->npc_next_proto = npc->npc_ip.v4.ip_p; 330 break; 331 } 332 333 case (IPV6_VERSION >> 4): { 334 struct ip6_hdr *ip6 = &npc->npc_ip.v6; 335 size_t hlen = sizeof(struct ip6_hdr); 336 struct ip6_ext ip6e; 337 338 /* Fetch IPv6 header and set initial next-protocol value. */ 339 if (nbuf_fetch_datum(nbuf, n_ptr, hlen, ip6)) { 340 return false; 341 } 342 npc->npc_next_proto = ip6->ip6_nxt; 343 npc->npc_hlen = hlen; 344 345 /* 346 * Advance by the length of the current header and 347 * prefetch the extension header. 348 */ 349 while (nbuf_advfetch(&nbuf, &n_ptr, hlen, 350 sizeof(struct ip6_ext), &ip6e) == 0) { 351 /* 352 * Determine whether we are going to continue. 353 */ 354 switch (npc->npc_next_proto) { 355 case IPPROTO_HOPOPTS: 356 case IPPROTO_DSTOPTS: 357 case IPPROTO_ROUTING: 358 hlen = (ip6e.ip6e_len + 1) << 3; 359 break; 360 case IPPROTO_FRAGMENT: 361 npc->npc_info |= NPC_IPFRAG; 362 hlen = sizeof(struct ip6_frag); 363 break; 364 case IPPROTO_AH: 365 hlen = (ip6e.ip6e_len + 2) << 2; 366 break; 367 default: 368 hlen = 0; 369 break; 370 } 371 372 if (!hlen) { 373 break; 374 } 375 npc->npc_next_proto = ip6e.ip6e_nxt; 376 npc->npc_hlen += hlen; 377 } 378 379 /* Cache: layer 3 - IPv6. */ 380 npc->npc_alen = sizeof(struct in6_addr); 381 npc->npc_srcip = (npf_addr_t *)&ip6->ip6_src; 382 npc->npc_dstip = (npf_addr_t *)&ip6->ip6_dst; 383 npc->npc_info |= NPC_IP6; 384 break; 385 } 386 default: 387 return false; 388 } 389 390 return true; 391 } 392 393 /* 394 * npf_fetch_tcp: fetch, check and cache TCP header. If necessary, 395 * fetch and cache layer 3 as well. 396 */ 397 bool 398 npf_fetch_tcp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) 399 { 400 struct tcphdr *th; 401 402 /* Must have IP header processed for its length and protocol. */ 403 if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) { 404 return false; 405 } 406 if (npf_cache_ipproto(npc) != IPPROTO_TCP) { 407 return false; 408 } 409 th = &npc->npc_l4.tcp; 410 411 /* Fetch TCP header. */ 412 if (nbuf_advfetch(&nbuf, &n_ptr, npf_cache_hlen(npc), 413 sizeof(struct tcphdr), th)) { 414 return false; 415 } 416 417 /* Cache: layer 4 - TCP. */ 418 npc->npc_info |= (NPC_LAYER4 | NPC_TCP); 419 return true; 420 } 421 422 /* 423 * npf_fetch_udp: fetch, check and cache UDP header. If necessary, 424 * fetch and cache layer 3 as well. 425 */ 426 bool 427 npf_fetch_udp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) 428 { 429 struct udphdr *uh; 430 u_int hlen; 431 432 /* Must have IP header processed for its length and protocol. */ 433 if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) { 434 return false; 435 } 436 if (npf_cache_ipproto(npc) != IPPROTO_UDP) { 437 return false; 438 } 439 uh = &npc->npc_l4.udp; 440 hlen = npf_cache_hlen(npc); 441 442 /* Fetch UDP header. */ 443 if (nbuf_advfetch(&nbuf, &n_ptr, hlen, sizeof(struct udphdr), uh)) { 444 return false; 445 } 446 447 /* Cache: layer 4 - UDP. */ 448 npc->npc_info |= (NPC_LAYER4 | NPC_UDP); 449 return true; 450 } 451 452 /* 453 * npf_fetch_icmp: fetch ICMP code, type and possible query ID. 454 */ 455 bool 456 npf_fetch_icmp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) 457 { 458 struct icmp *ic; 459 u_int hlen, iclen; 460 461 /* Must have IP header processed for its length and protocol. */ 462 if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) { 463 return false; 464 } 465 if (npf_cache_ipproto(npc) != IPPROTO_ICMP && 466 npf_cache_ipproto(npc) != IPPROTO_ICMPV6) { 467 return false; 468 } 469 ic = &npc->npc_l4.icmp; 470 hlen = npf_cache_hlen(npc); 471 472 /* Fetch basic ICMP header, up to the "data" point. */ 473 CTASSERT(offsetof(struct icmp, icmp_void) == 474 offsetof(struct icmp6_hdr, icmp6_data32)); 475 476 iclen = offsetof(struct icmp, icmp_void); 477 if (nbuf_advfetch(&nbuf, &n_ptr, hlen, iclen, ic)) { 478 return false; 479 } 480 481 /* Cache: layer 4 - ICMP. */ 482 npc->npc_info |= (NPC_LAYER4 | NPC_ICMP); 483 return true; 484 } 485 486 /* 487 * npf_cache_all: general routine to cache all relevant IP (v4 or v6) 488 * and TCP, UDP or ICMP headers. 489 */ 490 int 491 npf_cache_all(npf_cache_t *npc, nbuf_t *nbuf) 492 { 493 void *n_ptr = nbuf_dataptr(nbuf); 494 495 if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) { 496 return npc->npc_info; 497 } 498 if (npf_iscached(npc, NPC_IPFRAG)) { 499 return npc->npc_info; 500 } 501 switch (npf_cache_ipproto(npc)) { 502 case IPPROTO_TCP: 503 (void)npf_fetch_tcp(npc, nbuf, n_ptr); 504 break; 505 case IPPROTO_UDP: 506 (void)npf_fetch_udp(npc, nbuf, n_ptr); 507 break; 508 case IPPROTO_ICMP: 509 case IPPROTO_ICMPV6: 510 (void)npf_fetch_icmp(npc, nbuf, n_ptr); 511 break; 512 } 513 return npc->npc_info; 514 } 515 516 /* 517 * npf_rwrip: rewrite required IP address, update the cache. 518 */ 519 bool 520 npf_rwrip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di, 521 npf_addr_t *addr) 522 { 523 npf_addr_t *oaddr; 524 u_int offby; 525 526 KASSERT(npf_iscached(npc, NPC_IP46)); 527 528 if (di == PFIL_OUT) { 529 /* Rewrite source address, if outgoing. */ 530 offby = offsetof(struct ip, ip_src); 531 oaddr = npc->npc_srcip; 532 } else { 533 /* Rewrite destination, if incoming. */ 534 offby = offsetof(struct ip, ip_dst); 535 oaddr = npc->npc_dstip; 536 } 537 538 /* Advance to the address and rewrite it. */ 539 if (nbuf_advstore(&nbuf, &n_ptr, offby, npc->npc_alen, addr)) 540 return false; 541 542 /* Cache: IP address. */ 543 memcpy(oaddr, addr, npc->npc_alen); 544 return true; 545 } 546 547 /* 548 * npf_rwrport: rewrite required TCP/UDP port, update the cache. 549 */ 550 bool 551 npf_rwrport(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di, 552 in_port_t port) 553 { 554 const int proto = npf_cache_ipproto(npc); 555 u_int offby = npf_cache_hlen(npc); 556 in_port_t *oport; 557 558 KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP)); 559 KASSERT(proto == IPPROTO_TCP || proto == IPPROTO_UDP); 560 561 /* Offset to the port and pointer in the cache. */ 562 if (proto == IPPROTO_TCP) { 563 struct tcphdr *th = &npc->npc_l4.tcp; 564 if (di == PFIL_OUT) { 565 CTASSERT(offsetof(struct tcphdr, th_sport) == 0); 566 oport = &th->th_sport; 567 } else { 568 offby += offsetof(struct tcphdr, th_dport); 569 oport = &th->th_dport; 570 } 571 } else { 572 struct udphdr *uh = &npc->npc_l4.udp; 573 if (di == PFIL_OUT) { 574 CTASSERT(offsetof(struct udphdr, uh_sport) == 0); 575 oport = &uh->uh_sport; 576 } else { 577 offby += offsetof(struct udphdr, uh_dport); 578 oport = &uh->uh_dport; 579 } 580 } 581 582 /* Advance and rewrite the port. */ 583 if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(in_port_t), &port)) 584 return false; 585 586 /* Cache: TCP/UDP port. */ 587 *oport = port; 588 return true; 589 } 590 591 /* 592 * npf_rwrcksum: rewrite IPv4 and/or TCP/UDP checksum, update the cache. 593 */ 594 bool 595 npf_rwrcksum(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di, 596 npf_addr_t *addr, in_port_t port) 597 { 598 const int proto = npf_cache_ipproto(npc); 599 npf_addr_t *oaddr; 600 in_port_t *oport; 601 uint16_t *cksum; 602 u_int offby; 603 604 /* Checksum update for IPv4 header. */ 605 if (npf_iscached(npc, NPC_IP4)) { 606 struct ip *ip = &npc->npc_ip.v4; 607 uint16_t ipsum; 608 609 oaddr = (di == PFIL_OUT) ? npc->npc_srcip : npc->npc_dstip; 610 ipsum = npf_addr_cksum(ip->ip_sum, npc->npc_alen, oaddr, addr); 611 612 /* Advance to the IPv4 checksum and rewrite it. */ 613 offby = offsetof(struct ip, ip_sum); 614 if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(ipsum), &ipsum)) 615 return false; 616 617 ip->ip_sum = ipsum; 618 offby = npf_cache_hlen(npc) - offby; 619 } else { 620 /* No checksum for IPv6. */ 621 KASSERT(npf_iscached(npc, NPC_IP6)); 622 oaddr = NULL; 623 offby = 0; 624 return false; /* XXX: Not yet supported. */ 625 } 626 627 /* Determine whether TCP/UDP checksum update is needed. */ 628 if (proto == IPPROTO_ICMP || port == 0) { 629 return true; 630 } 631 KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP)); 632 633 /* Calculate TCP/UDP checksum. */ 634 if (proto == IPPROTO_TCP) { 635 struct tcphdr *th = &npc->npc_l4.tcp; 636 637 cksum = &th->th_sum; 638 offby += offsetof(struct tcphdr, th_sum); 639 oport = (di == PFIL_OUT) ? &th->th_sport : &th->th_dport; 640 } else { 641 struct udphdr *uh = &npc->npc_l4.udp; 642 643 KASSERT(proto == IPPROTO_UDP); 644 cksum = &uh->uh_sum; 645 if (*cksum == 0) { 646 /* No need to update. */ 647 return true; 648 } 649 offby += offsetof(struct udphdr, uh_sum); 650 oport = (di == PFIL_OUT) ? &uh->uh_sport : &uh->uh_dport; 651 } 652 *cksum = npf_addr_cksum(*cksum, npc->npc_alen, oaddr, addr); 653 *cksum = npf_fixup16_cksum(*cksum, *oport, port); 654 655 /* Advance to TCP/UDP checksum and rewrite it. */ 656 if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(uint16_t), cksum)) { 657 return false; 658 } 659 return true; 660 } 661 662 #if defined(DDB) || defined(_NPF_TESTING) 663 664 void 665 npf_addr_dump(const npf_addr_t *addr) 666 { 667 printf("IP[%x:%x:%x:%x]\n", 668 addr->s6_addr32[0], addr->s6_addr32[1], 669 addr->s6_addr32[2], addr->s6_addr32[3]); 670 } 671 672 #endif 673