1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 * $FreeBSD$ 9 * Id: ip_log.c,v 2.75.2.19 2007/09/09 11:32:06 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(__FreeBSD__) && !defined(_KERNEL) 19 # include <osreldate.h> 20 #endif 21 #ifndef SOLARIS 22 # if defined(sun) && defined(__SVR4) 23 # define SOLARIS 1 24 # else 25 # define SOLARIS 0 26 # endif 27 #endif 28 #include <sys/errno.h> 29 #include <sys/types.h> 30 #include <sys/file.h> 31 #ifndef _KERNEL 32 # include <stdio.h> 33 # include <string.h> 34 # include <stdlib.h> 35 # include <ctype.h> 36 # define _KERNEL 37 # define KERNEL 38 # include <sys/uio.h> 39 # undef _KERNEL 40 # undef KERNEL 41 #endif 42 #if defined(__FreeBSD__) && defined(_KERNEL) 43 # include <sys/fcntl.h> 44 # include <sys/filio.h> 45 #else 46 # include <sys/ioctl.h> 47 #endif 48 #include <sys/time.h> 49 #if defined(_KERNEL) 50 # include <sys/systm.h> 51 # if (defined(NetBSD) && (__NetBSD_Version__ >= 104000000)) 52 # include <sys/proc.h> 53 # endif 54 #endif /* _KERNEL */ 55 # if defined(NetBSD) || defined(__FreeBSD__) 56 # include <sys/dirent.h> 57 # include <sys/mbuf.h> 58 # include <sys/select.h> 59 # endif 60 # if defined(__FreeBSD__) 61 # include <sys/selinfo.h> 62 # endif 63 #if SOLARIS && defined(_KERNEL) 64 # include <sys/filio.h> 65 # include <sys/cred.h> 66 # include <sys/ddi.h> 67 # include <sys/sunddi.h> 68 # include <sys/ksynch.h> 69 # include <sys/kmem.h> 70 # include <sys/mkdev.h> 71 # include <sys/dditypes.h> 72 # include <sys/cmn_err.h> 73 #endif /* SOLARIS && _KERNEL */ 74 # include <sys/protosw.h> 75 #include <sys/socket.h> 76 77 #include <net/if.h> 78 #ifdef sun 79 # include <net/af.h> 80 #endif 81 #if defined(__FreeBSD__) 82 # include <net/if_var.h> 83 # include <net/if_private.h> 84 #endif 85 #include <netinet/in.h> 86 # include <netinet/in_var.h> 87 #include <netinet/in_systm.h> 88 #include <netinet/ip.h> 89 #include <netinet/tcp.h> 90 #include <netinet/udp.h> 91 #include <netinet/ip_icmp.h> 92 #ifdef USE_INET6 93 # include <netinet/icmp6.h> 94 #endif 95 # include <netinet/ip_var.h> 96 #ifndef _KERNEL 97 # include <syslog.h> 98 #endif 99 #include "netinet/ip_compat.h" 100 #include <netinet/tcpip.h> 101 #include "netinet/ip_fil.h" 102 #include "netinet/ip_nat.h" 103 #include "netinet/ip_frag.h" 104 #include "netinet/ip_state.h" 105 #include "netinet/ip_auth.h" 106 #if defined(__FreeBSD__) || defined(__NetBSD__) 107 # include <sys/malloc.h> 108 #endif 109 /* END OF INCLUDES */ 110 111 #ifdef IPFILTER_LOG 112 113 typedef struct ipf_log_softc_s { 114 ipfmutex_t ipl_mutex[IPL_LOGSIZE]; 115 # if SOLARIS && defined(_KERNEL) 116 kcondvar_t ipl_wait[IPL_LOGSIZE]; 117 # endif 118 iplog_t **iplh[IPL_LOGSIZE]; 119 iplog_t *iplt[IPL_LOGSIZE]; 120 iplog_t *ipll[IPL_LOGSIZE]; 121 u_long ipl_logfail[IPL_LOGSIZE]; 122 u_long ipl_logok[IPL_LOGSIZE]; 123 fr_info_t ipl_crc[IPL_LOGSIZE]; 124 u_32_t ipl_counter[IPL_LOGSIZE]; 125 int ipl_suppress; 126 int ipl_logall; 127 int ipl_log_init; 128 int ipl_logsize; 129 int ipl_used[IPL_LOGSIZE]; 130 int ipl_magic[IPL_LOGSIZE]; 131 ipftuneable_t *ipf_log_tune; 132 int ipl_readers[IPL_LOGSIZE]; 133 } ipf_log_softc_t; 134 135 static int magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE, 136 IPL_MAGIC, IPL_MAGIC, IPL_MAGIC, 137 IPL_MAGIC, IPL_MAGIC }; 138 139 static ipftuneable_t ipf_log_tuneables[] = { 140 /* log */ 141 { { (void *)offsetof(ipf_log_softc_t, ipl_suppress) }, 142 "log_suppress", 0, 1, 143 stsizeof(ipf_log_softc_t, ipl_suppress), 144 0, NULL, NULL }, 145 { { (void *)offsetof(ipf_log_softc_t, ipl_logall) }, 146 "log_all", 0, 1, 147 stsizeof(ipf_log_softc_t, ipl_logall), 148 0, NULL, NULL }, 149 { { (void *)offsetof(ipf_log_softc_t, ipl_logsize) }, 150 "log_size", 0, 0x80000, 151 stsizeof(ipf_log_softc_t, ipl_logsize), 152 0, NULL, NULL }, 153 { { NULL }, NULL, 0, 0, 154 0, 155 0, NULL, NULL } 156 }; 157 158 159 int 160 ipf_log_main_load(void) 161 { 162 return (0); 163 } 164 165 166 int 167 ipf_log_main_unload(void) 168 { 169 return (0); 170 } 171 172 /* ------------------------------------------------------------------------ */ 173 /* Function: ipf_log_soft_create */ 174 /* Returns: void * - NULL = failure, else pointer to log context data */ 175 /* Parameters: softc(I) - pointer to soft context main structure */ 176 /* */ 177 /* Initialise log buffers & pointers. Also iniialised the CRC to a local */ 178 /* secret for use in calculating the "last log checksum". */ 179 /* ------------------------------------------------------------------------ */ 180 void * 181 ipf_log_soft_create(ipf_main_softc_t *softc) 182 { 183 ipf_log_softc_t *softl; 184 int i; 185 186 KMALLOC(softl, ipf_log_softc_t *); 187 if (softl == NULL) 188 return (NULL); 189 190 bzero((char *)softl, sizeof(*softl)); 191 bcopy((char *)magic, (char *)softl->ipl_magic, sizeof(magic)); 192 193 softl->ipf_log_tune = ipf_tune_array_copy(softl, 194 sizeof(ipf_log_tuneables), 195 ipf_log_tuneables); 196 if (softl->ipf_log_tune == NULL) { 197 ipf_log_soft_destroy(softc, softl); 198 return (NULL); 199 } 200 if (ipf_tune_array_link(softc, softl->ipf_log_tune) == -1) { 201 ipf_log_soft_destroy(softc, softl); 202 return (NULL); 203 } 204 205 for (i = IPL_LOGMAX; i >= 0; i--) { 206 MUTEX_INIT(&softl->ipl_mutex[i], "ipf log mutex"); 207 } 208 209 softl->ipl_suppress = 1; 210 softl->ipl_logall = 0; 211 softl->ipl_log_init = 0; 212 softl->ipl_logsize = IPFILTER_LOGSIZE; 213 214 return (softl); 215 } 216 217 /* ------------------------------------------------------------------------ */ 218 /* Function: ipf_log_soft_init */ 219 /* Returns: int - 0 == success (always returned) */ 220 /* Parameters: softc(I) - pointer to soft context main structure */ 221 /* */ 222 /* Initialise log buffers & pointers. Also iniialised the CRC to a local */ 223 /* secret for use in calculating the "last log checksum". */ 224 /* ------------------------------------------------------------------------ */ 225 int 226 ipf_log_soft_init(ipf_main_softc_t *softc, void *arg) 227 { 228 ipf_log_softc_t *softl = arg; 229 int i; 230 231 for (i = IPL_LOGMAX; i >= 0; i--) { 232 softl->iplt[i] = NULL; 233 softl->ipll[i] = NULL; 234 softl->iplh[i] = &softl->iplt[i]; 235 bzero((char *)&softl->ipl_crc[i], sizeof(softl->ipl_crc[i])); 236 } 237 238 239 softl->ipl_log_init = 1; 240 241 return (0); 242 } 243 244 245 /* ------------------------------------------------------------------------ */ 246 /* Function: ipf_log_soft_fini */ 247 /* Parameters: softc(I) - pointer to soft context main structure */ 248 /* arg(I) - pointer to log context structure */ 249 /* */ 250 /* Clean up any log data that has accumulated without being read. */ 251 /* ------------------------------------------------------------------------ */ 252 int 253 ipf_log_soft_fini(ipf_main_softc_t *softc, void *arg) 254 { 255 ipf_log_softc_t *softl = arg; 256 int i; 257 258 if (softl->ipl_log_init == 0) 259 return (0); 260 261 softl->ipl_log_init = 0; 262 263 for (i = IPL_LOGMAX; i >= 0; i--) { 264 (void) ipf_log_clear(softc, i); 265 266 /* 267 * This is a busy-wait loop so as to avoid yet another lock 268 * to wait on. 269 */ 270 MUTEX_ENTER(&softl->ipl_mutex[i]); 271 while (softl->ipl_readers[i] > 0) { 272 # if SOLARIS && defined(_KERNEL) 273 cv_broadcast(&softl->ipl_wait[i]); 274 MUTEX_EXIT(&softl->ipl_mutex[i]); 275 delay(100); 276 pollwakeup(&softc->ipf_poll_head[i], POLLRDNORM); 277 # else 278 MUTEX_EXIT(&softl->ipl_mutex[i]); 279 WAKEUP(softl->iplh, i); 280 POLLWAKEUP(i); 281 # endif 282 MUTEX_ENTER(&softl->ipl_mutex[i]); 283 } 284 MUTEX_EXIT(&softl->ipl_mutex[i]); 285 } 286 287 return (0); 288 } 289 290 291 /* ------------------------------------------------------------------------ */ 292 /* Function: ipf_log_soft_destroy */ 293 /* Parameters: softc(I) - pointer to soft context main structure */ 294 /* arg(I) - pointer to log context structure */ 295 /* */ 296 /* When this function is called, it is expected that there are no longer */ 297 /* any threads active in the reading code path or the logging code path. */ 298 /* ------------------------------------------------------------------------ */ 299 void 300 ipf_log_soft_destroy(ipf_main_softc_t *softc, void *arg) 301 { 302 ipf_log_softc_t *softl = arg; 303 int i; 304 305 for (i = IPL_LOGMAX; i >= 0; i--) { 306 # if SOLARIS && defined(_KERNEL) 307 cv_destroy(&softl->ipl_wait[i]); 308 # endif 309 MUTEX_DESTROY(&softl->ipl_mutex[i]); 310 } 311 312 if (softl->ipf_log_tune != NULL) { 313 ipf_tune_array_unlink(softc, softl->ipf_log_tune); 314 KFREES(softl->ipf_log_tune, sizeof(ipf_log_tuneables)); 315 softl->ipf_log_tune = NULL; 316 } 317 318 KFREE(softl); 319 } 320 321 322 /* ------------------------------------------------------------------------ */ 323 /* Function: ipf_log_pkt */ 324 /* Returns: int - 0 == success, -1 == failure */ 325 /* Parameters: fin(I) - pointer to packet information */ 326 /* flags(I) - flags from filter rules */ 327 /* */ 328 /* Create a log record for a packet given that it has been triggered by a */ 329 /* rule (or the default setting). Calculate the transport protocol header */ 330 /* size using predetermined size of a couple of popular protocols and thus */ 331 /* how much data to copy into the log, including part of the data body if */ 332 /* requested. */ 333 /* ------------------------------------------------------------------------ */ 334 int 335 ipf_log_pkt(fr_info_t *fin, u_int flags) 336 { 337 ipf_main_softc_t *softc = fin->fin_main_soft; 338 ipf_log_softc_t *softl = softc->ipf_log_soft; 339 register size_t hlen; 340 int types[2], mlen; 341 size_t sizes[2]; 342 void *ptrs[2]; 343 ipflog_t ipfl; 344 u_char p; 345 mb_t *m; 346 # if SOLARIS && defined(_KERNEL) && !defined(FW_HOOKS) 347 qif_t *ifp; 348 # else 349 struct ifnet *ifp; 350 # endif /* SOLARIS */ 351 352 m = fin->fin_m; 353 if (m == NULL) 354 return (-1); 355 356 ipfl.fl_nattag.ipt_num[0] = 0; 357 ifp = fin->fin_ifp; 358 hlen = (char *)fin->fin_dp - (char *)fin->fin_ip; 359 360 /* 361 * calculate header size. 362 */ 363 if (fin->fin_off == 0) { 364 p = fin->fin_fi.fi_p; 365 if (p == IPPROTO_TCP) 366 hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); 367 else if (p == IPPROTO_UDP) 368 hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); 369 else if (p == IPPROTO_ICMP) { 370 struct icmp *icmp; 371 372 icmp = (struct icmp *)fin->fin_dp; 373 374 /* 375 * For ICMP, if the packet is an error packet, also 376 * include the information about the packet which 377 * caused the error. 378 */ 379 switch (icmp->icmp_type) 380 { 381 case ICMP_UNREACH : 382 case ICMP_SOURCEQUENCH : 383 case ICMP_REDIRECT : 384 case ICMP_TIMXCEED : 385 case ICMP_PARAMPROB : 386 hlen += MIN(sizeof(struct icmp) + 8, 387 fin->fin_dlen); 388 break; 389 default : 390 hlen += MIN(sizeof(struct icmp), 391 fin->fin_dlen); 392 break; 393 } 394 } 395 # ifdef USE_INET6 396 else if (p == IPPROTO_ICMPV6) { 397 struct icmp6_hdr *icmp; 398 399 icmp = (struct icmp6_hdr *)fin->fin_dp; 400 401 /* 402 * For ICMPV6, if the packet is an error packet, also 403 * include the information about the packet which 404 * caused the error. 405 */ 406 if (icmp->icmp6_type < 128) { 407 hlen += MIN(sizeof(struct icmp6_hdr) + 8, 408 fin->fin_dlen); 409 } else { 410 hlen += MIN(sizeof(struct icmp6_hdr), 411 fin->fin_dlen); 412 } 413 } 414 # endif 415 } 416 /* 417 * Get the interface number and name to which this packet is 418 * currently associated. 419 */ 420 # if SOLARIS && defined(_KERNEL) 421 # if !defined(FW_HOOKS) 422 ipfl.fl_unit = (u_int)ifp->qf_ppa; 423 # endif 424 COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname); 425 # else 426 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ 427 defined(__FreeBSD__) 428 COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname); 429 # else 430 ipfl.fl_unit = (u_int)ifp->if_unit; 431 # if defined(_KERNEL) 432 if ((ipfl.fl_ifname[0] = ifp->if_name[0])) 433 if ((ipfl.fl_ifname[1] = ifp->if_name[1])) 434 if ((ipfl.fl_ifname[2] = ifp->if_name[2])) 435 ipfl.fl_ifname[3] = ifp->if_name[3]; 436 # else 437 (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); 438 ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0'; 439 # endif 440 # endif 441 # endif /* __hpux || SOLARIS */ 442 mlen = fin->fin_plen - hlen; 443 if (!softl->ipl_logall) { 444 mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0; 445 } else if ((flags & FR_LOGBODY) == 0) { 446 mlen = 0; 447 } 448 if (mlen < 0) 449 mlen = 0; 450 ipfl.fl_plen = (u_char)mlen; 451 ipfl.fl_hlen = (u_char)hlen; 452 ipfl.fl_rule = fin->fin_rule; 453 (void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN); 454 if (fin->fin_fr != NULL) { 455 ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; 456 ipfl.fl_logtag = fin->fin_fr->fr_logtag; 457 } else { 458 ipfl.fl_loglevel = 0xffff; 459 ipfl.fl_logtag = FR_NOLOGTAG; 460 } 461 if (fin->fin_nattag != NULL) 462 bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag, 463 sizeof(ipfl.fl_nattag)); 464 ipfl.fl_flags = flags; 465 ipfl.fl_breason = (fin->fin_reason & 0xff); 466 ipfl.fl_dir = fin->fin_out; 467 ipfl.fl_lflags = fin->fin_flx; 468 ipfl.fl_family = fin->fin_family; 469 ptrs[0] = (void *)&ipfl; 470 sizes[0] = sizeof(ipfl); 471 types[0] = 0; 472 # if SOLARIS && defined(_KERNEL) 473 /* 474 * Are we copied from the mblk or an aligned array ? 475 */ 476 if (fin->fin_ip == (ip_t *)m->b_rptr) { 477 ptrs[1] = m; 478 sizes[1] = hlen + mlen; 479 types[1] = 1; 480 } else { 481 ptrs[1] = fin->fin_ip; 482 sizes[1] = hlen + mlen; 483 types[1] = 0; 484 } 485 # else 486 ptrs[1] = m; 487 sizes[1] = hlen + mlen; 488 types[1] = 1; 489 # endif /* SOLARIS */ 490 return (ipf_log_items(softc, IPL_LOGIPF, fin, ptrs, sizes, types, 2)); 491 } 492 493 494 /* ------------------------------------------------------------------------ */ 495 /* Function: ipf_log_items */ 496 /* Returns: int - 0 == success, -1 == failure */ 497 /* Parameters: softc(I) - pointer to main soft context */ 498 /* unit(I) - device we are reading from */ 499 /* fin(I) - pointer to packet information */ 500 /* items(I) - array of pointers to log data */ 501 /* itemsz(I) - array of size of valid memory pointed to */ 502 /* types(I) - type of data pointed to by items pointers */ 503 /* cnt(I) - number of elements in arrays items/itemsz/types */ 504 /* */ 505 /* Takes an array of parameters and constructs one record to include the */ 506 /* miscellaneous packet information, as well as packet data, for reading */ 507 /* from the log device. */ 508 /* ------------------------------------------------------------------------ */ 509 int 510 ipf_log_items(ipf_main_softc_t *softc, int unit, fr_info_t *fin, void **items, 511 size_t *itemsz, int *types, int cnt) 512 { 513 ipf_log_softc_t *softl = softc->ipf_log_soft; 514 caddr_t buf, ptr; 515 iplog_t *ipl; 516 size_t len; 517 int i; 518 SPL_INT(s); 519 520 /* 521 * Get the total amount of data to be logged. 522 */ 523 for (i = 0, len = sizeof(iplog_t); i < cnt; i++) 524 len += itemsz[i]; 525 526 SPL_NET(s); 527 MUTEX_ENTER(&softl->ipl_mutex[unit]); 528 softl->ipl_counter[unit]++; 529 /* 530 * check that we have space to record this information and can 531 * allocate that much. 532 */ 533 if ((softl->ipl_used[unit] + len) > softl->ipl_logsize) { 534 softl->ipl_logfail[unit]++; 535 MUTEX_EXIT(&softl->ipl_mutex[unit]); 536 return (-1); 537 } 538 539 KMALLOCS(buf, caddr_t, len); 540 if (buf == NULL) { 541 softl->ipl_logfail[unit]++; 542 MUTEX_EXIT(&softl->ipl_mutex[unit]); 543 return (-1); 544 } 545 ipl = (iplog_t *)buf; 546 ipl->ipl_magic = softl->ipl_magic[unit]; 547 ipl->ipl_count = 1; 548 ipl->ipl_seqnum = softl->ipl_counter[unit]; 549 ipl->ipl_next = NULL; 550 ipl->ipl_dsize = len; 551 #ifdef _KERNEL 552 GETKTIME(&ipl->ipl_sec); 553 #else 554 ipl->ipl_sec = 0; 555 ipl->ipl_usec = 0; 556 #endif 557 558 /* 559 * Loop through all the items to be logged, copying each one to the 560 * buffer. Use bcopy for normal data or the mb_t copyout routine. 561 */ 562 for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) { 563 if (types[i] == 0) { 564 bcopy(items[i], ptr, itemsz[i]); 565 } else if (types[i] == 1) { 566 COPYDATA(items[i], 0, itemsz[i], ptr); 567 } 568 ptr += itemsz[i]; 569 } 570 /* 571 * Check to see if this log record has a CRC which matches the last 572 * record logged. If it does, just up the count on the previous one 573 * rather than create a new one. 574 */ 575 if (softl->ipl_suppress) { 576 if ((fin != NULL) && (fin->fin_off == 0)) { 577 if ((softl->ipll[unit] != NULL) && 578 (fin->fin_crc == softl->ipl_crc[unit].fin_crc) && 579 bcmp((char *)fin, (char *)&softl->ipl_crc[unit], 580 FI_LCSIZE) == 0) { 581 softl->ipll[unit]->ipl_count++; 582 MUTEX_EXIT(&softl->ipl_mutex[unit]); 583 SPL_X(s); 584 KFREES(buf, len); 585 return (0); 586 } 587 bcopy((char *)fin, (char *)&softl->ipl_crc[unit], 588 FI_LCSIZE); 589 softl->ipl_crc[unit].fin_crc = fin->fin_crc; 590 } else 591 bzero((char *)&softl->ipl_crc[unit], FI_CSIZE); 592 } 593 594 /* 595 * advance the log pointer to the next empty record and deduct the 596 * amount of space we're going to use. 597 */ 598 softl->ipl_logok[unit]++; 599 softl->ipll[unit] = ipl; 600 *softl->iplh[unit] = ipl; 601 softl->iplh[unit] = &ipl->ipl_next; 602 softl->ipl_used[unit] += len; 603 604 /* 605 * Now that the log record has been completed and added to the queue, 606 * wake up any listeners who may want to read it. 607 */ 608 # if SOLARIS && defined(_KERNEL) 609 cv_signal(&softl->ipl_wait[unit]); 610 MUTEX_EXIT(&softl->ipl_mutex[unit]); 611 pollwakeup(&softc->ipf_poll_head[unit], POLLRDNORM); 612 # else 613 MUTEX_EXIT(&softl->ipl_mutex[unit]); 614 WAKEUP(softl->iplh, unit); 615 POLLWAKEUP(unit); 616 # endif 617 SPL_X(s); 618 return (0); 619 } 620 621 622 /* ------------------------------------------------------------------------ */ 623 /* Function: ipf_log_read */ 624 /* Returns: int - 0 == success, else error value. */ 625 /* Parameters: softc(I) - pointer to main soft context */ 626 /* unit(I) - device we are reading from */ 627 /* uio(O) - pointer to information about where to store data */ 628 /* */ 629 /* Called to handle a read on an IPFilter device. Returns only complete */ 630 /* log messages - will not partially copy a log record out to userland. */ 631 /* */ 632 /* NOTE: This function will block and wait for a signal to return data if */ 633 /* there is none present. Asynchronous I/O is not implemented. */ 634 /* ------------------------------------------------------------------------ */ 635 int 636 ipf_log_read(ipf_main_softc_t *softc, minor_t unit, struct uio *uio) 637 { 638 ipf_log_softc_t *softl = softc->ipf_log_soft; 639 size_t dlen; 640 int error = 0; 641 iplog_t *ipl; 642 SPL_INT(s); 643 644 if (softl->ipl_log_init == 0) { 645 IPFERROR(40007); 646 return (0); 647 } 648 649 /* 650 * Sanity checks. Make sure the minor # is valid and we're copying 651 * a valid chunk of data. 652 */ 653 if (IPL_LOGMAX < unit) { 654 IPFERROR(40001); 655 return (ENXIO); 656 } 657 if (uio->uio_resid == 0) 658 return (0); 659 660 if (uio->uio_resid < sizeof(iplog_t)) { 661 IPFERROR(40002); 662 return (EINVAL); 663 } 664 if (uio->uio_resid > softl->ipl_logsize) { 665 IPFERROR(40005); 666 return (EINVAL); 667 } 668 669 /* 670 * Lock the log so we can snapshot the variables. Wait for a signal 671 * if the log is empty. 672 */ 673 SPL_NET(s); 674 MUTEX_ENTER(&softl->ipl_mutex[unit]); 675 softl->ipl_readers[unit]++; 676 677 while (softl->ipl_log_init == 1 && softl->iplt[unit] == NULL) { 678 # if SOLARIS && defined(_KERNEL) 679 if (!cv_wait_sig(&softl->ipl_wait[unit], 680 &softl->ipl_mutex[unit].ipf_lk)) { 681 softl->ipl_readers[unit]--; 682 MUTEX_EXIT(&softl->ipl_mutex[unit]); 683 IPFERROR(40003); 684 return (EINTR); 685 } 686 # else 687 MUTEX_EXIT(&softl->ipl_mutex[unit]); 688 SPL_X(s); 689 error = SLEEP(unit + softl->iplh, "ipl sleep"); 690 SPL_NET(s); 691 MUTEX_ENTER(&softl->ipl_mutex[unit]); 692 if (error) { 693 softl->ipl_readers[unit]--; 694 MUTEX_EXIT(&softl->ipl_mutex[unit]); 695 IPFERROR(40004); 696 return (error); 697 } 698 # endif /* SOLARIS */ 699 } 700 if (softl->ipl_log_init != 1) { 701 softl->ipl_readers[unit]--; 702 MUTEX_EXIT(&softl->ipl_mutex[unit]); 703 IPFERROR(40008); 704 return (EIO); 705 } 706 707 # if defined(BSD) 708 uio->uio_rw = UIO_READ; 709 # endif 710 711 for (; (ipl = softl->iplt[unit]) != NULL;) { 712 dlen = ipl->ipl_dsize; 713 if (dlen > uio->uio_resid) 714 break; 715 /* 716 * Don't hold the mutex over the uiomove call. 717 */ 718 softl->iplt[unit] = ipl->ipl_next; 719 softl->ipl_used[unit] -= dlen; 720 MUTEX_EXIT(&softl->ipl_mutex[unit]); 721 SPL_X(s); 722 error = UIOMOVE(ipl, dlen, UIO_READ, uio); 723 if (error) { 724 SPL_NET(s); 725 MUTEX_ENTER(&softl->ipl_mutex[unit]); 726 IPFERROR(40006); 727 ipl->ipl_next = softl->iplt[unit]; 728 softl->iplt[unit] = ipl; 729 softl->ipl_used[unit] += dlen; 730 break; 731 } 732 MUTEX_ENTER(&softl->ipl_mutex[unit]); 733 KFREES((caddr_t)ipl, dlen); 734 SPL_NET(s); 735 } 736 if (!softl->iplt[unit]) { 737 softl->ipl_used[unit] = 0; 738 softl->iplh[unit] = &softl->iplt[unit]; 739 softl->ipll[unit] = NULL; 740 } 741 742 softl->ipl_readers[unit]--; 743 MUTEX_EXIT(&softl->ipl_mutex[unit]); 744 SPL_X(s); 745 return (error); 746 } 747 748 749 /* ------------------------------------------------------------------------ */ 750 /* Function: ipf_log_clear */ 751 /* Returns: int - number of log bytes cleared. */ 752 /* Parameters: softc(I) - pointer to main soft context */ 753 /* unit(I) - device we are reading from */ 754 /* */ 755 /* Deletes all queued up log records for a given output device. */ 756 /* ------------------------------------------------------------------------ */ 757 int 758 ipf_log_clear(ipf_main_softc_t *softc, minor_t unit) 759 { 760 ipf_log_softc_t *softl = softc->ipf_log_soft; 761 iplog_t *ipl; 762 int used; 763 SPL_INT(s); 764 765 SPL_NET(s); 766 MUTEX_ENTER(&softl->ipl_mutex[unit]); 767 while ((ipl = softl->iplt[unit]) != NULL) { 768 softl->iplt[unit] = ipl->ipl_next; 769 KFREES((caddr_t)ipl, ipl->ipl_dsize); 770 } 771 softl->iplh[unit] = &softl->iplt[unit]; 772 softl->ipll[unit] = NULL; 773 used = softl->ipl_used[unit]; 774 softl->ipl_used[unit] = 0; 775 bzero((char *)&softl->ipl_crc[unit], FI_CSIZE); 776 MUTEX_EXIT(&softl->ipl_mutex[unit]); 777 SPL_X(s); 778 return (used); 779 } 780 781 782 /* ------------------------------------------------------------------------ */ 783 /* Function: ipf_log_canread */ 784 /* Returns: int - 0 == no data to read, 1 = data present */ 785 /* Parameters: softc(I) - pointer to main soft context */ 786 /* unit(I) - device we are reading from */ 787 /* */ 788 /* Returns an indication of whether or not there is data present in the */ 789 /* current buffer for the selected ipf device. */ 790 /* ------------------------------------------------------------------------ */ 791 int 792 ipf_log_canread(ipf_main_softc_t *softc, int unit) 793 { 794 ipf_log_softc_t *softl = softc->ipf_log_soft; 795 796 return (softl->iplt[unit] != NULL); 797 } 798 799 800 /* ------------------------------------------------------------------------ */ 801 /* Function: ipf_log_canread */ 802 /* Returns: int - 0 == no data to read, 1 = data present */ 803 /* Parameters: softc(I) - pointer to main soft context */ 804 /* unit(I) - device we are reading from */ 805 /* */ 806 /* Returns how many bytes are currently held in log buffers for the */ 807 /* selected ipf device. */ 808 /* ------------------------------------------------------------------------ */ 809 int 810 ipf_log_bytesused(ipf_main_softc_t *softc, int unit) 811 { 812 ipf_log_softc_t *softl = softc->ipf_log_soft; 813 814 if (softl == NULL) 815 return (0); 816 817 return (softl->ipl_used[unit]); 818 } 819 820 821 /* ------------------------------------------------------------------------ */ 822 /* Function: ipf_log_failures */ 823 /* Returns: U_QUAD_T - number of log failures */ 824 /* Parameters: softc(I) - pointer to main soft context */ 825 /* unit(I) - device we are reading from */ 826 /* */ 827 /* Returns how many times we've tried to log a packet but failed to do so */ 828 /* for the selected ipf device. */ 829 /* ------------------------------------------------------------------------ */ 830 u_long 831 ipf_log_failures(ipf_main_softc_t *softc, int unit) 832 { 833 ipf_log_softc_t *softl = softc->ipf_log_soft; 834 835 if (softl == NULL) 836 return (0); 837 838 return (softl->ipl_logfail[unit]); 839 } 840 841 842 /* ------------------------------------------------------------------------ */ 843 /* Function: ipf_log_logok */ 844 /* Returns: U_QUAD_T - number of packets logged */ 845 /* Parameters: softc(I) - pointer to main soft context */ 846 /* unit(I) - device we are reading from */ 847 /* */ 848 /* Returns how many times we've successfully logged a packet for the */ 849 /* selected ipf device. */ 850 /* ------------------------------------------------------------------------ */ 851 u_long 852 ipf_log_logok(ipf_main_softc_t *softc, int unit) 853 { 854 ipf_log_softc_t *softl = softc->ipf_log_soft; 855 856 if (softl == NULL) 857 return (0); 858 859 return (softl->ipl_logok[unit]); 860 } 861 #endif /* IPFILTER_LOG */ 862