ip_log.c revision 153084
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_log.c 153084 2005-12-04 10:06:06Z ru $ */ 2 3/* 4 * Copyright (C) 1997-2003 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_log.c 153084 2005-12-04 10:06:06Z ru $ 9 * Id: ip_log.c,v 2.75.2.6 2004/10/16 07:59:27 darrenr Exp 10 */ 11#include <sys/param.h> 12#if defined(KERNEL) || defined(_KERNEL) 13# undef KERNEL 14# undef _KERNEL 15# define KERNEL 1 16# define _KERNEL 1 17#endif 18#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ 19 defined(_KERNEL) 20# include "opt_ipfilter_log.h" 21#endif 22#if defined(__FreeBSD__) && !defined(IPFILTER_LKM) 23# if defined(_KERNEL) 24# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 25# include "opt_ipfilter.h" 26# endif 27# else 28# include <osreldate.h> 29# endif 30#endif 31#ifndef SOLARIS 32# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) 33#endif 34#include <sys/errno.h> 35#include <sys/types.h> 36#include <sys/file.h> 37#ifndef _KERNEL 38# include <stdio.h> 39# include <string.h> 40# include <stdlib.h> 41# include <ctype.h> 42# define _KERNEL 43# define KERNEL 44# ifdef __OpenBSD__ 45struct file; 46# endif 47# include <sys/uio.h> 48# undef _KERNEL 49# undef KERNEL 50#endif 51#if __FreeBSD_version >= 220000 && defined(_KERNEL) 52# include <sys/fcntl.h> 53# include <sys/filio.h> 54#else 55# include <sys/ioctl.h> 56#endif 57#include <sys/time.h> 58#if defined(_KERNEL) 59# include <sys/systm.h> 60# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) 61# include <sys/proc.h> 62# endif 63#endif /* _KERNEL */ 64#if !SOLARIS && !defined(__hpux) && !defined(linux) 65# if (defined(NetBSD) && NetBSD > 199609) || \ 66 (defined(OpenBSD) && OpenBSD > 199603) || \ 67 (__FreeBSD_version >= 300000) 68# include <sys/dirent.h> 69# else 70# include <sys/dir.h> 71# endif 72# include <sys/mbuf.h> 73#else 74# if !defined(__hpux) && defined(_KERNEL) 75# include <sys/filio.h> 76# include <sys/cred.h> 77# include <sys/ddi.h> 78# include <sys/sunddi.h> 79# include <sys/ksynch.h> 80# include <sys/kmem.h> 81# include <sys/mkdev.h> 82# include <sys/dditypes.h> 83# include <sys/cmn_err.h> 84# endif /* !__hpux */ 85#endif /* !SOLARIS && !__hpux */ 86#if !defined(linux) 87# include <sys/protosw.h> 88#endif 89#include <sys/socket.h> 90 91#include <net/if.h> 92#ifdef sun 93# include <net/af.h> 94#endif 95#if __FreeBSD_version >= 300000 96# include <net/if_var.h> 97#endif 98#include <net/route.h> 99#include <netinet/in.h> 100#ifdef __sgi 101# include <sys/ddi.h> 102# ifdef IFF_DRVRLOCK /* IRIX6 */ 103# include <sys/hashing.h> 104# endif 105#endif 106#if !defined(__hpux) && !defined(linux) && \ 107 !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ 108# include <netinet/in_var.h> 109#endif 110#include <netinet/in_systm.h> 111#include <netinet/ip.h> 112#include <netinet/tcp.h> 113#include <netinet/udp.h> 114#include <netinet/ip_icmp.h> 115#ifdef USE_INET6 116# include <netinet/icmp6.h> 117#endif 118#if !defined(linux) 119# include <netinet/ip_var.h> 120#endif 121#ifndef _KERNEL 122# include <syslog.h> 123#endif 124#include "netinet/ip_compat.h" 125#include <netinet/tcpip.h> 126#include "netinet/ip_fil.h" 127#include "netinet/ip_nat.h" 128#include "netinet/ip_frag.h" 129#include "netinet/ip_state.h" 130#include "netinet/ip_auth.h" 131#if (__FreeBSD_version >= 300000) || defined(__NetBSD__) 132# include <sys/malloc.h> 133#endif 134/* END OF INCLUDES */ 135 136#ifdef IPFILTER_LOG 137 138# if defined(IPL_SELECT) 139# include <machine/sys/user.h> 140# include <sys/kthread_iface.h> 141# define READ_COLLISION 0x001 142 143iplog_select_t iplog_ss[IPL_LOGMAX+1]; 144 145extern int selwait; 146# endif /* IPL_SELECT */ 147 148# if defined(linux) && defined(_KERNEL) 149wait_queue_head_t iplh_linux[IPL_LOGSIZE]; 150# endif 151# if SOLARIS 152extern kcondvar_t iplwait; 153# endif 154 155iplog_t **iplh[IPL_LOGSIZE], *iplt[IPL_LOGSIZE], *ipll[IPL_LOGSIZE]; 156int iplused[IPL_LOGSIZE]; 157static fr_info_t iplcrc[IPL_LOGSIZE]; 158int ipl_suppress = 1; 159int ipl_buffer_sz; 160int ipl_logmax = IPL_LOGMAX; 161int ipl_logall = 0; 162int ipl_log_init = 0; 163int ipl_logsize = IPFILTER_LOGSIZE; 164int ipl_magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE, 165 IPL_MAGIC, IPL_MAGIC, IPL_MAGIC, 166 IPL_MAGIC, IPL_MAGIC }; 167 168 169/* ------------------------------------------------------------------------ */ 170/* Function: fr_loginit */ 171/* Returns: int - 0 == success (always returned) */ 172/* Parameters: Nil */ 173/* */ 174/* Initialise log buffers & pointers. Also iniialised the CRC to a local */ 175/* secret for use in calculating the "last log checksum". */ 176/* ------------------------------------------------------------------------ */ 177int fr_loginit() 178{ 179 int i; 180 181 for (i = IPL_LOGMAX; i >= 0; i--) { 182 iplt[i] = NULL; 183 ipll[i] = NULL; 184 iplh[i] = &iplt[i]; 185 iplused[i] = 0; 186 bzero((char *)&iplcrc[i], sizeof(iplcrc[i])); 187# ifdef IPL_SELECT 188 iplog_ss[i].read_waiter = 0; 189 iplog_ss[i].state = 0; 190# endif 191# if defined(linux) && defined(_KERNEL) 192 init_waitqueue_head(iplh_linux + i); 193# endif 194 } 195 196# if SOLARIS && defined(_KERNEL) 197 cv_init(&iplwait, "ipl condvar", CV_DRIVER, NULL); 198# endif 199 MUTEX_INIT(&ipl_mutex, "ipf log mutex"); 200 201 ipl_log_init = 1; 202 203 return 0; 204} 205 206 207/* ------------------------------------------------------------------------ */ 208/* Function: fr_logunload */ 209/* Returns: Nil */ 210/* Parameters: Nil */ 211/* */ 212/* Clean up any log data that has accumulated without being read. */ 213/* ------------------------------------------------------------------------ */ 214void fr_logunload() 215{ 216 int i; 217 218 if (ipl_log_init == 0) 219 return; 220 221 for (i = IPL_LOGMAX; i >= 0; i--) 222 (void) ipflog_clear(i); 223 224# if SOLARIS && defined(_KERNEL) 225 cv_destroy(&iplwait); 226# endif 227 MUTEX_DESTROY(&ipl_mutex); 228 229 ipl_log_init = 0; 230} 231 232 233/* ------------------------------------------------------------------------ */ 234/* Function: ipflog */ 235/* Returns: int - 0 == success, -1 == failure */ 236/* Parameters: fin(I) - pointer to packet information */ 237/* flags(I) - flags from filter rules */ 238/* */ 239/* Create a log record for a packet given that it has been triggered by a */ 240/* rule (or the default setting). Calculate the transport protocol header */ 241/* size using predetermined size of a couple of popular protocols and thus */ 242/* how much data to copy into the log, including part of the data body if */ 243/* requested. */ 244/* ------------------------------------------------------------------------ */ 245int ipflog(fin, flags) 246fr_info_t *fin; 247u_int flags; 248{ 249 register size_t hlen; 250 int types[2], mlen; 251 size_t sizes[2]; 252 void *ptrs[2]; 253 ipflog_t ipfl; 254 u_char p; 255 mb_t *m; 256# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) 257 qif_t *ifp; 258# else 259 struct ifnet *ifp; 260# endif /* SOLARIS || __hpux */ 261 262 ipfl.fl_nattag.ipt_num[0] = 0; 263 m = fin->fin_m; 264 ifp = fin->fin_ifp; 265 hlen = fin->fin_hlen; 266 /* 267 * calculate header size. 268 */ 269 if (fin->fin_off == 0) { 270 p = fin->fin_fi.fi_p; 271 if (p == IPPROTO_TCP) 272 hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); 273 else if (p == IPPROTO_UDP) 274 hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); 275 else if (p == IPPROTO_ICMP) { 276 struct icmp *icmp; 277 278 icmp = (struct icmp *)fin->fin_dp; 279 280 /* 281 * For ICMP, if the packet is an error packet, also 282 * include the information about the packet which 283 * caused the error. 284 */ 285 switch (icmp->icmp_type) 286 { 287 case ICMP_UNREACH : 288 case ICMP_SOURCEQUENCH : 289 case ICMP_REDIRECT : 290 case ICMP_TIMXCEED : 291 case ICMP_PARAMPROB : 292 hlen += MIN(sizeof(struct icmp) + 8, 293 fin->fin_dlen); 294 break; 295 default : 296 hlen += MIN(sizeof(struct icmp), 297 fin->fin_dlen); 298 break; 299 } 300 } 301# ifdef USE_INET6 302 else if (p == IPPROTO_ICMPV6) { 303 struct icmp6_hdr *icmp; 304 305 icmp = (struct icmp6_hdr *)fin->fin_dp; 306 307 /* 308 * For ICMPV6, if the packet is an error packet, also 309 * include the information about the packet which 310 * caused the error. 311 */ 312 if (icmp->icmp6_type < 128) { 313 hlen += MIN(sizeof(struct icmp6_hdr) + 8, 314 fin->fin_dlen); 315 } else { 316 hlen += MIN(sizeof(struct icmp6_hdr), 317 fin->fin_dlen); 318 } 319 } 320# endif 321 } 322 /* 323 * Get the interface number and name to which this packet is 324 * currently associated. 325 */ 326# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) 327 ipfl.fl_unit = (u_int)ifp->qf_ppa; 328 COPYIFNAME(ifp, ipfl.fl_ifname); 329# else 330# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ 331 (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ 332 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) 333 COPYIFNAME(ifp, ipfl.fl_ifname); 334# else 335 ipfl.fl_unit = (u_int)ifp->if_unit; 336# if defined(_KERNEL) 337 if ((ipfl.fl_ifname[0] = ifp->if_name[0])) 338 if ((ipfl.fl_ifname[1] = ifp->if_name[1])) 339 if ((ipfl.fl_ifname[2] = ifp->if_name[2])) 340 ipfl.fl_ifname[3] = ifp->if_name[3]; 341# else 342 (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); 343 ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0'; 344# endif 345# endif 346# endif /* __hpux || SOLARIS */ 347 mlen = fin->fin_plen - hlen; 348 if (!ipl_logall) { 349 mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0; 350 } else if ((flags & FR_LOGBODY) == 0) { 351 mlen = 0; 352 } 353 if (mlen < 0) 354 mlen = 0; 355 ipfl.fl_plen = (u_char)mlen; 356 ipfl.fl_hlen = (u_char)hlen; 357 ipfl.fl_rule = fin->fin_rule; 358 (void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN); 359 if (fin->fin_fr != NULL) { 360 ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; 361 ipfl.fl_logtag = fin->fin_fr->fr_logtag; 362 } else { 363 ipfl.fl_loglevel = 0xffff; 364 ipfl.fl_logtag = FR_NOLOGTAG; 365 } 366 if (fin->fin_nattag != NULL) 367 bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag, 368 sizeof(ipfl.fl_nattag)); 369 ipfl.fl_flags = flags; 370 ipfl.fl_dir = fin->fin_out; 371 ipfl.fl_lflags = fin->fin_flx; 372 ptrs[0] = (void *)&ipfl; 373 sizes[0] = sizeof(ipfl); 374 types[0] = 0; 375# if defined(MENTAT) && defined(_KERNEL) 376 /* 377 * Are we copied from the mblk or an aligned array ? 378 */ 379 if (fin->fin_ip == (ip_t *)m->b_rptr) { 380 ptrs[1] = m; 381 sizes[1] = hlen + mlen; 382 types[1] = 1; 383 } else { 384 ptrs[1] = fin->fin_ip; 385 sizes[1] = hlen + mlen; 386 types[1] = 0; 387 } 388# else 389 ptrs[1] = m; 390 sizes[1] = hlen + mlen; 391 types[1] = 1; 392# endif /* MENTAT */ 393 return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2); 394} 395 396 397/* ------------------------------------------------------------------------ */ 398/* Function: ipllog */ 399/* Returns: int - 0 == success, -1 == failure */ 400/* Parameters: dev(I) - device that owns this log record */ 401/* fin(I) - pointer to packet information */ 402/* items(I) - array of pointers to log data */ 403/* itemsz(I) - array of size of valid memory pointed to */ 404/* types(I) - type of data pointed to by items pointers */ 405/* cnt(I) - number of elements in arrays items/itemsz/types */ 406/* */ 407/* Takes an array of parameters and constructs one record to include the */ 408/* miscellaneous packet information, as well as packet data, for reading */ 409/* from the log device. */ 410/* ------------------------------------------------------------------------ */ 411int ipllog(dev, fin, items, itemsz, types, cnt) 412int dev; 413fr_info_t *fin; 414void **items; 415size_t *itemsz; 416int *types, cnt; 417{ 418 caddr_t buf, ptr; 419 iplog_t *ipl; 420 size_t len; 421 int i; 422# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) 423 int s; 424# endif 425 426 /* 427 * Check to see if this log record has a CRC which matches the last 428 * record logged. If it does, just up the count on the previous one 429 * rather than create a new one. 430 */ 431 if (ipl_suppress) { 432 MUTEX_ENTER(&ipl_mutex); 433 if ((fin != NULL) && (fin->fin_off == 0)) { 434 if ((ipll[dev] != NULL) && 435 bcmp((char *)fin, (char *)&iplcrc[dev], 436 FI_LCSIZE) == 0) { 437 ipll[dev]->ipl_count++; 438 MUTEX_EXIT(&ipl_mutex); 439 return 0; 440 } 441 bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE); 442 } else 443 bzero((char *)&iplcrc[dev], FI_CSIZE); 444 MUTEX_EXIT(&ipl_mutex); 445 } 446 447 /* 448 * Get the total amount of data to be logged. 449 */ 450 for (i = 0, len = sizeof(iplog_t); i < cnt; i++) 451 len += itemsz[i]; 452 453 /* 454 * check that we have space to record this information and can 455 * allocate that much. 456 */ 457 KMALLOCS(buf, caddr_t, len); 458 if (buf == NULL) 459 return -1; 460 SPL_NET(s); 461 MUTEX_ENTER(&ipl_mutex); 462 if ((iplused[dev] + len) > ipl_logsize) { 463 MUTEX_EXIT(&ipl_mutex); 464 SPL_X(s); 465 KFREES(buf, len); 466 return -1; 467 } 468 iplused[dev] += len; 469 MUTEX_EXIT(&ipl_mutex); 470 SPL_X(s); 471 472 /* 473 * advance the log pointer to the next empty record and deduct the 474 * amount of space we're going to use. 475 */ 476 ipl = (iplog_t *)buf; 477 ipl->ipl_magic = ipl_magic[dev]; 478 ipl->ipl_count = 1; 479 ipl->ipl_next = NULL; 480 ipl->ipl_dsize = len; 481#ifdef _KERNEL 482 GETKTIME(&ipl->ipl_sec); 483#else 484 ipl->ipl_sec = 0; 485 ipl->ipl_usec = 0; 486#endif 487 488 /* 489 * Loop through all the items to be logged, copying each one to the 490 * buffer. Use bcopy for normal data or the mb_t copyout routine. 491 */ 492 for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) { 493 if (types[i] == 0) { 494 bcopy(items[i], ptr, itemsz[i]); 495 } else if (types[i] == 1) { 496 COPYDATA(items[i], 0, itemsz[i], ptr); 497 } 498 ptr += itemsz[i]; 499 } 500 SPL_NET(s); 501 MUTEX_ENTER(&ipl_mutex); 502 ipll[dev] = ipl; 503 *iplh[dev] = ipl; 504 iplh[dev] = &ipl->ipl_next; 505 506 /* 507 * Now that the log record has been completed and added to the queue, 508 * wake up any listeners who may want to read it. 509 */ 510# if SOLARIS && defined(_KERNEL) 511 cv_signal(&iplwait); 512 MUTEX_EXIT(&ipl_mutex); 513# else 514 MUTEX_EXIT(&ipl_mutex); 515 WAKEUP(iplh,dev); 516# endif 517 SPL_X(s); 518# ifdef IPL_SELECT 519 iplog_input_ready(dev); 520# endif 521 return 0; 522} 523 524 525/* ------------------------------------------------------------------------ */ 526/* Function: ipflog_read */ 527/* Returns: int - 0 == success, else error value. */ 528/* Parameters: unit(I) - device we are reading from */ 529/* uio(O) - pointer to information about where to store data */ 530/* */ 531/* Called to handle a read on an IPFilter device. Returns only complete */ 532/* log messages - will not partially copy a log record out to userland. */ 533/* */ 534/* NOTE: This function will block and wait for a signal to return data if */ 535/* there is none present. Asynchronous I/O is not implemented. */ 536/* ------------------------------------------------------------------------ */ 537int ipflog_read(unit, uio) 538minor_t unit; 539struct uio *uio; 540{ 541 size_t dlen, copied; 542 int error = 0; 543 iplog_t *ipl; 544# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) 545 int s; 546# endif 547 548 /* 549 * Sanity checks. Make sure the minor # is valid and we're copying 550 * a valid chunk of data. 551 */ 552 if (IPL_LOGMAX < unit) 553 return ENXIO; 554 if (uio->uio_resid == 0) 555 return 0; 556 if ((uio->uio_resid < sizeof(iplog_t)) || 557 (uio->uio_resid > ipl_logsize)) 558 return EINVAL; 559 560 /* 561 * Lock the log so we can snapshot the variables. Wait for a signal 562 * if the log is empty. 563 */ 564 SPL_NET(s); 565 MUTEX_ENTER(&ipl_mutex); 566 567 while (iplt[unit] == NULL) { 568# if SOLARIS && defined(_KERNEL) 569 if (!cv_wait_sig(&iplwait, &ipl_mutex.ipf_lk)) { 570 MUTEX_EXIT(&ipl_mutex); 571 return EINTR; 572 } 573# else 574# if defined(__hpux) && defined(_KERNEL) 575 lock_t *l; 576 577# ifdef IPL_SELECT 578 if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) { 579 /* this is no blocking system call */ 580 MUTEX_EXIT(&ipl_mutex); 581 return 0; 582 } 583# endif 584 585 MUTEX_EXIT(&ipl_mutex); 586 l = get_sleep_lock(&iplh[unit]); 587 error = sleep(&iplh[unit], PZERO+1); 588 spinunlock(l); 589# else 590# if defined(__osf__) && defined(_KERNEL) 591 error = mpsleep(&iplh[unit], PSUSP|PCATCH, "iplread", 0, 592 &ipl_mutex, MS_LOCK_SIMPLE); 593# else 594 MUTEX_EXIT(&ipl_mutex); 595 SPL_X(s); 596 error = SLEEP(unit + iplh, "ipl sleep"); 597# endif /* __osf__ */ 598# endif /* __hpux */ 599 if (error) 600 return error; 601 SPL_NET(s); 602 MUTEX_ENTER(&ipl_mutex); 603# endif /* SOLARIS */ 604 } 605 606# if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__) 607 uio->uio_rw = UIO_READ; 608# endif 609 610 for (copied = 0; (ipl = iplt[unit]) != NULL; copied += dlen) { 611 dlen = ipl->ipl_dsize; 612 if (dlen > uio->uio_resid) 613 break; 614 /* 615 * Don't hold the mutex over the uiomove call. 616 */ 617 iplt[unit] = ipl->ipl_next; 618 iplused[unit] -= dlen; 619 MUTEX_EXIT(&ipl_mutex); 620 SPL_X(s); 621 error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio); 622 if (error) { 623 SPL_NET(s); 624 MUTEX_ENTER(&ipl_mutex); 625 ipl->ipl_next = iplt[unit]; 626 iplt[unit] = ipl; 627 iplused[unit] += dlen; 628 break; 629 } 630 MUTEX_ENTER(&ipl_mutex); 631 KFREES((caddr_t)ipl, dlen); 632 SPL_NET(s); 633 } 634 if (!iplt[unit]) { 635 iplused[unit] = 0; 636 iplh[unit] = &iplt[unit]; 637 ipll[unit] = NULL; 638 } 639 640 MUTEX_EXIT(&ipl_mutex); 641 SPL_X(s); 642 return error; 643} 644 645 646/* ------------------------------------------------------------------------ */ 647/* Function: ipflog_clear */ 648/* Returns: int - number of log bytes cleared. */ 649/* Parameters: unit(I) - device we are reading from */ 650/* */ 651/* Deletes all queued up log records for a given output device. */ 652/* ------------------------------------------------------------------------ */ 653int ipflog_clear(unit) 654minor_t unit; 655{ 656 iplog_t *ipl; 657 int used; 658# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) 659 int s; 660# endif 661 662 SPL_NET(s); 663 MUTEX_ENTER(&ipl_mutex); 664 while ((ipl = iplt[unit]) != NULL) { 665 iplt[unit] = ipl->ipl_next; 666 KFREES((caddr_t)ipl, ipl->ipl_dsize); 667 } 668 iplh[unit] = &iplt[unit]; 669 ipll[unit] = NULL; 670 used = iplused[unit]; 671 iplused[unit] = 0; 672 bzero((char *)&iplcrc[unit], FI_CSIZE); 673 MUTEX_EXIT(&ipl_mutex); 674 SPL_X(s); 675 return used; 676} 677#endif /* IPFILTER_LOG */ 678