ip_log.c revision 153876
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_log.c 153876 2005-12-30 11:32:23Z guido $ */ 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 153876 2005-12-30 11:32:23Z guido $ 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 SPL_INT(s); 423 424 /* 425 * Check to see if this log record has a CRC which matches the last 426 * record logged. If it does, just up the count on the previous one 427 * rather than create a new one. 428 */ 429 if (ipl_suppress) { 430 MUTEX_ENTER(&ipl_mutex); 431 if ((fin != NULL) && (fin->fin_off == 0)) { 432 if ((ipll[dev] != NULL) && 433 bcmp((char *)fin, (char *)&iplcrc[dev], 434 FI_LCSIZE) == 0) { 435 ipll[dev]->ipl_count++; 436 MUTEX_EXIT(&ipl_mutex); 437 return 0; 438 } 439 bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE); 440 } else 441 bzero((char *)&iplcrc[dev], FI_CSIZE); 442 MUTEX_EXIT(&ipl_mutex); 443 } 444 445 /* 446 * Get the total amount of data to be logged. 447 */ 448 for (i = 0, len = sizeof(iplog_t); i < cnt; i++) 449 len += itemsz[i]; 450 451 /* 452 * check that we have space to record this information and can 453 * allocate that much. 454 */ 455 KMALLOCS(buf, caddr_t, len); 456 if (buf == NULL) 457 return -1; 458 SPL_NET(s); 459 MUTEX_ENTER(&ipl_mutex); 460 if ((iplused[dev] + len) > ipl_logsize) { 461 MUTEX_EXIT(&ipl_mutex); 462 SPL_X(s); 463 KFREES(buf, len); 464 return -1; 465 } 466 iplused[dev] += len; 467 MUTEX_EXIT(&ipl_mutex); 468 SPL_X(s); 469 470 /* 471 * advance the log pointer to the next empty record and deduct the 472 * amount of space we're going to use. 473 */ 474 ipl = (iplog_t *)buf; 475 ipl->ipl_magic = ipl_magic[dev]; 476 ipl->ipl_count = 1; 477 ipl->ipl_next = NULL; 478 ipl->ipl_dsize = len; 479#ifdef _KERNEL 480 GETKTIME(&ipl->ipl_sec); 481#else 482 ipl->ipl_sec = 0; 483 ipl->ipl_usec = 0; 484#endif 485 486 /* 487 * Loop through all the items to be logged, copying each one to the 488 * buffer. Use bcopy for normal data or the mb_t copyout routine. 489 */ 490 for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) { 491 if (types[i] == 0) { 492 bcopy(items[i], ptr, itemsz[i]); 493 } else if (types[i] == 1) { 494 COPYDATA(items[i], 0, itemsz[i], ptr); 495 } 496 ptr += itemsz[i]; 497 } 498 SPL_NET(s); 499 MUTEX_ENTER(&ipl_mutex); 500 ipll[dev] = ipl; 501 *iplh[dev] = ipl; 502 iplh[dev] = &ipl->ipl_next; 503 504 /* 505 * Now that the log record has been completed and added to the queue, 506 * wake up any listeners who may want to read it. 507 */ 508# if SOLARIS && defined(_KERNEL) 509 cv_signal(&iplwait); 510 MUTEX_EXIT(&ipl_mutex); 511# else 512 MUTEX_EXIT(&ipl_mutex); 513 WAKEUP(iplh,dev); 514# endif 515 SPL_X(s); 516# ifdef IPL_SELECT 517 iplog_input_ready(dev); 518# endif 519 return 0; 520} 521 522 523/* ------------------------------------------------------------------------ */ 524/* Function: ipflog_read */ 525/* Returns: int - 0 == success, else error value. */ 526/* Parameters: unit(I) - device we are reading from */ 527/* uio(O) - pointer to information about where to store data */ 528/* */ 529/* Called to handle a read on an IPFilter device. Returns only complete */ 530/* log messages - will not partially copy a log record out to userland. */ 531/* */ 532/* NOTE: This function will block and wait for a signal to return data if */ 533/* there is none present. Asynchronous I/O is not implemented. */ 534/* ------------------------------------------------------------------------ */ 535int ipflog_read(unit, uio) 536minor_t unit; 537struct uio *uio; 538{ 539 size_t dlen, copied; 540 int error = 0; 541 iplog_t *ipl; 542 SPL_INT(s); 543 544 /* 545 * Sanity checks. Make sure the minor # is valid and we're copying 546 * a valid chunk of data. 547 */ 548 if (IPL_LOGMAX < unit) 549 return ENXIO; 550 if (uio->uio_resid == 0) 551 return 0; 552 if ((uio->uio_resid < sizeof(iplog_t)) || 553 (uio->uio_resid > ipl_logsize)) 554 return EINVAL; 555 556 /* 557 * Lock the log so we can snapshot the variables. Wait for a signal 558 * if the log is empty. 559 */ 560 SPL_NET(s); 561 MUTEX_ENTER(&ipl_mutex); 562 563 while (iplt[unit] == NULL) { 564# if SOLARIS && defined(_KERNEL) 565 if (!cv_wait_sig(&iplwait, &ipl_mutex.ipf_lk)) { 566 MUTEX_EXIT(&ipl_mutex); 567 return EINTR; 568 } 569# else 570# if defined(__hpux) && defined(_KERNEL) 571 lock_t *l; 572 573# ifdef IPL_SELECT 574 if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) { 575 /* this is no blocking system call */ 576 MUTEX_EXIT(&ipl_mutex); 577 return 0; 578 } 579# endif 580 581 MUTEX_EXIT(&ipl_mutex); 582 l = get_sleep_lock(&iplh[unit]); 583 error = sleep(&iplh[unit], PZERO+1); 584 spinunlock(l); 585# else 586# if defined(__osf__) && defined(_KERNEL) 587 error = mpsleep(&iplh[unit], PSUSP|PCATCH, "iplread", 0, 588 &ipl_mutex, MS_LOCK_SIMPLE); 589# else 590 MUTEX_EXIT(&ipl_mutex); 591 SPL_X(s); 592 error = SLEEP(unit + iplh, "ipl sleep"); 593# endif /* __osf__ */ 594# endif /* __hpux */ 595 if (error) 596 return error; 597 SPL_NET(s); 598 MUTEX_ENTER(&ipl_mutex); 599# endif /* SOLARIS */ 600 } 601 602# if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__) 603 uio->uio_rw = UIO_READ; 604# endif 605 606 for (copied = 0; (ipl = iplt[unit]) != NULL; copied += dlen) { 607 dlen = ipl->ipl_dsize; 608 if (dlen > uio->uio_resid) 609 break; 610 /* 611 * Don't hold the mutex over the uiomove call. 612 */ 613 iplt[unit] = ipl->ipl_next; 614 iplused[unit] -= dlen; 615 MUTEX_EXIT(&ipl_mutex); 616 SPL_X(s); 617 error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio); 618 if (error) { 619 SPL_NET(s); 620 MUTEX_ENTER(&ipl_mutex); 621 ipl->ipl_next = iplt[unit]; 622 iplt[unit] = ipl; 623 iplused[unit] += dlen; 624 break; 625 } 626 MUTEX_ENTER(&ipl_mutex); 627 KFREES((caddr_t)ipl, dlen); 628 SPL_NET(s); 629 } 630 if (!iplt[unit]) { 631 iplused[unit] = 0; 632 iplh[unit] = &iplt[unit]; 633 ipll[unit] = NULL; 634 } 635 636 MUTEX_EXIT(&ipl_mutex); 637 SPL_X(s); 638 return error; 639} 640 641 642/* ------------------------------------------------------------------------ */ 643/* Function: ipflog_clear */ 644/* Returns: int - number of log bytes cleared. */ 645/* Parameters: unit(I) - device we are reading from */ 646/* */ 647/* Deletes all queued up log records for a given output device. */ 648/* ------------------------------------------------------------------------ */ 649int ipflog_clear(unit) 650minor_t unit; 651{ 652 iplog_t *ipl; 653 int used; 654 SPL_INT(s); 655 656 SPL_NET(s); 657 MUTEX_ENTER(&ipl_mutex); 658 while ((ipl = iplt[unit]) != NULL) { 659 iplt[unit] = ipl->ipl_next; 660 KFREES((caddr_t)ipl, ipl->ipl_dsize); 661 } 662 iplh[unit] = &iplt[unit]; 663 ipll[unit] = NULL; 664 used = iplused[unit]; 665 iplused[unit] = 0; 666 bzero((char *)&iplcrc[unit], FI_CSIZE); 667 MUTEX_EXIT(&ipl_mutex); 668 SPL_X(s); 669 return used; 670} 671#endif /* IPFILTER_LOG */ 672