1 2 /* 3 * Copyright (C) 2012 by Darren Reed. 4 * 5 * See the IPFILTER.LICENCE file for details on licencing. 6 * 7 * $Id$ 8 */ 9 #if !defined(lint) 10 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 11 static const char rcsid[] = "@(#)$Id$"; 12 #endif 13 14 #include "ipf.h" 15 #include "md5.h" 16 #include "ipt.h" 17 18 ipf_main_softc_t ipfmain; 19 20 static struct ifnet **ifneta = NULL; 21 static int nifs = 0; 22 23 struct rtentry; 24 25 static void ipf_setifpaddr(struct ifnet *, char *); 26 void init_ifp(void); 27 static int no_output(struct ifnet *, struct mbuf *, 28 struct sockaddr *, struct rtentry *); 29 static int write_output(struct ifnet *, struct mbuf *, 30 struct sockaddr *, struct rtentry *); 31 32 struct ifaddr { 33 struct sockaddr_storage ifa_addr; 34 }; 35 36 int 37 ipfattach(softc) 38 ipf_main_softc_t *softc; 39 { 40 return (0); 41 } 42 43 44 int 45 ipfdetach(softc) 46 ipf_main_softc_t *softc; 47 { 48 return (0); 49 } 50 51 52 /* 53 * Filter ioctl interface. 54 */ 55 int 56 ipfioctl(softc, dev, cmd, data, mode) 57 ipf_main_softc_t *softc; 58 int dev; 59 ioctlcmd_t cmd; 60 caddr_t data; 61 int mode; 62 { 63 int error = 0, unit = 0, uid; 64 65 uid = getuid(); 66 unit = dev; 67 68 SPL_NET(s); 69 70 error = ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, NULL); 71 if (error != -1) { 72 SPL_X(s); 73 return (error); 74 } 75 SPL_X(s); 76 return (error); 77 } 78 79 80 void 81 ipf_forgetifp(softc, ifp) 82 ipf_main_softc_t *softc; 83 void *ifp; 84 { 85 register frentry_t *f; 86 87 WRITE_ENTER(&softc->ipf_mutex); 88 for (f = softc->ipf_acct[0][softc->ipf_active]; (f != NULL); 89 f = f->fr_next) 90 if (f->fr_ifa == ifp) 91 f->fr_ifa = (void *)-1; 92 for (f = softc->ipf_acct[1][softc->ipf_active]; (f != NULL); 93 f = f->fr_next) 94 if (f->fr_ifa == ifp) 95 f->fr_ifa = (void *)-1; 96 for (f = softc->ipf_rules[0][softc->ipf_active]; (f != NULL); 97 f = f->fr_next) 98 if (f->fr_ifa == ifp) 99 f->fr_ifa = (void *)-1; 100 for (f = softc->ipf_rules[1][softc->ipf_active]; (f != NULL); 101 f = f->fr_next) 102 if (f->fr_ifa == ifp) 103 f->fr_ifa = (void *)-1; 104 RWLOCK_EXIT(&softc->ipf_mutex); 105 ipf_nat_sync(softc, ifp); 106 ipf_lookup_sync(softc, ifp); 107 } 108 109 110 static int 111 no_output(ifp, m, s, rt) 112 struct rtentry *rt; 113 struct ifnet *ifp; 114 struct mbuf *m; 115 struct sockaddr *s; 116 { 117 return (0); 118 } 119 120 121 static int 122 write_output(ifp, m, s, rt) 123 struct rtentry *rt; 124 struct ifnet *ifp; 125 struct mbuf *m; 126 struct sockaddr *s; 127 { 128 char fname[32]; 129 mb_t *mb; 130 ip_t *ip; 131 int fd; 132 133 mb = (mb_t *)m; 134 ip = MTOD(mb, ip_t *); 135 136 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ 137 defined(__FreeBSD__) 138 sprintf(fname, "/tmp/%s", ifp->if_xname); 139 #else 140 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); 141 #endif 142 fd = open(fname, O_WRONLY|O_APPEND); 143 if (fd == -1) { 144 perror("open"); 145 return (-1); 146 } 147 write(fd, (char *)ip, ntohs(ip->ip_len)); 148 close(fd); 149 return (0); 150 } 151 152 153 static void 154 ipf_setifpaddr(ifp, addr) 155 struct ifnet *ifp; 156 char *addr; 157 { 158 struct ifaddr *ifa; 159 160 #if defined(__NetBSD__) || defined(__FreeBSD__) 161 if (ifp->if_addrlist.tqh_first != NULL) 162 #else 163 if (ifp->if_addrlist != NULL) 164 #endif 165 return; 166 167 ifa = (struct ifaddr *)malloc(sizeof(*ifa)); 168 #if defined(__NetBSD__) || defined(__FreeBSD__) 169 ifp->if_addrlist.tqh_first = ifa; 170 #else 171 ifp->if_addrlist = ifa; 172 #endif 173 174 if (ifa != NULL) { 175 struct sockaddr_in *sin; 176 177 sin = (struct sockaddr_in *)&ifa->ifa_addr; 178 #ifdef USE_INET6 179 if (index(addr, ':') != NULL) { 180 struct sockaddr_in6 *sin6; 181 182 sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr; 183 sin6->sin6_family = AF_INET6; 184 /* Abort if bad address. */ 185 switch (inet_pton(AF_INET6, addr, &sin6->sin6_addr)) 186 { 187 case 1: 188 break; 189 case -1: 190 perror("inet_pton"); 191 abort(); 192 break; 193 default: 194 abort(); 195 break; 196 } 197 } else 198 #endif 199 { 200 sin->sin_family = AF_INET; 201 sin->sin_addr.s_addr = inet_addr(addr); 202 if (sin->sin_addr.s_addr == 0) 203 abort(); 204 } 205 } 206 } 207 208 struct ifnet * 209 get_unit(name, family) 210 char *name; 211 int family; 212 { 213 struct ifnet *ifp, **ifpp, **old_ifneta; 214 char *addr; 215 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ 216 defined(__FreeBSD__) 217 218 if (!*name) 219 return (NULL); 220 221 if (name == NULL) 222 name = "anon0"; 223 224 addr = strchr(name, '='); 225 if (addr != NULL) 226 *addr++ = '\0'; 227 228 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { 229 if (!strcmp(name, ifp->if_xname)) { 230 if (addr != NULL) 231 ipf_setifpaddr(ifp, addr); 232 return (ifp); 233 } 234 } 235 #else 236 char *s, ifname[LIFNAMSIZ+1]; 237 238 if (name == NULL) 239 name = "anon0"; 240 241 addr = strchr(name, '='); 242 if (addr != NULL) 243 *addr++ = '\0'; 244 245 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { 246 COPYIFNAME(family, ifp, ifname); 247 if (!strcmp(name, ifname)) { 248 if (addr != NULL) 249 ipf_setifpaddr(ifp, addr); 250 return (ifp); 251 } 252 } 253 #endif 254 255 if (!ifneta) { 256 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2); 257 if (!ifneta) 258 return (NULL); 259 ifneta[1] = NULL; 260 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp)); 261 if (!ifneta[0]) { 262 free(ifneta); 263 return (NULL); 264 } 265 nifs = 1; 266 } else { 267 old_ifneta = ifneta; 268 nifs++; 269 ifneta = (struct ifnet **)reallocarray(ifneta, nifs + 1, 270 sizeof(ifp)); 271 if (!ifneta) { 272 free(old_ifneta); 273 nifs = 0; 274 return (NULL); 275 } 276 ifneta[nifs] = NULL; 277 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp)); 278 if (!ifneta[nifs - 1]) { 279 nifs--; 280 return (NULL); 281 } 282 } 283 ifp = ifneta[nifs - 1]; 284 285 #if defined(__NetBSD__) || defined(__FreeBSD__) 286 TAILQ_INIT(&ifp->if_addrlist); 287 #endif 288 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ 289 defined(__FreeBSD__) 290 (void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname)); 291 #else 292 s = name + strlen(name) - 1; 293 for (; s > name; s--) { 294 if (!ISDIGIT(*s)) { 295 s++; 296 break; 297 } 298 } 299 300 if ((s > name) && (*s != 0) && ISDIGIT(*s)) { 301 ifp->if_unit = atoi(s); 302 ifp->if_name = (char *)malloc(s - name + 1); 303 (void) strncpy(ifp->if_name, name, s - name); 304 ifp->if_name[s - name] = '\0'; 305 } else { 306 ifp->if_name = strdup(name); 307 ifp->if_unit = -1; 308 } 309 #endif 310 ifp->if_output = (void *)no_output; 311 312 if (addr != NULL) { 313 ipf_setifpaddr(ifp, addr); 314 } 315 316 return (ifp); 317 } 318 319 320 char * 321 get_ifname(ifp) 322 struct ifnet *ifp; 323 { 324 static char ifname[LIFNAMSIZ]; 325 326 #if defined(__NetBSD__) || defined(__FreeBSD__) 327 sprintf(ifname, "%s", ifp->if_xname); 328 #else 329 if (ifp->if_unit != -1) 330 sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit); 331 else 332 strcpy(ifname, ifp->if_name); 333 #endif 334 return (ifname); 335 } 336 337 338 339 void 340 init_ifp() 341 { 342 struct ifnet *ifp, **ifpp; 343 char fname[32]; 344 int fd; 345 346 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ 347 defined(__FreeBSD__) 348 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { 349 ifp->if_output = (void *)write_output; 350 sprintf(fname, "/tmp/%s", ifp->if_xname); 351 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); 352 if (fd == -1) 353 perror("open"); 354 else 355 close(fd); 356 } 357 #else 358 359 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { 360 ifp->if_output = (void *)write_output; 361 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); 362 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); 363 if (fd == -1) 364 perror("open"); 365 else 366 close(fd); 367 } 368 #endif 369 } 370 371 372 int 373 ipf_fastroute(m, mpp, fin, fdp) 374 mb_t *m, **mpp; 375 fr_info_t *fin; 376 frdest_t *fdp; 377 { 378 struct ifnet *ifp; 379 ip_t *ip = fin->fin_ip; 380 frdest_t node; 381 int error = 0; 382 frentry_t *fr; 383 void *sifp; 384 int sout; 385 386 sifp = fin->fin_ifp; 387 sout = fin->fin_out; 388 fr = fin->fin_fr; 389 ip->ip_sum = 0; 390 391 if (!(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) && 392 (fdp->fd_type == FRD_DSTLIST)) { 393 bzero(&node, sizeof(node)); 394 ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node); 395 fdp = &node; 396 } 397 ifp = fdp->fd_ptr; 398 399 if (ifp == NULL) 400 return (0; /* no routing table out here */); 401 402 if (fin->fin_out == 0) { 403 fin->fin_ifp = ifp; 404 fin->fin_out = 1; 405 (void) ipf_acctpkt(fin, NULL); 406 fin->fin_fr = NULL; 407 if (!fr || !(fr->fr_flags & FR_RETMASK)) { 408 u_32_t pass; 409 410 (void) ipf_state_check(fin, &pass); 411 } 412 413 switch (ipf_nat_checkout(fin, NULL)) 414 { 415 case 0 : 416 break; 417 case 1 : 418 ip->ip_sum = 0; 419 break; 420 case -1 : 421 error = -1; 422 goto done; 423 break; 424 } 425 426 } 427 428 m->mb_ifp = ifp; 429 printpacket(fin->fin_out, m); 430 431 (*ifp->if_output)(ifp, (void *)m, NULL, 0); 432 done: 433 fin->fin_ifp = sifp; 434 fin->fin_out = sout; 435 return (error); 436 } 437 438 439 int 440 ipf_send_reset(fin) 441 fr_info_t *fin; 442 { 443 ipfkverbose("- TCP RST sent\n"); 444 return (0); 445 } 446 447 448 int 449 ipf_send_icmp_err(type, fin, dst) 450 int type; 451 fr_info_t *fin; 452 int dst; 453 { 454 ipfkverbose("- ICMP unreachable sent\n"); 455 return (0); 456 } 457 458 459 void 460 m_freem(m) 461 mb_t *m; 462 { 463 return; 464 } 465 466 467 void 468 m_copydata(m, off, len, cp) 469 mb_t *m; 470 int off, len; 471 caddr_t cp; 472 { 473 bcopy((char *)m + off, cp, len); 474 } 475 476 477 int 478 ipfuiomove(buf, len, rwflag, uio) 479 caddr_t buf; 480 int len, rwflag; 481 struct uio *uio; 482 { 483 int left, ioc, num, offset; 484 struct iovec *io; 485 char *start; 486 487 if (rwflag == UIO_READ) { 488 left = len; 489 ioc = 0; 490 491 offset = uio->uio_offset; 492 493 while ((left > 0) && (ioc < uio->uio_iovcnt)) { 494 io = uio->uio_iov + ioc; 495 num = io->iov_len; 496 if (num > left) 497 num = left; 498 start = (char *)io->iov_base + offset; 499 if (start > (char *)io->iov_base + io->iov_len) { 500 offset -= io->iov_len; 501 ioc++; 502 continue; 503 } 504 bcopy(buf, start, num); 505 uio->uio_resid -= num; 506 uio->uio_offset += num; 507 left -= num; 508 if (left > 0) 509 ioc++; 510 } 511 if (left > 0) 512 return (EFAULT); 513 } 514 return (0); 515 } 516 517 518 u_32_t 519 ipf_newisn(fin) 520 fr_info_t *fin; 521 { 522 static int iss_seq_off = 0; 523 u_char hash[16]; 524 u_32_t newiss; 525 MD5_CTX ctx; 526 527 /* 528 * Compute the base value of the ISS. It is a hash 529 * of (saddr, sport, daddr, dport, secret). 530 */ 531 MD5Init(&ctx); 532 533 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 534 sizeof(fin->fin_fi.fi_src)); 535 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 536 sizeof(fin->fin_fi.fi_dst)); 537 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 538 539 /* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */ 540 541 MD5Final(hash, &ctx); 542 543 memcpy(&newiss, hash, sizeof(newiss)); 544 545 /* 546 * Now increment our "timer", and add it in to 547 * the computed value. 548 * 549 * XXX Use `addin'? 550 * XXX TCP_ISSINCR too large to use? 551 */ 552 iss_seq_off += 0x00010000; 553 newiss += iss_seq_off; 554 return (newiss); 555 } 556 557 558 /* ------------------------------------------------------------------------ */ 559 /* Function: ipf_nextipid */ 560 /* Returns: int - 0 == success, -1 == error (packet should be dropped) */ 561 /* Parameters: fin(I) - pointer to packet information */ 562 /* */ 563 /* Returns the next IPv4 ID to use for this packet. */ 564 /* ------------------------------------------------------------------------ */ 565 inline u_short 566 ipf_nextipid(fin) 567 fr_info_t *fin; 568 { 569 static u_short ipid = 0; 570 ipf_main_softc_t *softc = fin->fin_main_soft; 571 u_short id; 572 573 MUTEX_ENTER(&softc->ipf_rw); 574 if (fin->fin_pktnum != 0) { 575 /* 576 * The -1 is for aligned test results. 577 */ 578 id = (fin->fin_pktnum - 1) & 0xffff; 579 } else { 580 } 581 id = ipid++; 582 MUTEX_EXIT(&softc->ipf_rw); 583 584 return (id); 585 } 586 587 588 inline int 589 ipf_checkv4sum(fin) 590 fr_info_t *fin; 591 { 592 593 if (fin->fin_flx & FI_SHORT) 594 return (1); 595 596 if (ipf_checkl4sum(fin) == -1) { 597 fin->fin_flx |= FI_BAD; 598 return (-1); 599 } 600 return (0); 601 } 602 603 604 #ifdef USE_INET6 605 inline int 606 ipf_checkv6sum(fin) 607 fr_info_t *fin; 608 { 609 if (fin->fin_flx & FI_SHORT) 610 return (1); 611 612 if (ipf_checkl4sum(fin) == -1) { 613 fin->fin_flx |= FI_BAD; 614 return (-1); 615 } 616 return (0); 617 } 618 #endif 619 620 621 #if 0 622 /* 623 * See above for description, except that all addressing is in user space. 624 */ 625 int 626 copyoutptr(softc, src, dst, size) 627 void *src, *dst; 628 size_t size; 629 { 630 caddr_t ca; 631 632 bcopy(dst, (char *)&ca, sizeof(ca)); 633 bcopy(src, ca, size); 634 return (0); 635 } 636 637 638 /* 639 * See above for description, except that all addressing is in user space. 640 */ 641 int 642 copyinptr(src, dst, size) 643 void *src, *dst; 644 size_t size; 645 { 646 caddr_t ca; 647 648 bcopy(src, (char *)&ca, sizeof(ca)); 649 bcopy(ca, dst, size); 650 return (0); 651 } 652 #endif 653 654 655 /* 656 * return the first IP Address associated with an interface 657 */ 658 int 659 ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask) 660 ipf_main_softc_t *softc; 661 int v, atype; 662 void *ifptr; 663 i6addr_t *inp, *inpmask; 664 { 665 struct ifnet *ifp = ifptr; 666 struct ifaddr *ifa; 667 668 #if defined(__NetBSD__) || defined(__FreeBSD__) 669 ifa = ifp->if_addrlist.tqh_first; 670 #else 671 ifa = ifp->if_addrlist; 672 #endif 673 if (ifa != NULL) { 674 if (v == 4) { 675 struct sockaddr_in *sin, mask; 676 677 mask.sin_addr.s_addr = 0xffffffff; 678 679 sin = (struct sockaddr_in *)&ifa->ifa_addr; 680 681 return (ipf_ifpfillv4addr(atype, sin, &mask, 682 &inp->in4, &inpmask->in4)); 683 } 684 #ifdef USE_INET6 685 if (v == 6) { 686 struct sockaddr_in6 *sin6, mask; 687 688 sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr; 689 ((i6addr_t *)&mask.sin6_addr)->i6[0] = 0xffffffff; 690 ((i6addr_t *)&mask.sin6_addr)->i6[1] = 0xffffffff; 691 ((i6addr_t *)&mask.sin6_addr)->i6[2] = 0xffffffff; 692 ((i6addr_t *)&mask.sin6_addr)->i6[3] = 0xffffffff; 693 return (ipf_ifpfillv6addr(atype, sin6, &mask, 694 inp, inpmask)); 695 } 696 #endif 697 } 698 return (0); 699 } 700 701 702 /* 703 * This function is not meant to be random, rather just produce a 704 * sequence of numbers that isn't linear to show "randomness". 705 */ 706 u_32_t 707 ipf_random() 708 { 709 static unsigned int last = 0xa5a5a5a5; 710 static int calls = 0; 711 int number; 712 713 calls++; 714 715 /* 716 * These are deliberately chosen to ensure that there is some 717 * attempt to test whether the output covers the range in test n18. 718 */ 719 switch (calls) 720 { 721 case 1 : 722 number = 0; 723 break; 724 case 2 : 725 number = 4; 726 break; 727 case 3 : 728 number = 3999; 729 break; 730 case 4 : 731 number = 4000; 732 break; 733 case 5 : 734 number = 48999; 735 break; 736 case 6 : 737 number = 49000; 738 break; 739 default : 740 number = last; 741 last *= calls; 742 last++; 743 number ^= last; 744 break; 745 } 746 return (number); 747 } 748 749 750 int 751 ipf_verifysrc(fin) 752 fr_info_t *fin; 753 { 754 return (1); 755 } 756 757 758 int 759 ipf_inject(fin, m) 760 fr_info_t *fin; 761 mb_t *m; 762 { 763 FREE_MB_T(m); 764 765 return (0); 766 } 767 768 769 u_int 770 ipf_pcksum(fin, hlen, sum) 771 fr_info_t *fin; 772 int hlen; 773 u_int sum; 774 { 775 u_short *sp; 776 u_int sum2; 777 int slen; 778 779 slen = fin->fin_plen - hlen; 780 sp = (u_short *)((u_char *)fin->fin_ip + hlen); 781 782 for (; slen > 1; slen -= 2) 783 sum += *sp++; 784 if (slen) 785 sum += ntohs(*(u_char *)sp << 8); 786 while (sum > 0xffff) 787 sum = (sum & 0xffff) + (sum >> 16); 788 sum2 = (u_short)(~sum & 0xffff); 789 790 return (sum2); 791 } 792 793 794 void * 795 ipf_pullup(m, fin, plen) 796 mb_t *m; 797 fr_info_t *fin; 798 int plen; 799 { 800 if (M_LEN(m) >= plen) 801 return (fin->fin_ip); 802 803 /* 804 * Fake ipf_pullup failing 805 */ 806 fin->fin_reason = FRB_PULLUP; 807 *fin->fin_mp = NULL; 808 fin->fin_m = NULL; 809 fin->fin_ip = NULL; 810 return (NULL); 811 } 812