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