1145522Sdarrenr/* $FreeBSD$ */ 2145522Sdarrenr 353642Sguido/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 553642Sguido * 680482Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 753642Sguido * 857126Sguido * $FreeBSD$ 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 22145522Sdarrenr# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) 23145522Sdarrenr#endif 24145522Sdarrenr#include <sys/errno.h> 25145522Sdarrenr#include <sys/types.h> 26145522Sdarrenr#include <sys/file.h> 27145522Sdarrenr#ifndef _KERNEL 28145522Sdarrenr# include <stdio.h> 29145522Sdarrenr# include <string.h> 30145522Sdarrenr# include <stdlib.h> 31145522Sdarrenr# include <ctype.h> 32145522Sdarrenr# define _KERNEL 33145522Sdarrenr# define KERNEL 34145522Sdarrenr# ifdef __OpenBSD__ 35145522Sdarrenrstruct file; 3653642Sguido# endif 37145522Sdarrenr# include <sys/uio.h> 38145522Sdarrenr# undef _KERNEL 39145522Sdarrenr# undef KERNEL 40145522Sdarrenr#endif 41173181Sdarrenr#if (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) && \ 42173181Sdarrenr defined(_KERNEL) 43145522Sdarrenr# include <sys/fcntl.h> 44145522Sdarrenr# include <sys/filio.h> 45145522Sdarrenr#else 46145522Sdarrenr# include <sys/ioctl.h> 47145522Sdarrenr#endif 48145522Sdarrenr#include <sys/time.h> 49145522Sdarrenr#if defined(_KERNEL) 50145522Sdarrenr# include <sys/systm.h> 51173181Sdarrenr# if (defined(NetBSD) && (__NetBSD_Version__ >= 104000000)) 52145522Sdarrenr# include <sys/proc.h> 5353642Sguido# endif 54145522Sdarrenr#endif /* _KERNEL */ 55145522Sdarrenr#if !SOLARIS && !defined(__hpux) && !defined(linux) 56173181Sdarrenr# if (defined(NetBSD) && (NetBSD > 199609)) || \ 57173181Sdarrenr (defined(OpenBSD) && (OpenBSD > 199603)) || \ 58173181Sdarrenr (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)) 59145522Sdarrenr# include <sys/dirent.h> 6053642Sguido# else 61145522Sdarrenr# include <sys/dir.h> 6253642Sguido# endif 63145522Sdarrenr# include <sys/mbuf.h> 64161356Sguido# include <sys/select.h> 65161356Sguido# if __FreeBSD_version >= 500000 66161356Sguido# include <sys/selinfo.h> 67161356Sguido# endif 68145522Sdarrenr#else 69145522Sdarrenr# if !defined(__hpux) && defined(_KERNEL) 7053642Sguido# include <sys/filio.h> 7153642Sguido# include <sys/cred.h> 72145522Sdarrenr# include <sys/ddi.h> 73145522Sdarrenr# include <sys/sunddi.h> 74145522Sdarrenr# include <sys/ksynch.h> 7553642Sguido# include <sys/kmem.h> 76145522Sdarrenr# include <sys/mkdev.h> 77145522Sdarrenr# include <sys/dditypes.h> 78145522Sdarrenr# include <sys/cmn_err.h> 79145522Sdarrenr# endif /* !__hpux */ 80145522Sdarrenr#endif /* !SOLARIS && !__hpux */ 81145522Sdarrenr#if !defined(linux) 8280482Sdarrenr# include <sys/protosw.h> 83145522Sdarrenr#endif 84145522Sdarrenr#include <sys/socket.h> 8553642Sguido 86145522Sdarrenr#include <net/if.h> 87145522Sdarrenr#ifdef sun 88145522Sdarrenr# include <net/af.h> 89145522Sdarrenr#endif 90145522Sdarrenr#if __FreeBSD_version >= 300000 91145522Sdarrenr# include <net/if_var.h> 92145522Sdarrenr#endif 93145522Sdarrenr#include <netinet/in.h> 94145522Sdarrenr#ifdef __sgi 95145522Sdarrenr# include <sys/ddi.h> 96145522Sdarrenr# ifdef IFF_DRVRLOCK /* IRIX6 */ 97145522Sdarrenr# include <sys/hashing.h> 9853642Sguido# endif 99145522Sdarrenr#endif 100145522Sdarrenr#if !defined(__hpux) && !defined(linux) && \ 101145522Sdarrenr !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ 102145522Sdarrenr# include <netinet/in_var.h> 103145522Sdarrenr#endif 104145522Sdarrenr#include <netinet/in_systm.h> 105145522Sdarrenr#include <netinet/ip.h> 106145522Sdarrenr#include <netinet/tcp.h> 107145522Sdarrenr#include <netinet/udp.h> 108145522Sdarrenr#include <netinet/ip_icmp.h> 109145522Sdarrenr#ifdef USE_INET6 110145522Sdarrenr# include <netinet/icmp6.h> 111145522Sdarrenr#endif 112145522Sdarrenr#if !defined(linux) 11380482Sdarrenr# include <netinet/ip_var.h> 114145522Sdarrenr#endif 115145522Sdarrenr#ifndef _KERNEL 116145522Sdarrenr# include <syslog.h> 117145522Sdarrenr#endif 118145522Sdarrenr#include "netinet/ip_compat.h" 119145522Sdarrenr#include <netinet/tcpip.h> 120145522Sdarrenr#include "netinet/ip_fil.h" 121145522Sdarrenr#include "netinet/ip_nat.h" 122145522Sdarrenr#include "netinet/ip_frag.h" 123145522Sdarrenr#include "netinet/ip_state.h" 124145522Sdarrenr#include "netinet/ip_auth.h" 125145522Sdarrenr#if (__FreeBSD_version >= 300000) || defined(__NetBSD__) 126145522Sdarrenr# include <sys/malloc.h> 127145522Sdarrenr#endif 128145522Sdarrenr/* END OF INCLUDES */ 12953642Sguido 130145522Sdarrenr#ifdef IPFILTER_LOG 13153642Sguido 132145522Sdarrenr# if defined(IPL_SELECT) 133145522Sdarrenr# include <machine/sys/user.h> 134145522Sdarrenr# include <sys/kthread_iface.h> 135145522Sdarrenr# define READ_COLLISION 0x001 136145522Sdarrenrextern int selwait; 137145522Sdarrenr# endif /* IPL_SELECT */ 138145522Sdarrenr 139255332Scytypedef struct ipf_log_softc_s { 140255332Scy ipfmutex_t ipl_mutex[IPL_LOGSIZE]; 141255332Scy# if SOLARIS && defined(_KERNEL) 142255332Scy kcondvar_t ipl_wait[IPL_LOGSIZE]; 143255332Scy# endif 144145522Sdarrenr# if defined(linux) && defined(_KERNEL) 145255332Scy wait_queue_head_t iplh_linux[IPL_LOGSIZE]; 146145522Sdarrenr# endif 147255332Scy# if defined(__hpux) && defined(_KERNEL) 148255332Scy iplog_select_t ipl_ss[IPL_LOGSIZE]; 14953642Sguido# endif 150255332Scy iplog_t **iplh[IPL_LOGSIZE]; 151255332Scy iplog_t *iplt[IPL_LOGSIZE]; 152255332Scy iplog_t *ipll[IPL_LOGSIZE]; 153255332Scy u_long ipl_logfail[IPL_LOGSIZE]; 154255332Scy u_long ipl_logok[IPL_LOGSIZE]; 155255332Scy fr_info_t ipl_crc[IPL_LOGSIZE]; 156255332Scy u_32_t ipl_counter[IPL_LOGSIZE]; 157255332Scy int ipl_suppress; 158255332Scy int ipl_logall; 159255332Scy int ipl_log_init; 160255332Scy int ipl_logsize; 161255332Scy int ipl_used[IPL_LOGSIZE]; 162255332Scy int ipl_magic[IPL_LOGSIZE]; 163255332Scy ipftuneable_t *ipf_log_tune; 164255332Scy int ipl_readers[IPL_LOGSIZE]; 165255332Scy} ipf_log_softc_t; 16653642Sguido 167255332Scystatic int magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE, 168255332Scy IPL_MAGIC, IPL_MAGIC, IPL_MAGIC, 169255332Scy IPL_MAGIC, IPL_MAGIC }; 17053642Sguido 171255332Scystatic ipftuneable_t ipf_log_tuneables[] = { 172255332Scy /* log */ 173255332Scy { { (void *)offsetof(ipf_log_softc_t, ipl_suppress) }, 174255332Scy "log_suppress", 0, 1, 175255332Scy stsizeof(ipf_log_softc_t, ipl_suppress), 176255332Scy 0, NULL, NULL }, 177255332Scy { { (void *)offsetof(ipf_log_softc_t, ipl_logall) }, 178255332Scy "log_all", 0, 1, 179255332Scy stsizeof(ipf_log_softc_t, ipl_logall), 180255332Scy 0, NULL, NULL }, 181255332Scy { { (void *)offsetof(ipf_log_softc_t, ipl_logsize) }, 182255332Scy "log_size", 0, 0x80000, 183255332Scy stsizeof(ipf_log_softc_t, ipl_logsize), 184255332Scy 0, NULL, NULL }, 185255332Scy { { NULL }, NULL, 0, 0, 186255332Scy 0, 187255332Scy 0, NULL, NULL } 188255332Scy}; 18953642Sguido 190255332Scy 191255332Scyint 192255332Scyipf_log_main_load() 193255332Scy{ 194255332Scy return 0; 195255332Scy} 196255332Scy 197255332Scy 198255332Scyint 199255332Scyipf_log_main_unload() 200255332Scy{ 201255332Scy return 0; 202255332Scy} 203255332Scy 204145522Sdarrenr/* ------------------------------------------------------------------------ */ 205255332Scy/* Function: ipf_log_soft_create */ 206255332Scy/* Returns: void * - NULL = failure, else pointer to log context data */ 207255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 208255332Scy/* */ 209255332Scy/* Initialise log buffers & pointers. Also iniialised the CRC to a local */ 210255332Scy/* secret for use in calculating the "last log checksum". */ 211255332Scy/* ------------------------------------------------------------------------ */ 212255332Scyvoid * 213255332Scyipf_log_soft_create(softc) 214255332Scy ipf_main_softc_t *softc; 215255332Scy{ 216255332Scy ipf_log_softc_t *softl; 217267020Scy int i; 218255332Scy 219255332Scy KMALLOC(softl, ipf_log_softc_t *); 220255332Scy if (softl == NULL) 221255332Scy return NULL; 222255332Scy 223255332Scy bzero((char *)softl, sizeof(*softl)); 224255332Scy bcopy((char *)magic, (char *)softl->ipl_magic, sizeof(magic)); 225255332Scy 226255332Scy softl->ipf_log_tune = ipf_tune_array_copy(softl, 227255332Scy sizeof(ipf_log_tuneables), 228255332Scy ipf_log_tuneables); 229255332Scy if (softl->ipf_log_tune == NULL) { 230255332Scy ipf_log_soft_destroy(softc, softl); 231255332Scy return NULL; 232255332Scy } 233255332Scy if (ipf_tune_array_link(softc, softl->ipf_log_tune) == -1) { 234255332Scy ipf_log_soft_destroy(softc, softl); 235255332Scy return NULL; 236255332Scy } 237255332Scy 238267020Scy for (i = IPL_LOGMAX; i >= 0; i--) { 239267020Scy MUTEX_INIT(&softl->ipl_mutex[i], "ipf log mutex"); 240267020Scy } 241267020Scy 242255332Scy softl->ipl_suppress = 1; 243255332Scy softl->ipl_logall = 0; 244255332Scy softl->ipl_log_init = 0; 245255332Scy softl->ipl_logsize = IPFILTER_LOGSIZE; 246255332Scy 247255332Scy return softl; 248255332Scy} 249255332Scy 250255332Scy/* ------------------------------------------------------------------------ */ 251255332Scy/* Function: ipf_log_soft_init */ 252145522Sdarrenr/* Returns: int - 0 == success (always returned) */ 253255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 254145522Sdarrenr/* */ 255145522Sdarrenr/* Initialise log buffers & pointers. Also iniialised the CRC to a local */ 256145522Sdarrenr/* secret for use in calculating the "last log checksum". */ 257145522Sdarrenr/* ------------------------------------------------------------------------ */ 258255332Scyint 259255332Scyipf_log_soft_init(softc, arg) 260255332Scy ipf_main_softc_t *softc; 261255332Scy void *arg; 26253642Sguido{ 263255332Scy ipf_log_softc_t *softl = arg; 264255332Scy int i; 26553642Sguido 26653642Sguido for (i = IPL_LOGMAX; i >= 0; i--) { 267255332Scy softl->iplt[i] = NULL; 268255332Scy softl->ipll[i] = NULL; 269255332Scy softl->iplh[i] = &softl->iplt[i]; 270255332Scy bzero((char *)&softl->ipl_crc[i], sizeof(softl->ipl_crc[i])); 271145522Sdarrenr# ifdef IPL_SELECT 272255332Scy softl->iplog_ss[i].read_waiter = 0; 273255332Scy softl->iplog_ss[i].state = 0; 274145522Sdarrenr# endif 275255332Scy } 276145522Sdarrenr 277145522Sdarrenr 278255332Scy softl->ipl_log_init = 1; 279255332Scy 280145522Sdarrenr return 0; 28153642Sguido} 28253642Sguido 28353642Sguido 284145522Sdarrenr/* ------------------------------------------------------------------------ */ 285255332Scy/* Function: ipf_log_soft_fini */ 286255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 287255332Scy/* arg(I) - pointer to log context structure */ 288145522Sdarrenr/* */ 289145522Sdarrenr/* Clean up any log data that has accumulated without being read. */ 290145522Sdarrenr/* ------------------------------------------------------------------------ */ 291255332Scyint 292255332Scyipf_log_soft_fini(softc, arg) 293255332Scy ipf_main_softc_t *softc; 294255332Scy void *arg; 295145522Sdarrenr{ 296255332Scy ipf_log_softc_t *softl = arg; 297145522Sdarrenr int i; 298145522Sdarrenr 299255332Scy if (softl->ipl_log_init == 0) 300255332Scy return 0; 301145522Sdarrenr 302255332Scy softl->ipl_log_init = 0; 303145522Sdarrenr 304255332Scy for (i = IPL_LOGMAX; i >= 0; i--) { 305255332Scy (void) ipf_log_clear(softc, i); 306255332Scy 307255332Scy /* 308255332Scy * This is a busy-wait loop so as to avoid yet another lock 309255332Scy * to wait on. 310255332Scy */ 311255332Scy MUTEX_ENTER(&softl->ipl_mutex[i]); 312255332Scy while (softl->ipl_readers[i] > 0) { 313145522Sdarrenr# if SOLARIS && defined(_KERNEL) 314255332Scy cv_broadcast(&softl->ipl_wait[i]); 315255332Scy MUTEX_EXIT(&softl->ipl_mutex[i]); 316255332Scy delay(100); 317255332Scy pollwakeup(&softc->ipf_poll_head[i], POLLRDNORM); 318255332Scy# else 319255332Scy MUTEX_EXIT(&softl->ipl_mutex[i]); 320255332Scy WAKEUP(softl->iplh, i); 321255332Scy POLLWAKEUP(i); 322145522Sdarrenr# endif 323255332Scy MUTEX_ENTER(&softl->ipl_mutex[i]); 324255332Scy } 325267020Scy MUTEX_EXIT(&softl->ipl_mutex[i]); 326255332Scy } 327145522Sdarrenr 328255332Scy return 0; 329145522Sdarrenr} 330145522Sdarrenr 331145522Sdarrenr 332145522Sdarrenr/* ------------------------------------------------------------------------ */ 333255332Scy/* Function: ipf_log_soft_destroy */ 334255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 335255332Scy/* arg(I) - pointer to log context structure */ 336255332Scy/* */ 337255332Scy/* When this function is called, it is expected that there are no longer */ 338255332Scy/* any threads active in the reading code path or the logging code path. */ 339255332Scy/* ------------------------------------------------------------------------ */ 340255332Scyvoid 341255332Scyipf_log_soft_destroy(softc, arg) 342255332Scy ipf_main_softc_t *softc; 343255332Scy void *arg; 344255332Scy{ 345255332Scy ipf_log_softc_t *softl = arg; 346255332Scy int i; 347255332Scy 348255332Scy for (i = IPL_LOGMAX; i >= 0; i--) { 349255332Scy# if SOLARIS && defined(_KERNEL) 350255332Scy cv_destroy(&softl->ipl_wait[i]); 351255332Scy# endif 352255332Scy MUTEX_DESTROY(&softl->ipl_mutex[i]); 353255332Scy } 354255332Scy 355255332Scy if (softl->ipf_log_tune != NULL) { 356255332Scy ipf_tune_array_unlink(softc, softl->ipf_log_tune); 357255332Scy KFREES(softl->ipf_log_tune, sizeof(ipf_log_tuneables)); 358255332Scy softl->ipf_log_tune = NULL; 359255332Scy } 360255332Scy 361255332Scy KFREE(softl); 362255332Scy} 363255332Scy 364255332Scy 365255332Scy/* ------------------------------------------------------------------------ */ 366255332Scy/* Function: ipf_log_pkt */ 367255332Scy/* Returns: int - 0 == success, -1 == failure */ 368145522Sdarrenr/* Parameters: fin(I) - pointer to packet information */ 369145522Sdarrenr/* flags(I) - flags from filter rules */ 370145522Sdarrenr/* */ 371145522Sdarrenr/* Create a log record for a packet given that it has been triggered by a */ 372145522Sdarrenr/* rule (or the default setting). Calculate the transport protocol header */ 373145522Sdarrenr/* size using predetermined size of a couple of popular protocols and thus */ 374145522Sdarrenr/* how much data to copy into the log, including part of the data body if */ 375145522Sdarrenr/* requested. */ 376145522Sdarrenr/* ------------------------------------------------------------------------ */ 377255332Scyint 378255332Scyipf_log_pkt(fin, flags) 379255332Scy fr_info_t *fin; 380255332Scy u_int flags; 38153642Sguido{ 382255332Scy ipf_main_softc_t *softc = fin->fin_main_soft; 383255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 384145522Sdarrenr register size_t hlen; 385145522Sdarrenr int types[2], mlen; 38653642Sguido size_t sizes[2]; 38753642Sguido void *ptrs[2]; 388145522Sdarrenr ipflog_t ipfl; 38960857Sdarrenr u_char p; 390145522Sdarrenr mb_t *m; 391255332Scy# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && !defined(FW_HOOKS) 392145522Sdarrenr qif_t *ifp; 39353642Sguido# else 394145522Sdarrenr struct ifnet *ifp; 395145522Sdarrenr# endif /* SOLARIS || __hpux */ 39653642Sguido 397170268Sdarrenr m = fin->fin_m; 398170268Sdarrenr if (m == NULL) 399170268Sdarrenr return -1; 400170268Sdarrenr 401145522Sdarrenr ipfl.fl_nattag.ipt_num[0] = 0; 402145522Sdarrenr ifp = fin->fin_ifp; 403255332Scy hlen = (char *)fin->fin_dp - (char *)fin->fin_ip; 404255332Scy 40553642Sguido /* 40653642Sguido * calculate header size. 40753642Sguido */ 40860857Sdarrenr if (fin->fin_off == 0) { 40960857Sdarrenr p = fin->fin_fi.fi_p; 41060857Sdarrenr if (p == IPPROTO_TCP) 41153642Sguido hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); 41260857Sdarrenr else if (p == IPPROTO_UDP) 41353642Sguido hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); 41460857Sdarrenr else if (p == IPPROTO_ICMP) { 41560857Sdarrenr struct icmp *icmp; 41653642Sguido 41760857Sdarrenr icmp = (struct icmp *)fin->fin_dp; 418255332Scy 41953642Sguido /* 42053642Sguido * For ICMP, if the packet is an error packet, also 42153642Sguido * include the information about the packet which 42253642Sguido * caused the error. 42353642Sguido */ 42453642Sguido switch (icmp->icmp_type) 42553642Sguido { 42653642Sguido case ICMP_UNREACH : 42753642Sguido case ICMP_SOURCEQUENCH : 42853642Sguido case ICMP_REDIRECT : 42953642Sguido case ICMP_TIMXCEED : 43053642Sguido case ICMP_PARAMPROB : 43153642Sguido hlen += MIN(sizeof(struct icmp) + 8, 43253642Sguido fin->fin_dlen); 43353642Sguido break; 43453642Sguido default : 43553642Sguido hlen += MIN(sizeof(struct icmp), 43653642Sguido fin->fin_dlen); 43753642Sguido break; 43853642Sguido } 43953642Sguido } 440145522Sdarrenr# ifdef USE_INET6 441110916Sdarrenr else if (p == IPPROTO_ICMPV6) { 442110916Sdarrenr struct icmp6_hdr *icmp; 443110916Sdarrenr 444110916Sdarrenr icmp = (struct icmp6_hdr *)fin->fin_dp; 445145522Sdarrenr 446110916Sdarrenr /* 447110916Sdarrenr * For ICMPV6, if the packet is an error packet, also 448110916Sdarrenr * include the information about the packet which 449110916Sdarrenr * caused the error. 450110916Sdarrenr */ 451110916Sdarrenr if (icmp->icmp6_type < 128) { 452110916Sdarrenr hlen += MIN(sizeof(struct icmp6_hdr) + 8, 453110916Sdarrenr fin->fin_dlen); 454110916Sdarrenr } else { 455110916Sdarrenr hlen += MIN(sizeof(struct icmp6_hdr), 456110916Sdarrenr fin->fin_dlen); 457110916Sdarrenr } 458110916Sdarrenr } 459145522Sdarrenr# endif 46053642Sguido } 46153642Sguido /* 46253642Sguido * Get the interface number and name to which this packet is 46353642Sguido * currently associated. 46453642Sguido */ 465255332Scy# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) 466255332Scy# if !defined(FW_HOOKS) 467145522Sdarrenr ipfl.fl_unit = (u_int)ifp->qf_ppa; 468255332Scy# endif 469172776Sdarrenr COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname); 47053642Sguido# else 471255332Scy# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ 472255332Scy OPENBSD_GE_REV(199603) || defined(linux) || FREEBSD_GE_REV(501113) 473172776Sdarrenr COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname); 47453642Sguido# else 475130886Sdarrenr ipfl.fl_unit = (u_int)ifp->if_unit; 476145522Sdarrenr# if defined(_KERNEL) 477145522Sdarrenr if ((ipfl.fl_ifname[0] = ifp->if_name[0])) 478145522Sdarrenr if ((ipfl.fl_ifname[1] = ifp->if_name[1])) 479145522Sdarrenr if ((ipfl.fl_ifname[2] = ifp->if_name[2])) 480145522Sdarrenr ipfl.fl_ifname[3] = ifp->if_name[3]; 481145522Sdarrenr# else 482255332Scy (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); 483145522Sdarrenr ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0'; 484145522Sdarrenr# endif 48553642Sguido# endif 486145522Sdarrenr# endif /* __hpux || SOLARIS */ 487145522Sdarrenr mlen = fin->fin_plen - hlen; 488255332Scy if (!softl->ipl_logall) { 489145522Sdarrenr mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0; 490145522Sdarrenr } else if ((flags & FR_LOGBODY) == 0) { 491145522Sdarrenr mlen = 0; 492145522Sdarrenr } 493145522Sdarrenr if (mlen < 0) 494145522Sdarrenr mlen = 0; 49553642Sguido ipfl.fl_plen = (u_char)mlen; 49653642Sguido ipfl.fl_hlen = (u_char)hlen; 49753642Sguido ipfl.fl_rule = fin->fin_rule; 498145522Sdarrenr (void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN); 499145522Sdarrenr if (fin->fin_fr != NULL) { 50053642Sguido ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; 501145522Sdarrenr ipfl.fl_logtag = fin->fin_fr->fr_logtag; 502145522Sdarrenr } else { 50353642Sguido ipfl.fl_loglevel = 0xffff; 504145522Sdarrenr ipfl.fl_logtag = FR_NOLOGTAG; 505145522Sdarrenr } 506145522Sdarrenr if (fin->fin_nattag != NULL) 507145522Sdarrenr bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag, 508145522Sdarrenr sizeof(ipfl.fl_nattag)); 50953642Sguido ipfl.fl_flags = flags; 510255332Scy ipfl.fl_breason = (fin->fin_reason & 0xff); 51192685Sdarrenr ipfl.fl_dir = fin->fin_out; 512145522Sdarrenr ipfl.fl_lflags = fin->fin_flx; 513255332Scy ipfl.fl_family = fin->fin_family; 51453642Sguido ptrs[0] = (void *)&ipfl; 51553642Sguido sizes[0] = sizeof(ipfl); 51653642Sguido types[0] = 0; 517145522Sdarrenr# if defined(MENTAT) && defined(_KERNEL) 51853642Sguido /* 51953642Sguido * Are we copied from the mblk or an aligned array ? 52053642Sguido */ 521145522Sdarrenr if (fin->fin_ip == (ip_t *)m->b_rptr) { 52253642Sguido ptrs[1] = m; 52353642Sguido sizes[1] = hlen + mlen; 52453642Sguido types[1] = 1; 52553642Sguido } else { 526145522Sdarrenr ptrs[1] = fin->fin_ip; 52753642Sguido sizes[1] = hlen + mlen; 52853642Sguido types[1] = 0; 52953642Sguido } 53053642Sguido# else 53153642Sguido ptrs[1] = m; 53253642Sguido sizes[1] = hlen + mlen; 53353642Sguido types[1] = 1; 534145522Sdarrenr# endif /* MENTAT */ 535255332Scy return ipf_log_items(softc, IPL_LOGIPF, fin, ptrs, sizes, types, 2); 53653642Sguido} 53753642Sguido 53853642Sguido 539145522Sdarrenr/* ------------------------------------------------------------------------ */ 540255332Scy/* Function: ipf_log_items */ 541255332Scy/* Returns: int - 0 == success, -1 == failure */ 542255332Scy/* Parameters: softc(I) - pointer to main soft context */ 543255332Scy/* unit(I) - device we are reading from */ 544145522Sdarrenr/* fin(I) - pointer to packet information */ 545145522Sdarrenr/* items(I) - array of pointers to log data */ 546145522Sdarrenr/* itemsz(I) - array of size of valid memory pointed to */ 547145522Sdarrenr/* types(I) - type of data pointed to by items pointers */ 548145522Sdarrenr/* cnt(I) - number of elements in arrays items/itemsz/types */ 549145522Sdarrenr/* */ 550145522Sdarrenr/* Takes an array of parameters and constructs one record to include the */ 551145522Sdarrenr/* miscellaneous packet information, as well as packet data, for reading */ 552145522Sdarrenr/* from the log device. */ 553145522Sdarrenr/* ------------------------------------------------------------------------ */ 554255332Scyint 555255332Scyipf_log_items(softc, unit, fin, items, itemsz, types, cnt) 556255332Scy ipf_main_softc_t *softc; 557255332Scy int unit; 558255332Scy fr_info_t *fin; 559255332Scy void **items; 560255332Scy size_t *itemsz; 561255332Scy int *types, cnt; 56253642Sguido{ 563255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 564255332Scy caddr_t buf, ptr; 56553642Sguido iplog_t *ipl; 56653642Sguido size_t len; 56753642Sguido int i; 568153876Sguido SPL_INT(s); 569145522Sdarrenr 57053642Sguido /* 57153642Sguido * Get the total amount of data to be logged. 57253642Sguido */ 573145522Sdarrenr for (i = 0, len = sizeof(iplog_t); i < cnt; i++) 57453642Sguido len += itemsz[i]; 57553642Sguido 576255332Scy SPL_NET(s); 577255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 578255332Scy softl->ipl_counter[unit]++; 57953642Sguido /* 58053642Sguido * check that we have space to record this information and can 58153642Sguido * allocate that much. 58253642Sguido */ 583255332Scy if ((softl->ipl_used[unit] + len) > softl->ipl_logsize) { 584255332Scy softl->ipl_logfail[unit]++; 585255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 586145522Sdarrenr return -1; 587255332Scy } 588255332Scy 589255332Scy KMALLOCS(buf, caddr_t, len); 590255332Scy if (buf == NULL) { 591255332Scy softl->ipl_logfail[unit]++; 592255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 593145522Sdarrenr return -1; 59453642Sguido } 59553642Sguido ipl = (iplog_t *)buf; 596255332Scy ipl->ipl_magic = softl->ipl_magic[unit]; 59753642Sguido ipl->ipl_count = 1; 598255332Scy ipl->ipl_seqnum = softl->ipl_counter[unit]; 59953642Sguido ipl->ipl_next = NULL; 60053642Sguido ipl->ipl_dsize = len; 601145522Sdarrenr#ifdef _KERNEL 602145522Sdarrenr GETKTIME(&ipl->ipl_sec); 603145522Sdarrenr#else 60492685Sdarrenr ipl->ipl_sec = 0; 60592685Sdarrenr ipl->ipl_usec = 0; 606145522Sdarrenr#endif 60753642Sguido 60853642Sguido /* 60953642Sguido * Loop through all the items to be logged, copying each one to the 61053642Sguido * buffer. Use bcopy for normal data or the mb_t copyout routine. 61153642Sguido */ 612145522Sdarrenr for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) { 613145522Sdarrenr if (types[i] == 0) { 614145522Sdarrenr bcopy(items[i], ptr, itemsz[i]); 615145522Sdarrenr } else if (types[i] == 1) { 616255332Scy COPYDATA(items[i], 0, itemsz[i], ptr); 61753642Sguido } 618145522Sdarrenr ptr += itemsz[i]; 61953642Sguido } 620255332Scy /* 621255332Scy * Check to see if this log record has a CRC which matches the last 622255332Scy * record logged. If it does, just up the count on the previous one 623255332Scy * rather than create a new one. 624255332Scy */ 625255332Scy if (softl->ipl_suppress) { 626255332Scy if ((fin != NULL) && (fin->fin_off == 0)) { 627255332Scy if ((softl->ipll[unit] != NULL) && 628255332Scy (fin->fin_crc == softl->ipl_crc[unit].fin_crc) && 629255332Scy bcmp((char *)fin, (char *)&softl->ipl_crc[unit], 630255332Scy FI_LCSIZE) == 0) { 631255332Scy softl->ipll[unit]->ipl_count++; 632255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 633255332Scy SPL_X(s); 634255332Scy KFREES(buf, len); 635255332Scy return 0; 636255332Scy } 637255332Scy bcopy((char *)fin, (char *)&softl->ipl_crc[unit], 638255332Scy FI_LCSIZE); 639255332Scy softl->ipl_crc[unit].fin_crc = fin->fin_crc; 640255332Scy } else 641255332Scy bzero((char *)&softl->ipl_crc[unit], FI_CSIZE); 642255332Scy } 643145522Sdarrenr 644145522Sdarrenr /* 645255332Scy * advance the log pointer to the next empty record and deduct the 646255332Scy * amount of space we're going to use. 647255332Scy */ 648255332Scy softl->ipl_logok[unit]++; 649255332Scy softl->ipll[unit] = ipl; 650255332Scy *softl->iplh[unit] = ipl; 651255332Scy softl->iplh[unit] = &ipl->ipl_next; 652255332Scy softl->ipl_used[unit] += len; 653255332Scy 654255332Scy /* 655145522Sdarrenr * Now that the log record has been completed and added to the queue, 656145522Sdarrenr * wake up any listeners who may want to read it. 657145522Sdarrenr */ 65892685Sdarrenr# if SOLARIS && defined(_KERNEL) 659255332Scy cv_signal(&softl->ipl_wait[unit]); 660255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 661255332Scy pollwakeup(&softc->ipf_poll_head[unit], POLLRDNORM); 66253642Sguido# else 663255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 664255332Scy WAKEUP(softl->iplh, unit); 665255332Scy POLLWAKEUP(unit); 66653642Sguido# endif 667145522Sdarrenr SPL_X(s); 668145522Sdarrenr# ifdef IPL_SELECT 669255332Scy iplog_input_ready(unit); 670145522Sdarrenr# endif 671145522Sdarrenr return 0; 67253642Sguido} 67353642Sguido 67453642Sguido 675145522Sdarrenr/* ------------------------------------------------------------------------ */ 676255332Scy/* Function: ipf_log_read */ 677255332Scy/* Returns: int - 0 == success, else error value. */ 678255332Scy/* Parameters: softc(I) - pointer to main soft context */ 679255332Scy/* unit(I) - device we are reading from */ 680255332Scy/* uio(O) - pointer to information about where to store data */ 681145522Sdarrenr/* */ 682145522Sdarrenr/* Called to handle a read on an IPFilter device. Returns only complete */ 683145522Sdarrenr/* log messages - will not partially copy a log record out to userland. */ 684145522Sdarrenr/* */ 685145522Sdarrenr/* NOTE: This function will block and wait for a signal to return data if */ 686145522Sdarrenr/* there is none present. Asynchronous I/O is not implemented. */ 687145522Sdarrenr/* ------------------------------------------------------------------------ */ 688255332Scyint 689255332Scyipf_log_read(softc, unit, uio) 690255332Scy ipf_main_softc_t *softc; 691255332Scy minor_t unit; 692255332Scy struct uio *uio; 69353642Sguido{ 694255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 69553642Sguido size_t dlen, copied; 69653642Sguido int error = 0; 69753642Sguido iplog_t *ipl; 698153876Sguido SPL_INT(s); 69953642Sguido 700255332Scy if (softl->ipl_log_init == 0) { 701255332Scy IPFERROR(40007); 702255332Scy return 0; 703255332Scy } 704255332Scy 70553642Sguido /* 70653642Sguido * Sanity checks. Make sure the minor # is valid and we're copying 70753642Sguido * a valid chunk of data. 70853642Sguido */ 709255332Scy if (IPL_LOGMAX < unit) { 710255332Scy IPFERROR(40001); 71153642Sguido return ENXIO; 712255332Scy } 713145522Sdarrenr if (uio->uio_resid == 0) 71453642Sguido return 0; 715255332Scy 716255332Scy if (uio->uio_resid < sizeof(iplog_t)) { 717255332Scy IPFERROR(40002); 71853642Sguido return EINVAL; 719255332Scy } 720255332Scy if (uio->uio_resid > softl->ipl_logsize) { 721255332Scy IPFERROR(40005); 722255332Scy return EINVAL; 723255332Scy } 724145522Sdarrenr 72553642Sguido /* 72653642Sguido * Lock the log so we can snapshot the variables. Wait for a signal 72753642Sguido * if the log is empty. 72853642Sguido */ 72953642Sguido SPL_NET(s); 730255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 731255332Scy softl->ipl_readers[unit]++; 73253642Sguido 733255332Scy while (softl->ipl_log_init == 1 && softl->iplt[unit] == NULL) { 73453642Sguido# if SOLARIS && defined(_KERNEL) 735255332Scy if (!cv_wait_sig(&softl->ipl_wait[unit], 736255332Scy &softl->ipl_mutex[unit].ipf_lk)) { 737255332Scy softl->ipl_readers[unit]--; 738255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 739255332Scy IPFERROR(40003); 74053642Sguido return EINTR; 74153642Sguido } 74253642Sguido# else 743145522Sdarrenr# if defined(__hpux) && defined(_KERNEL) 744145522Sdarrenr lock_t *l; 745145522Sdarrenr 746145522Sdarrenr# ifdef IPL_SELECT 747145522Sdarrenr if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) { 748145522Sdarrenr /* this is no blocking system call */ 749255332Scy softl->ipl_readers[unit]--; 750255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 751145522Sdarrenr return 0; 752145522Sdarrenr } 753145522Sdarrenr# endif 754145522Sdarrenr 755255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 756255332Scy l = get_sleep_lock(&softl->iplh[unit]); 757255332Scy error = sleep(&softl->iplh[unit], PZERO+1); 758145522Sdarrenr spinunlock(l); 759145522Sdarrenr# else 760145522Sdarrenr# if defined(__osf__) && defined(_KERNEL) 761255332Scy error = mpsleep(&softl->iplh[unit], PSUSP|PCATCH, "ipfread", 0, 762255332Scy &softl->ipl_mutex, MS_LOCK_SIMPLE); 763145522Sdarrenr# else 764255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 765145522Sdarrenr SPL_X(s); 766255332Scy error = SLEEP(unit + softl->iplh, "ipl sleep"); 767145522Sdarrenr# endif /* __osf__ */ 768145522Sdarrenr# endif /* __hpux */ 769255332Scy SPL_NET(s); 770255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 771255332Scy if (error) { 772255332Scy softl->ipl_readers[unit]--; 773255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 774255332Scy IPFERROR(40004); 77553642Sguido return error; 776255332Scy } 77753642Sguido# endif /* SOLARIS */ 77853642Sguido } 779255332Scy if (softl->ipl_log_init != 1) { 780255332Scy softl->ipl_readers[unit]--; 781255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 782255332Scy IPFERROR(40008); 783255332Scy return EIO; 784255332Scy } 78553642Sguido 786255332Scy# if (defined(BSD) && (BSD >= 199101)) || defined(__FreeBSD__) || \ 787255332Scy defined(__osf__) 78853642Sguido uio->uio_rw = UIO_READ; 78953642Sguido# endif 79053642Sguido 791255332Scy for (copied = 0; (ipl = softl->iplt[unit]) != NULL; copied += dlen) { 79253642Sguido dlen = ipl->ipl_dsize; 79353642Sguido if (dlen > uio->uio_resid) 79453642Sguido break; 79553642Sguido /* 79653642Sguido * Don't hold the mutex over the uiomove call. 79753642Sguido */ 798255332Scy softl->iplt[unit] = ipl->ipl_next; 799255332Scy softl->ipl_used[unit] -= dlen; 800255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 801145522Sdarrenr SPL_X(s); 802172776Sdarrenr error = UIOMOVE(ipl, dlen, UIO_READ, uio); 80353642Sguido if (error) { 804145522Sdarrenr SPL_NET(s); 805255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 806255332Scy IPFERROR(40006); 807255332Scy ipl->ipl_next = softl->iplt[unit]; 808255332Scy softl->iplt[unit] = ipl; 809255332Scy softl->ipl_used[unit] += dlen; 81053642Sguido break; 81153642Sguido } 812255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 813255332Scy KFREES((caddr_t)ipl, dlen); 814145522Sdarrenr SPL_NET(s); 81553642Sguido } 816255332Scy if (!softl->iplt[unit]) { 817255332Scy softl->ipl_used[unit] = 0; 818255332Scy softl->iplh[unit] = &softl->iplt[unit]; 819255332Scy softl->ipll[unit] = NULL; 82053642Sguido } 82153642Sguido 822255332Scy softl->ipl_readers[unit]--; 823255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 82453642Sguido SPL_X(s); 82553642Sguido return error; 82653642Sguido} 82753642Sguido 82853642Sguido 829145522Sdarrenr/* ------------------------------------------------------------------------ */ 830255332Scy/* Function: ipf_log_clear */ 831255332Scy/* Returns: int - number of log bytes cleared. */ 832255332Scy/* Parameters: softc(I) - pointer to main soft context */ 833255332Scy/* unit(I) - device we are reading from */ 834145522Sdarrenr/* */ 835145522Sdarrenr/* Deletes all queued up log records for a given output device. */ 836145522Sdarrenr/* ------------------------------------------------------------------------ */ 837255332Scyint 838255332Scyipf_log_clear(softc, unit) 839255332Scy ipf_main_softc_t *softc; 840255332Scy minor_t unit; 84153642Sguido{ 842255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 84353642Sguido iplog_t *ipl; 84453642Sguido int used; 845153876Sguido SPL_INT(s); 84653642Sguido 847145522Sdarrenr SPL_NET(s); 848255332Scy MUTEX_ENTER(&softl->ipl_mutex[unit]); 849255332Scy while ((ipl = softl->iplt[unit]) != NULL) { 850255332Scy softl->iplt[unit] = ipl->ipl_next; 851255332Scy KFREES((caddr_t)ipl, ipl->ipl_dsize); 85253642Sguido } 853255332Scy softl->iplh[unit] = &softl->iplt[unit]; 854255332Scy softl->ipll[unit] = NULL; 855255332Scy used = softl->ipl_used[unit]; 856255332Scy softl->ipl_used[unit] = 0; 857255332Scy bzero((char *)&softl->ipl_crc[unit], FI_CSIZE); 858255332Scy MUTEX_EXIT(&softl->ipl_mutex[unit]); 859145522Sdarrenr SPL_X(s); 86053642Sguido return used; 86153642Sguido} 862161356Sguido 863161356Sguido 864161356Sguido/* ------------------------------------------------------------------------ */ 865255332Scy/* Function: ipf_log_canread */ 866255332Scy/* Returns: int - 0 == no data to read, 1 = data present */ 867255332Scy/* Parameters: softc(I) - pointer to main soft context */ 868255332Scy/* unit(I) - device we are reading from */ 869161356Sguido/* */ 870161356Sguido/* Returns an indication of whether or not there is data present in the */ 871161356Sguido/* current buffer for the selected ipf device. */ 872161356Sguido/* ------------------------------------------------------------------------ */ 873255332Scyint 874255332Scyipf_log_canread(softc, unit) 875255332Scy ipf_main_softc_t *softc; 876255332Scy int unit; 877161356Sguido{ 878255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 879255332Scy 880255332Scy return softl->iplt[unit] != NULL; 881161356Sguido} 882255332Scy 883255332Scy 884255332Scy/* ------------------------------------------------------------------------ */ 885255332Scy/* Function: ipf_log_canread */ 886255332Scy/* Returns: int - 0 == no data to read, 1 = data present */ 887255332Scy/* Parameters: softc(I) - pointer to main soft context */ 888255332Scy/* unit(I) - device we are reading from */ 889255332Scy/* */ 890255332Scy/* Returns how many bytes are currently held in log buffers for the */ 891255332Scy/* selected ipf device. */ 892255332Scy/* ------------------------------------------------------------------------ */ 893255332Scyint 894255332Scyipf_log_bytesused(softc, unit) 895255332Scy ipf_main_softc_t *softc; 896255332Scy int unit; 897255332Scy{ 898255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 899255332Scy 900255332Scy if (softl == NULL) 901255332Scy return 0; 902255332Scy 903255332Scy return softl->ipl_used[unit]; 904255332Scy} 905255332Scy 906255332Scy 907255332Scy/* ------------------------------------------------------------------------ */ 908255332Scy/* Function: ipf_log_failures */ 909255332Scy/* Returns: U_QUAD_T - number of log failures */ 910255332Scy/* Parameters: softc(I) - pointer to main soft context */ 911255332Scy/* unit(I) - device we are reading from */ 912255332Scy/* */ 913255332Scy/* Returns how many times we've tried to log a packet but failed to do so */ 914255332Scy/* for the selected ipf device. */ 915255332Scy/* ------------------------------------------------------------------------ */ 916255332Scyu_long 917255332Scyipf_log_failures(softc, unit) 918255332Scy ipf_main_softc_t *softc; 919255332Scy int unit; 920255332Scy{ 921255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 922255332Scy 923255332Scy if (softl == NULL) 924255332Scy return 0; 925255332Scy 926255332Scy return softl->ipl_logfail[unit]; 927255332Scy} 928255332Scy 929255332Scy 930255332Scy/* ------------------------------------------------------------------------ */ 931255332Scy/* Function: ipf_log_logok */ 932255332Scy/* Returns: U_QUAD_T - number of packets logged */ 933255332Scy/* Parameters: softc(I) - pointer to main soft context */ 934255332Scy/* unit(I) - device we are reading from */ 935255332Scy/* */ 936255332Scy/* Returns how many times we've successfully logged a packet for the */ 937255332Scy/* selected ipf device. */ 938255332Scy/* ------------------------------------------------------------------------ */ 939255332Scyu_long 940255332Scyipf_log_logok(softc, unit) 941255332Scy ipf_main_softc_t *softc; 942255332Scy int unit; 943255332Scy{ 944255332Scy ipf_log_softc_t *softl = softc->ipf_log_soft; 945255332Scy 946255332Scy if (softl == NULL) 947255332Scy return 0; 948255332Scy 949255332Scy return softl->ipl_logok[unit]; 950255332Scy} 95153642Sguido#endif /* IPFILTER_LOG */ 952