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