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