1145522Sdarrenr/* $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_log.c 341739 2018-12-08 17:28:52Z cy $ */ 2145522Sdarrenr 353642Sguido/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 553642Sguido * 680482Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 753642Sguido * 857126Sguido * $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_log.c 341739 2018-12-08 17:28:52Z cy $ 9172776Sdarrenr * Id: ip_log.c,v 2.75.2.19 2007/09/09 11:32:06 darrenr Exp $ 1053642Sguido */ 1153642Sguido#include <sys/param.h> 12145522Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 13145522Sdarrenr# undef KERNEL 14145522Sdarrenr# undef _KERNEL 15145522Sdarrenr# define KERNEL 1 16145522Sdarrenr# define _KERNEL 1 1753642Sguido#endif 18255332Scy#if defined(__FreeBSD__) && !defined(_KERNEL) 19255332Scy# include <osreldate.h> 2053642Sguido#endif 21145522Sdarrenr#ifndef SOLARIS 22305138Sdim# if defined(sun) && (defined(__svr4__) || defined(__SVR4)) 23305138Sdim# define SOLARIS 1 24305138Sdim# else 25305138Sdim# define SOLARIS 0 26305138Sdim# endif 27145522Sdarrenr#endif 28145522Sdarrenr#include <sys/errno.h> 29145522Sdarrenr#include <sys/types.h> 30145522Sdarrenr#include <sys/file.h> 31145522Sdarrenr#ifndef _KERNEL 32145522Sdarrenr# include <stdio.h> 33145522Sdarrenr# include <string.h> 34145522Sdarrenr# include <stdlib.h> 35145522Sdarrenr# include <ctype.h> 36145522Sdarrenr# define _KERNEL 37145522Sdarrenr# define KERNEL 38145522Sdarrenr# ifdef __OpenBSD__ 39145522Sdarrenrstruct file; 4053642Sguido# endif 41145522Sdarrenr# include <sys/uio.h> 42145522Sdarrenr# undef _KERNEL 43145522Sdarrenr# undef KERNEL 44145522Sdarrenr#endif 45173181Sdarrenr#if (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) && \ 46173181Sdarrenr defined(_KERNEL) 47145522Sdarrenr# include <sys/fcntl.h> 48145522Sdarrenr# include <sys/filio.h> 49145522Sdarrenr#else 50145522Sdarrenr# include <sys/ioctl.h> 51145522Sdarrenr#endif 52145522Sdarrenr#include <sys/time.h> 53145522Sdarrenr#if defined(_KERNEL) 54145522Sdarrenr# include <sys/systm.h> 55173181Sdarrenr# if (defined(NetBSD) && (__NetBSD_Version__ >= 104000000)) 56145522Sdarrenr# include <sys/proc.h> 5753642Sguido# endif 58145522Sdarrenr#endif /* _KERNEL */ 59145522Sdarrenr#if !SOLARIS && !defined(__hpux) && !defined(linux) 60173181Sdarrenr# if (defined(NetBSD) && (NetBSD > 199609)) || \ 61173181Sdarrenr (defined(OpenBSD) && (OpenBSD > 199603)) || \ 62173181Sdarrenr (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)) 63145522Sdarrenr# include <sys/dirent.h> 6453642Sguido# else 65145522Sdarrenr# include <sys/dir.h> 6653642Sguido# endif 67145522Sdarrenr# include <sys/mbuf.h> 68161356Sguido# include <sys/select.h> 69161356Sguido# if __FreeBSD_version >= 500000 70161356Sguido# include <sys/selinfo.h> 71161356Sguido# endif 72145522Sdarrenr#else 73145522Sdarrenr# if !defined(__hpux) && defined(_KERNEL) 7453642Sguido# include <sys/filio.h> 7553642Sguido# include <sys/cred.h> 76145522Sdarrenr# include <sys/ddi.h> 77145522Sdarrenr# include <sys/sunddi.h> 78145522Sdarrenr# include <sys/ksynch.h> 7953642Sguido# include <sys/kmem.h> 80145522Sdarrenr# include <sys/mkdev.h> 81145522Sdarrenr# include <sys/dditypes.h> 82145522Sdarrenr# include <sys/cmn_err.h> 83145522Sdarrenr# endif /* !__hpux */ 84145522Sdarrenr#endif /* !SOLARIS && !__hpux */ 85145522Sdarrenr#if !defined(linux) 8680482Sdarrenr# include <sys/protosw.h> 87145522Sdarrenr#endif 88145522Sdarrenr#include <sys/socket.h> 8953642Sguido 90145522Sdarrenr#include <net/if.h> 91145522Sdarrenr#ifdef sun 92145522Sdarrenr# include <net/af.h> 93145522Sdarrenr#endif 94145522Sdarrenr#if __FreeBSD_version >= 300000 95145522Sdarrenr# include <net/if_var.h> 96145522Sdarrenr#endif 97145522Sdarrenr#include <netinet/in.h> 98145522Sdarrenr#ifdef __sgi 99145522Sdarrenr# include <sys/ddi.h> 100145522Sdarrenr#endif 101145522Sdarrenr# include <netinet/in_var.h> 102145522Sdarrenr#include <netinet/in_systm.h> 103145522Sdarrenr#include <netinet/ip.h> 104145522Sdarrenr#include <netinet/tcp.h> 105145522Sdarrenr#include <netinet/udp.h> 106145522Sdarrenr#include <netinet/ip_icmp.h> 107145522Sdarrenr#ifdef USE_INET6 108145522Sdarrenr# include <netinet/icmp6.h> 109145522Sdarrenr#endif 110145522Sdarrenr#if !defined(linux) 11180482Sdarrenr# include <netinet/ip_var.h> 112145522Sdarrenr#endif 113145522Sdarrenr#ifndef _KERNEL 114145522Sdarrenr# include <syslog.h> 115145522Sdarrenr#endif 116145522Sdarrenr#include "netinet/ip_compat.h" 117145522Sdarrenr#include <netinet/tcpip.h> 118145522Sdarrenr#include "netinet/ip_fil.h" 119145522Sdarrenr#include "netinet/ip_nat.h" 120145522Sdarrenr#include "netinet/ip_frag.h" 121145522Sdarrenr#include "netinet/ip_state.h" 122145522Sdarrenr#include "netinet/ip_auth.h" 123145522Sdarrenr#if (__FreeBSD_version >= 300000) || defined(__NetBSD__) 124145522Sdarrenr# include <sys/malloc.h> 125145522Sdarrenr#endif 126145522Sdarrenr/* END OF INCLUDES */ 12753642Sguido 128145522Sdarrenr#ifdef IPFILTER_LOG 12953642Sguido 130145522Sdarrenr# if defined(IPL_SELECT) 131145522Sdarrenr# include <machine/sys/user.h> 132145522Sdarrenr# include <sys/kthread_iface.h> 133145522Sdarrenr# define READ_COLLISION 0x001 134145522Sdarrenrextern int selwait; 135145522Sdarrenr# endif /* IPL_SELECT */ 136145522Sdarrenr 137255332Scytypedef struct ipf_log_softc_s { 138255332Scy ipfmutex_t ipl_mutex[IPL_LOGSIZE]; 139255332Scy# if SOLARIS && defined(_KERNEL) 140255332Scy kcondvar_t ipl_wait[IPL_LOGSIZE]; 141255332Scy# endif 142145522Sdarrenr# if defined(linux) && defined(_KERNEL) 143255332Scy wait_queue_head_t iplh_linux[IPL_LOGSIZE]; 144145522Sdarrenr# endif 145255332Scy# if defined(__hpux) && defined(_KERNEL) 146255332Scy iplog_select_t ipl_ss[IPL_LOGSIZE]; 14753642Sguido# endif 148255332Scy iplog_t **iplh[IPL_LOGSIZE]; 149255332Scy iplog_t *iplt[IPL_LOGSIZE]; 150255332Scy iplog_t *ipll[IPL_LOGSIZE]; 151255332Scy u_long ipl_logfail[IPL_LOGSIZE]; 152255332Scy u_long ipl_logok[IPL_LOGSIZE]; 153255332Scy fr_info_t ipl_crc[IPL_LOGSIZE]; 154255332Scy u_32_t ipl_counter[IPL_LOGSIZE]; 155255332Scy int ipl_suppress; 156255332Scy int ipl_logall; 157255332Scy int ipl_log_init; 158255332Scy int ipl_logsize; 159255332Scy int ipl_used[IPL_LOGSIZE]; 160255332Scy int ipl_magic[IPL_LOGSIZE]; 161255332Scy ipftuneable_t *ipf_log_tune; 162255332Scy int ipl_readers[IPL_LOGSIZE]; 163255332Scy} ipf_log_softc_t; 16453642Sguido 165255332Scystatic int magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE, 166255332Scy IPL_MAGIC, IPL_MAGIC, IPL_MAGIC, 167255332Scy IPL_MAGIC, IPL_MAGIC }; 16853642Sguido 169255332Scystatic ipftuneable_t ipf_log_tuneables[] = { 170255332Scy /* log */ 171255332Scy { { (void *)offsetof(ipf_log_softc_t, ipl_suppress) }, 172255332Scy "log_suppress", 0, 1, 173255332Scy stsizeof(ipf_log_softc_t, ipl_suppress), 174255332Scy 0, NULL, NULL }, 175255332Scy { { (void *)offsetof(ipf_log_softc_t, ipl_logall) }, 176255332Scy "log_all", 0, 1, 177255332Scy stsizeof(ipf_log_softc_t, ipl_logall), 178255332Scy 0, NULL, NULL }, 179255332Scy { { (void *)offsetof(ipf_log_softc_t, ipl_logsize) }, 180255332Scy "log_size", 0, 0x80000, 181255332Scy stsizeof(ipf_log_softc_t, ipl_logsize), 182255332Scy 0, NULL, NULL }, 183255332Scy { { NULL }, NULL, 0, 0, 184255332Scy 0, 185255332Scy 0, NULL, NULL } 186255332Scy}; 18753642Sguido 188255332Scy 189255332Scyint 190255332Scyipf_log_main_load() 191255332Scy{ 192255332Scy return 0; 193255332Scy} 194255332Scy 195255332Scy 196255332Scyint 197255332Scyipf_log_main_unload() 198255332Scy{ 199255332Scy return 0; 200255332Scy} 201255332Scy 202145522Sdarrenr/* ------------------------------------------------------------------------ */ 203255332Scy/* Function: ipf_log_soft_create */ 204255332Scy/* Returns: void * - NULL = failure, else pointer to log context data */ 205255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 206255332Scy/* */ 207255332Scy/* Initialise log buffers & pointers. Also iniialised the CRC to a local */ 208255332Scy/* secret for use in calculating the "last log checksum". */ 209255332Scy/* ------------------------------------------------------------------------ */ 210255332Scyvoid * 211255332Scyipf_log_soft_create(softc) 212255332Scy ipf_main_softc_t *softc; 213255332Scy{ 214255332Scy ipf_log_softc_t *softl; 215267020Scy int i; 216255332Scy 217255332Scy KMALLOC(softl, ipf_log_softc_t *); 218255332Scy if (softl == NULL) 219255332Scy return NULL; 220255332Scy 221255332Scy bzero((char *)softl, sizeof(*softl)); 222255332Scy bcopy((char *)magic, (char *)softl->ipl_magic, sizeof(magic)); 223255332Scy 224255332Scy softl->ipf_log_tune = ipf_tune_array_copy(softl, 225255332Scy sizeof(ipf_log_tuneables), 226255332Scy ipf_log_tuneables); 227255332Scy if (softl->ipf_log_tune == NULL) { 228255332Scy ipf_log_soft_destroy(softc, softl); 229255332Scy return NULL; 230255332Scy } 231255332Scy if (ipf_tune_array_link(softc, softl->ipf_log_tune) == -1) { 232255332Scy ipf_log_soft_destroy(softc, softl); 233255332Scy return NULL; 234255332Scy } 235255332Scy 236267020Scy for (i = IPL_LOGMAX; i >= 0; i--) { 237267020Scy MUTEX_INIT(&softl->ipl_mutex[i], "ipf log mutex"); 238267020Scy } 239267020Scy 240255332Scy softl->ipl_suppress = 1; 241255332Scy softl->ipl_logall = 0; 242255332Scy softl->ipl_log_init = 0; 243255332Scy softl->ipl_logsize = IPFILTER_LOGSIZE; 244255332Scy 245255332Scy return softl; 246255332Scy} 247255332Scy 248255332Scy/* ------------------------------------------------------------------------ */ 249255332Scy/* Function: ipf_log_soft_init */ 250145522Sdarrenr/* Returns: int - 0 == success (always returned) */ 251255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 252145522Sdarrenr/* */ 253145522Sdarrenr/* Initialise log buffers & pointers. Also iniialised the CRC to a local */ 254145522Sdarrenr/* secret for use in calculating the "last log checksum". */ 255145522Sdarrenr/* ------------------------------------------------------------------------ */ 256255332Scyint 257255332Scyipf_log_soft_init(softc, arg) 258255332Scy ipf_main_softc_t *softc; 259255332Scy void *arg; 26053642Sguido{ 261255332Scy ipf_log_softc_t *softl = arg; 262255332Scy int i; 26353642Sguido 26453642Sguido for (i = IPL_LOGMAX; i >= 0; i--) { 265255332Scy softl->iplt[i] = NULL; 266255332Scy softl->ipll[i] = NULL; 267255332Scy softl->iplh[i] = &softl->iplt[i]; 268255332Scy bzero((char *)&softl->ipl_crc[i], sizeof(softl->ipl_crc[i])); 269145522Sdarrenr# ifdef IPL_SELECT 270255332Scy softl->iplog_ss[i].read_waiter = 0; 271255332Scy softl->iplog_ss[i].state = 0; 272145522Sdarrenr# endif 273255332Scy } 274145522Sdarrenr 275145522Sdarrenr 276255332Scy softl->ipl_log_init = 1; 277255332Scy 278145522Sdarrenr return 0; 27953642Sguido} 28053642Sguido 28153642Sguido 282145522Sdarrenr/* ------------------------------------------------------------------------ */ 283255332Scy/* Function: ipf_log_soft_fini */ 284255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 285255332Scy/* arg(I) - pointer to log context structure */ 286145522Sdarrenr/* */ 287145522Sdarrenr/* Clean up any log data that has accumulated without being read. */ 288145522Sdarrenr/* ------------------------------------------------------------------------ */ 289255332Scyint 290255332Scyipf_log_soft_fini(softc, arg) 291255332Scy ipf_main_softc_t *softc; 292255332Scy void *arg; 293145522Sdarrenr{ 294255332Scy ipf_log_softc_t *softl = arg; 295145522Sdarrenr int i; 296145522Sdarrenr 297255332Scy if (softl->ipl_log_init == 0) 298255332Scy return 0; 299145522Sdarrenr 300255332Scy softl->ipl_log_init = 0; 301145522Sdarrenr 302255332Scy for (i = IPL_LOGMAX; i >= 0; i--) { 303255332Scy (void) ipf_log_clear(softc, i); 304255332Scy 305255332Scy /* 306255332Scy * This is a busy-wait loop so as to avoid yet another lock 307255332Scy * to wait on. 308255332Scy */ 309255332Scy MUTEX_ENTER(&softl->ipl_mutex[i]); 310255332Scy while (softl->ipl_readers[i] > 0) { 311145522Sdarrenr# if SOLARIS && defined(_KERNEL) 312255332Scy cv_broadcast(&softl->ipl_wait[i]); 313255332Scy MUTEX_EXIT(&softl->ipl_mutex[i]); 314255332Scy delay(100); 315255332Scy pollwakeup(&softc->ipf_poll_head[i], POLLRDNORM); 316255332Scy# else 317255332Scy MUTEX_EXIT(&softl->ipl_mutex[i]); 318255332Scy WAKEUP(softl->iplh, i); 319255332Scy POLLWAKEUP(i); 320145522Sdarrenr# endif 321255332Scy MUTEX_ENTER(&softl->ipl_mutex[i]); 322255332Scy } 323267020Scy MUTEX_EXIT(&softl->ipl_mutex[i]); 324255332Scy } 325145522Sdarrenr 326255332Scy return 0; 327145522Sdarrenr} 328145522Sdarrenr 329145522Sdarrenr 330145522Sdarrenr/* ------------------------------------------------------------------------ */ 331255332Scy/* Function: ipf_log_soft_destroy */ 332255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 333255332Scy/* arg(I) - pointer to log context structure */ 334255332Scy/* */ 335255332Scy/* When this function is called, it is expected that there are no longer */ 336255332Scy/* any threads active in the reading code path or the logging code path. */ 337255332Scy/* ------------------------------------------------------------------------ */ 338255332Scyvoid 339255332Scyipf_log_soft_destroy(softc, arg) 340255332Scy ipf_main_softc_t *softc; 341255332Scy void *arg; 342255332Scy{ 343255332Scy ipf_log_softc_t *softl = arg; 344255332Scy int i; 345255332Scy 346255332Scy for (i = IPL_LOGMAX; i >= 0; i--) { 347255332Scy# if SOLARIS && defined(_KERNEL) 348255332Scy cv_destroy(&softl->ipl_wait[i]); 349255332Scy# endif 350255332Scy MUTEX_DESTROY(&softl->ipl_mutex[i]); 351255332Scy } 352255332Scy 353255332Scy if (softl->ipf_log_tune != NULL) { 354255332Scy ipf_tune_array_unlink(softc, softl->ipf_log_tune); 355255332Scy KFREES(softl->ipf_log_tune, sizeof(ipf_log_tuneables)); 356255332Scy softl->ipf_log_tune = NULL; 357255332Scy } 358255332Scy 359255332Scy KFREE(softl); 360255332Scy} 361255332Scy 362255332Scy 363255332Scy/* ------------------------------------------------------------------------ */ 364255332Scy/* Function: ipf_log_pkt */ 365255332Scy/* Returns: int - 0 == success, -1 == failure */ 366145522Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 367145522Sdarrenr/* flags(I) - flags from filter rules */ 368145522Sdarrenr/* */ 369145522Sdarrenr/* Create a log record for a packet given that it has been triggered by a */ 370145522Sdarrenr/* rule (or the default setting). Calculate the transport protocol header */ 371145522Sdarrenr/* size using predetermined size of a couple of popular protocols and thus */ 372145522Sdarrenr/* how much data to copy into the log, including part of the data body if */ 373145522Sdarrenr/* requested. */ 374145522Sdarrenr/* ------------------------------------------------------------------------ */ 375255332Scyint 376255332Scyipf_log_pkt(fin, flags) 377255332Scy fr_info_t *fin; 378255332Scy u_int flags; 37953642Sguido{ 380255332Scy ipf_main_softc_t *softc = fin->fin_main_soft; 381255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 382145522Sdarrenr register size_t hlen; 383145522Sdarrenr int types[2], mlen; 38453642Sguido size_t sizes[2]; 38553642Sguido void *ptrs[2]; 386145522Sdarrenr ipflog_t ipfl; 38760857Sdarrenr u_char p; 388145522Sdarrenr mb_t *m; 389255332Scy# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && !defined(FW_HOOKS) 390145522Sdarrenr qif_t *ifp; 39153642Sguido# else 392145522Sdarrenr struct ifnet *ifp; 393145522Sdarrenr# endif /* SOLARIS || __hpux */ 39453642Sguido 395170268Sdarrenr m = fin->fin_m; 396170268Sdarrenr if (m == NULL) 397170268Sdarrenr return -1; 398170268Sdarrenr 399145522Sdarrenr ipfl.fl_nattag.ipt_num[0] = 0; 400145522Sdarrenr ifp = fin->fin_ifp; 401255332Scy hlen = (char *)fin->fin_dp - (char *)fin->fin_ip; 402255332Scy 40353642Sguido /* 40453642Sguido * calculate header size. 40553642Sguido */ 40660857Sdarrenr if (fin->fin_off == 0) { 40760857Sdarrenr p = fin->fin_fi.fi_p; 40860857Sdarrenr if (p == IPPROTO_TCP) 40953642Sguido hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); 41060857Sdarrenr else if (p == IPPROTO_UDP) 41153642Sguido hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); 41260857Sdarrenr else if (p == IPPROTO_ICMP) { 41360857Sdarrenr struct icmp *icmp; 41453642Sguido 41560857Sdarrenr icmp = (struct icmp *)fin->fin_dp; 416255332Scy 41753642Sguido /* 41853642Sguido * For ICMP, if the packet is an error packet, also 41953642Sguido * include the information about the packet which 42053642Sguido * caused the error. 42153642Sguido */ 42253642Sguido switch (icmp->icmp_type) 42353642Sguido { 42453642Sguido case ICMP_UNREACH : 42553642Sguido case ICMP_SOURCEQUENCH : 42653642Sguido case ICMP_REDIRECT : 42753642Sguido case ICMP_TIMXCEED : 42853642Sguido case ICMP_PARAMPROB : 42953642Sguido hlen += MIN(sizeof(struct icmp) + 8, 43053642Sguido fin->fin_dlen); 43153642Sguido break; 43253642Sguido default : 43353642Sguido hlen += MIN(sizeof(struct icmp), 43453642Sguido fin->fin_dlen); 43553642Sguido break; 43653642Sguido } 43753642Sguido } 438145522Sdarrenr# ifdef USE_INET6 439110916Sdarrenr else if (p == IPPROTO_ICMPV6) { 440110916Sdarrenr struct icmp6_hdr *icmp; 441110916Sdarrenr 442110916Sdarrenr icmp = (struct icmp6_hdr *)fin->fin_dp; 443145522Sdarrenr 444110916Sdarrenr /* 445110916Sdarrenr * For ICMPV6, if the packet is an error packet, also 446110916Sdarrenr * include the information about the packet which 447110916Sdarrenr * caused the error. 448110916Sdarrenr */ 449110916Sdarrenr if (icmp->icmp6_type < 128) { 450110916Sdarrenr hlen += MIN(sizeof(struct icmp6_hdr) + 8, 451110916Sdarrenr fin->fin_dlen); 452110916Sdarrenr } else { 453110916Sdarrenr hlen += MIN(sizeof(struct icmp6_hdr), 454110916Sdarrenr fin->fin_dlen); 455110916Sdarrenr } 456110916Sdarrenr } 457145522Sdarrenr# endif 45853642Sguido } 45953642Sguido /* 46053642Sguido * Get the interface number and name to which this packet is 46153642Sguido * currently associated. 46253642Sguido */ 463255332Scy# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) 464255332Scy# if !defined(FW_HOOKS) 465145522Sdarrenr ipfl.fl_unit = (u_int)ifp->qf_ppa; 466255332Scy# endif 467172776Sdarrenr COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname); 46853642Sguido# else 469255332Scy# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ 470255332Scy OPENBSD_GE_REV(199603) || defined(linux) || FREEBSD_GE_REV(501113) 471172776Sdarrenr COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname); 47253642Sguido# else 473130886Sdarrenr ipfl.fl_unit = (u_int)ifp->if_unit; 474145522Sdarrenr# if defined(_KERNEL) 475145522Sdarrenr if ((ipfl.fl_ifname[0] = ifp->if_name[0])) 476145522Sdarrenr if ((ipfl.fl_ifname[1] = ifp->if_name[1])) 477145522Sdarrenr if ((ipfl.fl_ifname[2] = ifp->if_name[2])) 478145522Sdarrenr ipfl.fl_ifname[3] = ifp->if_name[3]; 479145522Sdarrenr# else 480255332Scy (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); 481145522Sdarrenr ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0'; 482145522Sdarrenr# endif 48353642Sguido# endif 484145522Sdarrenr# endif /* __hpux || SOLARIS */ 485145522Sdarrenr mlen = fin->fin_plen - hlen; 486255332Scy if (!softl->ipl_logall) { 487145522Sdarrenr mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0; 488145522Sdarrenr } else if ((flags & FR_LOGBODY) == 0) { 489145522Sdarrenr mlen = 0; 490145522Sdarrenr } 491145522Sdarrenr if (mlen < 0) 492145522Sdarrenr mlen = 0; 49353642Sguido ipfl.fl_plen = (u_char)mlen; 49453642Sguido ipfl.fl_hlen = (u_char)hlen; 49553642Sguido ipfl.fl_rule = fin->fin_rule; 496145522Sdarrenr (void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN); 497145522Sdarrenr if (fin->fin_fr != NULL) { 49853642Sguido ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; 499145522Sdarrenr ipfl.fl_logtag = fin->fin_fr->fr_logtag; 500145522Sdarrenr } else { 50153642Sguido ipfl.fl_loglevel = 0xffff; 502145522Sdarrenr ipfl.fl_logtag = FR_NOLOGTAG; 503145522Sdarrenr } 504145522Sdarrenr if (fin->fin_nattag != NULL) 505145522Sdarrenr bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag, 506145522Sdarrenr sizeof(ipfl.fl_nattag)); 50753642Sguido ipfl.fl_flags = flags; 508255332Scy ipfl.fl_breason = (fin->fin_reason & 0xff); 50992685Sdarrenr ipfl.fl_dir = fin->fin_out; 510145522Sdarrenr ipfl.fl_lflags = fin->fin_flx; 511255332Scy ipfl.fl_family = fin->fin_family; 51253642Sguido ptrs[0] = (void *)&ipfl; 51353642Sguido sizes[0] = sizeof(ipfl); 51453642Sguido types[0] = 0; 515145522Sdarrenr# if defined(MENTAT) && defined(_KERNEL) 51653642Sguido /* 51753642Sguido * Are we copied from the mblk or an aligned array ? 51853642Sguido */ 519145522Sdarrenr if (fin->fin_ip == (ip_t *)m->b_rptr) { 52053642Sguido ptrs[1] = m; 52153642Sguido sizes[1] = hlen + mlen; 52253642Sguido types[1] = 1; 52353642Sguido } else { 524145522Sdarrenr ptrs[1] = fin->fin_ip; 52553642Sguido sizes[1] = hlen + mlen; 52653642Sguido types[1] = 0; 52753642Sguido } 52853642Sguido# else 52953642Sguido ptrs[1] = m; 53053642Sguido sizes[1] = hlen + mlen; 53153642Sguido types[1] = 1; 532145522Sdarrenr# endif /* MENTAT */ 533255332Scy return ipf_log_items(softc, IPL_LOGIPF, fin, ptrs, sizes, types, 2); 53453642Sguido} 53553642Sguido 53653642Sguido 537145522Sdarrenr/* ------------------------------------------------------------------------ */ 538255332Scy/* Function: ipf_log_items */ 539255332Scy/* Returns: int - 0 == success, -1 == failure */ 540255332Scy/* Parameters: softc(I) - pointer to main soft context */ 541255332Scy/* unit(I) - device we are reading from */ 542145522Sdarrenr/* fin(I) - pointer to packet information */ 543145522Sdarrenr/* items(I) - array of pointers to log data */ 544145522Sdarrenr/* itemsz(I) - array of size of valid memory pointed to */ 545145522Sdarrenr/* types(I) - type of data pointed to by items pointers */ 546145522Sdarrenr/* cnt(I) - number of elements in arrays items/itemsz/types */ 547145522Sdarrenr/* */ 548145522Sdarrenr/* Takes an array of parameters and constructs one record to include the */ 549145522Sdarrenr/* miscellaneous packet information, as well as packet data, for reading */ 550145522Sdarrenr/* from the log device. */ 551145522Sdarrenr/* ------------------------------------------------------------------------ */ 552255332Scyint 553255332Scyipf_log_items(softc, unit, fin, items, itemsz, types, cnt) 554255332Scy ipf_main_softc_t *softc; 555255332Scy int unit; 556255332Scy fr_info_t *fin; 557255332Scy void **items; 558255332Scy size_t *itemsz; 559255332Scy int *types, cnt; 56053642Sguido{ 561255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 562255332Scy caddr_t buf, ptr; 56353642Sguido iplog_t *ipl; 56453642Sguido size_t len; 56553642Sguido int i; 566153876Sguido SPL_INT(s); 567145522Sdarrenr 56853642Sguido /* 56953642Sguido * Get the total amount of data to be logged. 57053642Sguido */ 571145522Sdarrenr for (i = 0, len = sizeof(iplog_t); i < cnt; i++) 57253642Sguido len += itemsz[i]; 57353642Sguido 574255332Scy SPL_NET(s); 575255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 576255332Scy softl->ipl_counter[unit]++; 57753642Sguido /* 57853642Sguido * check that we have space to record this information and can 57953642Sguido * allocate that much. 58053642Sguido */ 581255332Scy if ((softl->ipl_used[unit] + len) > softl->ipl_logsize) { 582255332Scy softl->ipl_logfail[unit]++; 583255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 584145522Sdarrenr return -1; 585255332Scy } 586255332Scy 587255332Scy KMALLOCS(buf, caddr_t, len); 588255332Scy if (buf == NULL) { 589255332Scy softl->ipl_logfail[unit]++; 590255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 591145522Sdarrenr return -1; 59253642Sguido } 59353642Sguido ipl = (iplog_t *)buf; 594255332Scy ipl->ipl_magic = softl->ipl_magic[unit]; 59553642Sguido ipl->ipl_count = 1; 596255332Scy ipl->ipl_seqnum = softl->ipl_counter[unit]; 59753642Sguido ipl->ipl_next = NULL; 59853642Sguido ipl->ipl_dsize = len; 599145522Sdarrenr#ifdef _KERNEL 600145522Sdarrenr GETKTIME(&ipl->ipl_sec); 601145522Sdarrenr#else 60292685Sdarrenr ipl->ipl_sec = 0; 60392685Sdarrenr ipl->ipl_usec = 0; 604145522Sdarrenr#endif 60553642Sguido 60653642Sguido /* 60753642Sguido * Loop through all the items to be logged, copying each one to the 60853642Sguido * buffer. Use bcopy for normal data or the mb_t copyout routine. 60953642Sguido */ 610145522Sdarrenr for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) { 611145522Sdarrenr if (types[i] == 0) { 612145522Sdarrenr bcopy(items[i], ptr, itemsz[i]); 613145522Sdarrenr } else if (types[i] == 1) { 614255332Scy COPYDATA(items[i], 0, itemsz[i], ptr); 61553642Sguido } 616145522Sdarrenr ptr += itemsz[i]; 61753642Sguido } 618255332Scy /* 619255332Scy * Check to see if this log record has a CRC which matches the last 620255332Scy * record logged. If it does, just up the count on the previous one 621255332Scy * rather than create a new one. 622255332Scy */ 623255332Scy if (softl->ipl_suppress) { 624255332Scy if ((fin != NULL) && (fin->fin_off == 0)) { 625255332Scy if ((softl->ipll[unit] != NULL) && 626255332Scy (fin->fin_crc == softl->ipl_crc[unit].fin_crc) && 627255332Scy bcmp((char *)fin, (char *)&softl->ipl_crc[unit], 628255332Scy FI_LCSIZE) == 0) { 629255332Scy softl->ipll[unit]->ipl_count++; 630255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 631255332Scy SPL_X(s); 632255332Scy KFREES(buf, len); 633255332Scy return 0; 634255332Scy } 635255332Scy bcopy((char *)fin, (char *)&softl->ipl_crc[unit], 636255332Scy FI_LCSIZE); 637255332Scy softl->ipl_crc[unit].fin_crc = fin->fin_crc; 638255332Scy } else 639255332Scy bzero((char *)&softl->ipl_crc[unit], FI_CSIZE); 640255332Scy } 641145522Sdarrenr 642145522Sdarrenr /* 643255332Scy * advance the log pointer to the next empty record and deduct the 644255332Scy * amount of space we're going to use. 645255332Scy */ 646255332Scy softl->ipl_logok[unit]++; 647255332Scy softl->ipll[unit] = ipl; 648255332Scy *softl->iplh[unit] = ipl; 649255332Scy softl->iplh[unit] = &ipl->ipl_next; 650255332Scy softl->ipl_used[unit] += len; 651255332Scy 652255332Scy /* 653145522Sdarrenr * Now that the log record has been completed and added to the queue, 654145522Sdarrenr * wake up any listeners who may want to read it. 655145522Sdarrenr */ 65692685Sdarrenr# if SOLARIS && defined(_KERNEL) 657255332Scy cv_signal(&softl->ipl_wait[unit]); 658255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 659255332Scy pollwakeup(&softc->ipf_poll_head[unit], POLLRDNORM); 66053642Sguido# else 661255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 662255332Scy WAKEUP(softl->iplh, unit); 663255332Scy POLLWAKEUP(unit); 66453642Sguido# endif 665145522Sdarrenr SPL_X(s); 666145522Sdarrenr# ifdef IPL_SELECT 667255332Scy iplog_input_ready(unit); 668145522Sdarrenr# endif 669145522Sdarrenr return 0; 67053642Sguido} 67153642Sguido 67253642Sguido 673145522Sdarrenr/* ------------------------------------------------------------------------ */ 674255332Scy/* Function: ipf_log_read */ 675255332Scy/* Returns: int - 0 == success, else error value. */ 676255332Scy/* Parameters: softc(I) - pointer to main soft context */ 677255332Scy/* unit(I) - device we are reading from */ 678255332Scy/* uio(O) - pointer to information about where to store data */ 679145522Sdarrenr/* */ 680145522Sdarrenr/* Called to handle a read on an IPFilter device. Returns only complete */ 681145522Sdarrenr/* log messages - will not partially copy a log record out to userland. */ 682145522Sdarrenr/* */ 683145522Sdarrenr/* NOTE: This function will block and wait for a signal to return data if */ 684145522Sdarrenr/* there is none present. Asynchronous I/O is not implemented. */ 685145522Sdarrenr/* ------------------------------------------------------------------------ */ 686255332Scyint 687255332Scyipf_log_read(softc, unit, uio) 688255332Scy ipf_main_softc_t *softc; 689255332Scy minor_t unit; 690255332Scy struct uio *uio; 69153642Sguido{ 692255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 69353642Sguido size_t dlen, copied; 69453642Sguido int error = 0; 69553642Sguido iplog_t *ipl; 696153876Sguido SPL_INT(s); 69753642Sguido 698255332Scy if (softl->ipl_log_init == 0) { 699255332Scy IPFERROR(40007); 700255332Scy return 0; 701255332Scy } 702255332Scy 70353642Sguido /* 70453642Sguido * Sanity checks. Make sure the minor # is valid and we're copying 70553642Sguido * a valid chunk of data. 70653642Sguido */ 707255332Scy if (IPL_LOGMAX < unit) { 708255332Scy IPFERROR(40001); 70953642Sguido return ENXIO; 710255332Scy } 711145522Sdarrenr if (uio->uio_resid == 0) 71253642Sguido return 0; 713255332Scy 714255332Scy if (uio->uio_resid < sizeof(iplog_t)) { 715255332Scy IPFERROR(40002); 71653642Sguido return EINVAL; 717255332Scy } 718255332Scy if (uio->uio_resid > softl->ipl_logsize) { 719255332Scy IPFERROR(40005); 720255332Scy return EINVAL; 721255332Scy } 722145522Sdarrenr 72353642Sguido /* 72453642Sguido * Lock the log so we can snapshot the variables. Wait for a signal 72553642Sguido * if the log is empty. 72653642Sguido */ 72753642Sguido SPL_NET(s); 728255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 729255332Scy softl->ipl_readers[unit]++; 73053642Sguido 731255332Scy while (softl->ipl_log_init == 1 && softl->iplt[unit] == NULL) { 73253642Sguido# if SOLARIS && defined(_KERNEL) 733255332Scy if (!cv_wait_sig(&softl->ipl_wait[unit], 734255332Scy &softl->ipl_mutex[unit].ipf_lk)) { 735255332Scy softl->ipl_readers[unit]--; 736255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 737255332Scy IPFERROR(40003); 73853642Sguido return EINTR; 73953642Sguido } 74053642Sguido# else 741145522Sdarrenr# if defined(__hpux) && defined(_KERNEL) 742145522Sdarrenr lock_t *l; 743145522Sdarrenr 744145522Sdarrenr# ifdef IPL_SELECT 745145522Sdarrenr if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) { 746145522Sdarrenr /* this is no blocking system call */ 747255332Scy softl->ipl_readers[unit]--; 748255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 749145522Sdarrenr return 0; 750145522Sdarrenr } 751145522Sdarrenr# endif 752145522Sdarrenr 753255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 754255332Scy l = get_sleep_lock(&softl->iplh[unit]); 755255332Scy error = sleep(&softl->iplh[unit], PZERO+1); 756145522Sdarrenr spinunlock(l); 757145522Sdarrenr# else 758145522Sdarrenr# if defined(__osf__) && defined(_KERNEL) 759255332Scy error = mpsleep(&softl->iplh[unit], PSUSP|PCATCH, "ipfread", 0, 760255332Scy &softl->ipl_mutex, MS_LOCK_SIMPLE); 761145522Sdarrenr# else 762255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 763145522Sdarrenr SPL_X(s); 764255332Scy error = SLEEP(unit + softl->iplh, "ipl sleep"); 765145522Sdarrenr# endif /* __osf__ */ 766145522Sdarrenr# endif /* __hpux */ 767255332Scy SPL_NET(s); 768255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 769255332Scy if (error) { 770255332Scy softl->ipl_readers[unit]--; 771255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 772255332Scy IPFERROR(40004); 77353642Sguido return error; 774255332Scy } 77553642Sguido# endif /* SOLARIS */ 77653642Sguido } 777255332Scy if (softl->ipl_log_init != 1) { 778255332Scy softl->ipl_readers[unit]--; 779255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 780255332Scy IPFERROR(40008); 781255332Scy return EIO; 782255332Scy } 78353642Sguido 784255332Scy# if (defined(BSD) && (BSD >= 199101)) || defined(__FreeBSD__) || \ 785255332Scy defined(__osf__) 78653642Sguido uio->uio_rw = UIO_READ; 78753642Sguido# endif 78853642Sguido 789255332Scy for (copied = 0; (ipl = softl->iplt[unit]) != NULL; copied += dlen) { 79053642Sguido dlen = ipl->ipl_dsize; 79153642Sguido if (dlen > uio->uio_resid) 79253642Sguido break; 79353642Sguido /* 79453642Sguido * Don't hold the mutex over the uiomove call. 79553642Sguido */ 796255332Scy softl->iplt[unit] = ipl->ipl_next; 797255332Scy softl->ipl_used[unit] -= dlen; 798255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 799145522Sdarrenr SPL_X(s); 800172776Sdarrenr error = UIOMOVE(ipl, dlen, UIO_READ, uio); 80153642Sguido if (error) { 802145522Sdarrenr SPL_NET(s); 803255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 804255332Scy IPFERROR(40006); 805255332Scy ipl->ipl_next = softl->iplt[unit]; 806255332Scy softl->iplt[unit] = ipl; 807255332Scy softl->ipl_used[unit] += dlen; 80853642Sguido break; 80953642Sguido } 810255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 811255332Scy KFREES((caddr_t)ipl, dlen); 812145522Sdarrenr SPL_NET(s); 81353642Sguido } 814255332Scy if (!softl->iplt[unit]) { 815255332Scy softl->ipl_used[unit] = 0; 816255332Scy softl->iplh[unit] = &softl->iplt[unit]; 817255332Scy softl->ipll[unit] = NULL; 81853642Sguido } 81953642Sguido 820255332Scy softl->ipl_readers[unit]--; 821255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 82253642Sguido SPL_X(s); 82353642Sguido return error; 82453642Sguido} 82553642Sguido 82653642Sguido 827145522Sdarrenr/* ------------------------------------------------------------------------ */ 828255332Scy/* Function: ipf_log_clear */ 829255332Scy/* Returns: int - number of log bytes cleared. */ 830255332Scy/* Parameters: softc(I) - pointer to main soft context */ 831255332Scy/* unit(I) - device we are reading from */ 832145522Sdarrenr/* */ 833145522Sdarrenr/* Deletes all queued up log records for a given output device. */ 834145522Sdarrenr/* ------------------------------------------------------------------------ */ 835255332Scyint 836255332Scyipf_log_clear(softc, unit) 837255332Scy ipf_main_softc_t *softc; 838255332Scy minor_t unit; 83953642Sguido{ 840255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 84153642Sguido iplog_t *ipl; 84253642Sguido int used; 843153876Sguido SPL_INT(s); 84453642Sguido 845145522Sdarrenr SPL_NET(s); 846255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 847255332Scy while ((ipl = softl->iplt[unit]) != NULL) { 848255332Scy softl->iplt[unit] = ipl->ipl_next; 849255332Scy KFREES((caddr_t)ipl, ipl->ipl_dsize); 85053642Sguido } 851255332Scy softl->iplh[unit] = &softl->iplt[unit]; 852255332Scy softl->ipll[unit] = NULL; 853255332Scy used = softl->ipl_used[unit]; 854255332Scy softl->ipl_used[unit] = 0; 855255332Scy bzero((char *)&softl->ipl_crc[unit], FI_CSIZE); 856255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 857145522Sdarrenr SPL_X(s); 85853642Sguido return used; 85953642Sguido} 860161356Sguido 861161356Sguido 862161356Sguido/* ------------------------------------------------------------------------ */ 863255332Scy/* Function: ipf_log_canread */ 864255332Scy/* Returns: int - 0 == no data to read, 1 = data present */ 865255332Scy/* Parameters: softc(I) - pointer to main soft context */ 866255332Scy/* unit(I) - device we are reading from */ 867161356Sguido/* */ 868161356Sguido/* Returns an indication of whether or not there is data present in the */ 869161356Sguido/* current buffer for the selected ipf device. */ 870161356Sguido/* ------------------------------------------------------------------------ */ 871255332Scyint 872255332Scyipf_log_canread(softc, unit) 873255332Scy ipf_main_softc_t *softc; 874255332Scy int unit; 875161356Sguido{ 876255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 877255332Scy 878255332Scy return softl->iplt[unit] != NULL; 879161356Sguido} 880255332Scy 881255332Scy 882255332Scy/* ------------------------------------------------------------------------ */ 883255332Scy/* Function: ipf_log_canread */ 884255332Scy/* Returns: int - 0 == no data to read, 1 = data present */ 885255332Scy/* Parameters: softc(I) - pointer to main soft context */ 886255332Scy/* unit(I) - device we are reading from */ 887255332Scy/* */ 888255332Scy/* Returns how many bytes are currently held in log buffers for the */ 889255332Scy/* selected ipf device. */ 890255332Scy/* ------------------------------------------------------------------------ */ 891255332Scyint 892255332Scyipf_log_bytesused(softc, unit) 893255332Scy ipf_main_softc_t *softc; 894255332Scy int unit; 895255332Scy{ 896255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 897255332Scy 898255332Scy if (softl == NULL) 899255332Scy return 0; 900255332Scy 901255332Scy return softl->ipl_used[unit]; 902255332Scy} 903255332Scy 904255332Scy 905255332Scy/* ------------------------------------------------------------------------ */ 906255332Scy/* Function: ipf_log_failures */ 907255332Scy/* Returns: U_QUAD_T - number of log failures */ 908255332Scy/* Parameters: softc(I) - pointer to main soft context */ 909255332Scy/* unit(I) - device we are reading from */ 910255332Scy/* */ 911255332Scy/* Returns how many times we've tried to log a packet but failed to do so */ 912255332Scy/* for the selected ipf device. */ 913255332Scy/* ------------------------------------------------------------------------ */ 914255332Scyu_long 915255332Scyipf_log_failures(softc, unit) 916255332Scy ipf_main_softc_t *softc; 917255332Scy int unit; 918255332Scy{ 919255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 920255332Scy 921255332Scy if (softl == NULL) 922255332Scy return 0; 923255332Scy 924255332Scy return softl->ipl_logfail[unit]; 925255332Scy} 926255332Scy 927255332Scy 928255332Scy/* ------------------------------------------------------------------------ */ 929255332Scy/* Function: ipf_log_logok */ 930255332Scy/* Returns: U_QUAD_T - number of packets logged */ 931255332Scy/* Parameters: softc(I) - pointer to main soft context */ 932255332Scy/* unit(I) - device we are reading from */ 933255332Scy/* */ 934255332Scy/* Returns how many times we've successfully logged a packet for the */ 935255332Scy/* selected ipf device. */ 936255332Scy/* ------------------------------------------------------------------------ */ 937255332Scyu_long 938255332Scyipf_log_logok(softc, unit) 939255332Scy ipf_main_softc_t *softc; 940255332Scy int unit; 941255332Scy{ 942255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 943255332Scy 944255332Scy if (softl == NULL) 945255332Scy return 0; 946255332Scy 947255332Scy return softl->ipl_logok[unit]; 948255332Scy} 94953642Sguido#endif /* IPFILTER_LOG */ 950