ip_fil.c revision 170268
1/* $FreeBSD: head/contrib/ipfilter/ip_fil.c 170268 2007-06-04 02:54:36Z 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.16 2007/05/28 11:56:22 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__) 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(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) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ 433 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ 434 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) 435 (void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname)); 436#else 437 for (s = name; *s && !ISDIGIT(*s); s++) 438 ; 439 if (*s && ISDIGIT(*s)) { 440 ifp->if_unit = atoi(s); 441 ifp->if_name = (char *)malloc(s - name + 1); 442 (void) strncpy(ifp->if_name, name, s - name); 443 ifp->if_name[s - name] = '\0'; 444 } else { 445 ifp->if_name = strdup(name); 446 ifp->if_unit = -1; 447 } 448#endif 449 ifp->if_output = (void *)no_output; 450 451 if (addr != NULL) { 452 fr_setifpaddr(ifp, addr); 453 } 454 455 return ifp; 456} 457 458 459char *get_ifname(ifp) 460struct ifnet *ifp; 461{ 462 static char ifname[LIFNAMSIZ]; 463 464#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \ 465 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) 466 sprintf(ifname, "%s", ifp->if_xname); 467#else 468 sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit); 469#endif 470 return ifname; 471} 472 473 474 475void init_ifp() 476{ 477 struct ifnet *ifp, **ifpp; 478 char fname[32]; 479 int fd; 480 481#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ 482 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ 483 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) 484 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { 485 ifp->if_output = (void *)write_output; 486 sprintf(fname, "/tmp/%s", ifp->if_xname); 487 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); 488 if (fd == -1) 489 perror("open"); 490 else 491 close(fd); 492 } 493#else 494 495 for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { 496 ifp->if_output = write_output; 497 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); 498 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); 499 if (fd == -1) 500 perror("open"); 501 else 502 close(fd); 503 } 504#endif 505} 506 507 508int fr_fastroute(m, mpp, fin, fdp) 509mb_t *m, **mpp; 510fr_info_t *fin; 511frdest_t *fdp; 512{ 513 struct ifnet *ifp = fdp->fd_ifp; 514 ip_t *ip = fin->fin_ip; 515 int error = 0; 516 frentry_t *fr; 517 void *sifp; 518 519 if (!ifp) 520 return 0; /* no routing table out here */ 521 522 fr = fin->fin_fr; 523 ip->ip_sum = 0; 524 525 if (fin->fin_out == 0) { 526 sifp = fin->fin_ifp; 527 fin->fin_ifp = ifp; 528 fin->fin_out = 1; 529 (void) fr_acctpkt(fin, NULL); 530 fin->fin_fr = NULL; 531 if (!fr || !(fr->fr_flags & FR_RETMASK)) { 532 u_32_t pass; 533 534 (void) fr_checkstate(fin, &pass); 535 } 536 537 switch (fr_checknatout(fin, NULL)) 538 { 539 case 0 : 540 break; 541 case 1 : 542 ip->ip_sum = 0; 543 break; 544 case -1 : 545 error = -1; 546 goto done; 547 break; 548 } 549 550 fin->fin_ifp = sifp; 551 fin->fin_out = 0; 552 } 553 554#if defined(__sgi) && (IRIX < 60500) 555 (*ifp->if_output)(ifp, (void *)ip, NULL); 556# if TRU64 >= 1885 557 (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0); 558# else 559 (*ifp->if_output)(ifp, (void *)m, NULL, 0); 560# endif 561#endif 562done: 563 return error; 564} 565 566 567int fr_send_reset(fin) 568fr_info_t *fin; 569{ 570 verbose("- TCP RST sent\n"); 571 return 0; 572} 573 574 575int fr_send_icmp_err(type, fin, dst) 576int type; 577fr_info_t *fin; 578int dst; 579{ 580 verbose("- ICMP unreachable sent\n"); 581 return 0; 582} 583 584 585void frsync(ifp) 586void *ifp; 587{ 588 return; 589} 590 591 592void m_freem(m) 593mb_t *m; 594{ 595 return; 596} 597 598 599void m_copydata(m, off, len, cp) 600mb_t *m; 601int off, len; 602caddr_t cp; 603{ 604 bcopy((char *)m + off, cp, len); 605} 606 607 608int ipfuiomove(buf, len, rwflag, uio) 609caddr_t buf; 610int len, rwflag; 611struct uio *uio; 612{ 613 int left, ioc, num, offset; 614 struct iovec *io; 615 char *start; 616 617 if (rwflag == UIO_READ) { 618 left = len; 619 ioc = 0; 620 621 offset = uio->uio_offset; 622 623 while ((left > 0) && (ioc < uio->uio_iovcnt)) { 624 io = uio->uio_iov + ioc; 625 num = io->iov_len; 626 if (num > left) 627 num = left; 628 start = (char *)io->iov_base + offset; 629 if (start > (char *)io->iov_base + io->iov_len) { 630 offset -= io->iov_len; 631 ioc++; 632 continue; 633 } 634 bcopy(buf, start, num); 635 uio->uio_resid -= num; 636 uio->uio_offset += num; 637 left -= num; 638 if (left > 0) 639 ioc++; 640 } 641 if (left > 0) 642 return EFAULT; 643 } 644 return 0; 645} 646 647 648u_32_t fr_newisn(fin) 649fr_info_t *fin; 650{ 651 static int iss_seq_off = 0; 652 u_char hash[16]; 653 u_32_t newiss; 654 MD5_CTX ctx; 655 656 /* 657 * Compute the base value of the ISS. It is a hash 658 * of (saddr, sport, daddr, dport, secret). 659 */ 660 MD5Init(&ctx); 661 662 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 663 sizeof(fin->fin_fi.fi_src)); 664 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 665 sizeof(fin->fin_fi.fi_dst)); 666 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 667 668 /* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */ 669 670 MD5Final(hash, &ctx); 671 672 memcpy(&newiss, hash, sizeof(newiss)); 673 674 /* 675 * Now increment our "timer", and add it in to 676 * the computed value. 677 * 678 * XXX Use `addin'? 679 * XXX TCP_ISSINCR too large to use? 680 */ 681 iss_seq_off += 0x00010000; 682 newiss += iss_seq_off; 683 return newiss; 684} 685 686 687/* ------------------------------------------------------------------------ */ 688/* Function: fr_nextipid */ 689/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 690/* Parameters: fin(I) - pointer to packet information */ 691/* */ 692/* Returns the next IPv4 ID to use for this packet. */ 693/* ------------------------------------------------------------------------ */ 694INLINE u_short fr_nextipid(fin) 695fr_info_t *fin; 696{ 697 static u_short ipid = 0; 698 u_short id; 699 700 MUTEX_ENTER(&ipf_rw); 701 id = ipid++; 702 MUTEX_EXIT(&ipf_rw); 703 704 return id; 705} 706 707 708INLINE void fr_checkv4sum(fin) 709fr_info_t *fin; 710{ 711 if (fr_checkl4sum(fin) == -1) 712 fin->fin_flx |= FI_BAD; 713} 714 715 716#ifdef USE_INET6 717INLINE void fr_checkv6sum(fin) 718fr_info_t *fin; 719{ 720 if (fr_checkl4sum(fin) == -1) 721 fin->fin_flx |= FI_BAD; 722} 723#endif 724 725 726/* 727 * See above for description, except that all addressing is in user space. 728 */ 729int copyoutptr(src, dst, size) 730void *src, *dst; 731size_t size; 732{ 733 caddr_t ca; 734 735 bcopy(dst, (char *)&ca, sizeof(ca)); 736 bcopy(src, ca, size); 737 return 0; 738} 739 740 741/* 742 * See above for description, except that all addressing is in user space. 743 */ 744int copyinptr(src, dst, size) 745void *src, *dst; 746size_t size; 747{ 748 caddr_t ca; 749 750 bcopy(src, (char *)&ca, sizeof(ca)); 751 bcopy(ca, dst, size); 752 return 0; 753} 754 755 756/* 757 * return the first IP Address associated with an interface 758 */ 759int fr_ifpaddr(v, atype, ifptr, inp, inpmask) 760int v, atype; 761void *ifptr; 762struct in_addr *inp, *inpmask; 763{ 764 struct ifnet *ifp = ifptr; 765#ifdef __sgi 766 struct in_ifaddr *ifa; 767#else 768 struct ifaddr *ifa; 769#endif 770 771#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) 772 ifa = ifp->if_addrlist.tqh_first; 773#else 774# ifdef __sgi 775 ifa = (struct in_ifaddr *)ifp->in_ifaddr; 776# else 777 ifa = ifp->if_addrlist; 778# endif 779#endif 780 if (ifa != NULL) { 781 struct sockaddr_in *sin, mask; 782 783 mask.sin_addr.s_addr = 0xffffffff; 784 785#ifdef __sgi 786 sin = (struct sockaddr_in *)&ifa->ia_addr; 787#else 788 sin = (struct sockaddr_in *)&ifa->ifa_addr; 789#endif 790 791 return fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask); 792 } 793 return 0; 794} 795 796 797int ipfsync() 798{ 799 return 0; 800} 801