ip_log.c revision 95563
153642Sguido/* 280482Sdarrenr * Copyright (C) 1997-2001 by Darren Reed. 353642Sguido * 480482Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 553642Sguido * 663523Sdarrenr * $Id: ip_log.c,v 2.5.2.1 2000/07/19 13:11:47 darrenr Exp $ 757126Sguido * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_log.c 95563 2002-04-27 16:56:25Z darrenr $ 853642Sguido */ 953642Sguido#include <sys/param.h> 1053642Sguido#if defined(KERNEL) && !defined(_KERNEL) 1153642Sguido# define _KERNEL 1253642Sguido#endif 1395563Sdarrenr#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ 1495563Sdarrenr defined(_KERNEL) 1553642Sguido# include "opt_ipfilter_log.h" 1653642Sguido#endif 1753642Sguido#ifdef __FreeBSD__ 1860925Sdarrenr# if defined(IPFILTER_LKM) || defined(_KERNEL) 1960925Sdarrenr# if !defined(__FreeBSD_version) 2060925Sdarrenr# include <sys/osreldate.h> 2153642Sguido# endif 2260925Sdarrenr# if !defined(IPFILTER_LKM) 2360925Sdarrenr# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 2460925Sdarrenr# include "opt_ipfilter.h" 2560925Sdarrenr# endif 2660925Sdarrenr# endif 2760857Sdarrenr# else 2863523Sdarrenr# ifdef KLD_MODULE 2980482Sdarrenr# ifndef __FreeBSD_cc_version 3080482Sdarrenr# include <osreldate.h> 3180482Sdarrenr# else 3280482Sdarrenr# if __FreeBSD_cc_version < 430000 3380482Sdarrenr# include <osreldate.h> 3480482Sdarrenr# endif 3580482Sdarrenr# endif 3663523Sdarrenr# endif 3753642Sguido# endif 3853642Sguido#endif 3960925Sdarrenr#ifdef IPFILTER_LOG 4053642Sguido# ifndef SOLARIS 4153642Sguido# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) 4253642Sguido# endif 4353642Sguido# ifndef _KERNEL 4453642Sguido# include <stdio.h> 4553642Sguido# include <string.h> 4653642Sguido# include <stdlib.h> 4753642Sguido# include <ctype.h> 4853642Sguido# endif 4953642Sguido# include <sys/errno.h> 5053642Sguido# include <sys/types.h> 5153642Sguido# include <sys/file.h> 5253642Sguido# if __FreeBSD_version >= 220000 && defined(_KERNEL) 5353642Sguido# include <sys/fcntl.h> 5453642Sguido# include <sys/filio.h> 5553642Sguido# else 5653642Sguido# include <sys/ioctl.h> 5753642Sguido# endif 5853642Sguido# include <sys/time.h> 5980482Sdarrenr# if defined(_KERNEL) 6053642Sguido# include <sys/systm.h> 6153642Sguido# endif 6253642Sguido# if !SOLARIS 6353642Sguido# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) 6453642Sguido# include <sys/dirent.h> 6553642Sguido# else 6653642Sguido# include <sys/dir.h> 6753642Sguido# endif 6880482Sdarrenr# include <sys/mbuf.h> 6953642Sguido# else 7053642Sguido# include <sys/filio.h> 7153642Sguido# include <sys/cred.h> 7253642Sguido# include <sys/kmem.h> 7392685Sdarrenr# ifdef _KERNEL 7492685Sdarrenr# include <sys/ddi.h> 7592685Sdarrenr# include <sys/sunddi.h> 7692685Sdarrenr# include <sys/ksynch.h> 7792685Sdarrenr# include <sys/dditypes.h> 7892685Sdarrenr# include <sys/cmn_err.h> 7992685Sdarrenr# endif 8053642Sguido# endif 8180482Sdarrenr# include <sys/protosw.h> 8253642Sguido# include <sys/socket.h> 8353642Sguido 8453642Sguido# include <net/if.h> 8553642Sguido# ifdef sun 8653642Sguido# include <net/af.h> 8753642Sguido# endif 8853642Sguido# if __FreeBSD_version >= 300000 8953642Sguido# include <net/if_var.h> 9053642Sguido# endif 9153642Sguido# include <net/route.h> 9253642Sguido# include <netinet/in.h> 9353642Sguido# ifdef __sgi 9495418Sdarrenr# define _KMEMUSER 9553642Sguido# include <sys/ddi.h> 9653642Sguido# ifdef IFF_DRVRLOCK /* IRIX6 */ 9753642Sguido# include <sys/hashing.h> 9853642Sguido# endif 9953642Sguido# endif 10080482Sdarrenr# if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ 10153642Sguido# include <netinet/in_var.h> 10253642Sguido# endif 10353642Sguido# include <netinet/in_systm.h> 10453642Sguido# include <netinet/ip.h> 10553642Sguido# include <netinet/tcp.h> 10653642Sguido# include <netinet/udp.h> 10753642Sguido# include <netinet/ip_icmp.h> 10880482Sdarrenr# include <netinet/ip_var.h> 10953642Sguido# ifndef _KERNEL 11053642Sguido# include <syslog.h> 11153642Sguido# endif 11253642Sguido# include "netinet/ip_compat.h" 11353642Sguido# include <netinet/tcpip.h> 11453642Sguido# include "netinet/ip_fil.h" 11553642Sguido# if (__FreeBSD_version >= 300000) 11653642Sguido# include <sys/malloc.h> 11753642Sguido# endif 11853642Sguido 11953642Sguido# ifndef MIN 12053642Sguido# define MIN(a,b) (((a)<(b))?(a):(b)) 12153642Sguido# endif 12292685Sdarrenr# ifdef IPFILTER_LOGSIZE 12392685Sdarrenr# undef IPLLOGSIZE 12492685Sdarrenr# define IPLLOGSIZE IPFILTER_LOGSIZE 12592685Sdarrenr# endif 12653642Sguido 12753642Sguido 12853642Sguido# if SOLARIS || defined(__sgi) 12953642Sguidoextern kmutex_t ipl_mutex; 13053642Sguido# if SOLARIS 13153642Sguidoextern kcondvar_t iplwait; 13253642Sguido# endif 13353642Sguido# endif 13453642Sguido 13553642Sguidoiplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; 13653642Sguidosize_t iplused[IPL_LOGMAX+1]; 13760857Sdarrenrstatic fr_info_t iplcrc[IPL_LOGMAX+1]; 13853642Sguido 13953642Sguido 14053642Sguido/* 14153642Sguido * Initialise log buffers & pointers. Also iniialised the CRC to a local 14253642Sguido * secret for use in calculating the "last log checksum". 14353642Sguido */ 14453642Sguidovoid ipflog_init() 14553642Sguido{ 14653642Sguido int i; 14753642Sguido 14853642Sguido for (i = IPL_LOGMAX; i >= 0; i--) { 14953642Sguido iplt[i] = NULL; 15053642Sguido ipll[i] = NULL; 15153642Sguido iplh[i] = &iplt[i]; 15253642Sguido iplused[i] = 0; 15353642Sguido bzero((char *)&iplcrc[i], sizeof(iplcrc[i])); 15453642Sguido } 15553642Sguido} 15653642Sguido 15753642Sguido 15853642Sguido/* 15953642Sguido * ipflog 16053642Sguido * Create a log record for a packet given that it has been triggered by a 16153642Sguido * rule (or the default setting). Calculate the transport protocol header 16253642Sguido * size using predetermined size of a couple of popular protocols and thus 16353642Sguido * how much data to copy into the log, including part of the data body if 16453642Sguido * requested. 16553642Sguido */ 16653642Sguidoint ipflog(flags, ip, fin, m) 16753642Sguidou_int flags; 16853642Sguidoip_t *ip; 16953642Sguidofr_info_t *fin; 17053642Sguidomb_t *m; 17153642Sguido{ 17253642Sguido ipflog_t ipfl; 17353642Sguido register size_t mlen, hlen; 17453642Sguido size_t sizes[2]; 17553642Sguido void *ptrs[2]; 17653642Sguido int types[2]; 17760857Sdarrenr u_char p; 17892685Sdarrenr# if SOLARIS && defined(_KERNEL) 17953642Sguido ill_t *ifp = fin->fin_ifp; 18053642Sguido# else 18153642Sguido struct ifnet *ifp = fin->fin_ifp; 18253642Sguido# endif 18353642Sguido 18453642Sguido /* 18553642Sguido * calculate header size. 18653642Sguido */ 18753642Sguido hlen = fin->fin_hlen; 18860857Sdarrenr if (fin->fin_off == 0) { 18960857Sdarrenr p = fin->fin_fi.fi_p; 19060857Sdarrenr if (p == IPPROTO_TCP) 19153642Sguido hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); 19260857Sdarrenr else if (p == IPPROTO_UDP) 19353642Sguido hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); 19460857Sdarrenr else if (p == IPPROTO_ICMP) { 19560857Sdarrenr struct icmp *icmp; 19653642Sguido 19760857Sdarrenr icmp = (struct icmp *)fin->fin_dp; 19853642Sguido 19953642Sguido /* 20053642Sguido * For ICMP, if the packet is an error packet, also 20153642Sguido * include the information about the packet which 20253642Sguido * caused the error. 20353642Sguido */ 20453642Sguido switch (icmp->icmp_type) 20553642Sguido { 20653642Sguido case ICMP_UNREACH : 20753642Sguido case ICMP_SOURCEQUENCH : 20853642Sguido case ICMP_REDIRECT : 20953642Sguido case ICMP_TIMXCEED : 21053642Sguido case ICMP_PARAMPROB : 21153642Sguido hlen += MIN(sizeof(struct icmp) + 8, 21253642Sguido fin->fin_dlen); 21353642Sguido break; 21453642Sguido default : 21553642Sguido hlen += MIN(sizeof(struct icmp), 21653642Sguido fin->fin_dlen); 21753642Sguido break; 21853642Sguido } 21953642Sguido } 22053642Sguido } 22153642Sguido /* 22253642Sguido * Get the interface number and name to which this packet is 22353642Sguido * currently associated. 22453642Sguido */ 22592685Sdarrenr bzero((char *)ipfl.fl_ifname, sizeof(ipfl.fl_ifname)); 22692685Sdarrenr# if SOLARIS && defined(_KERNEL) 22753642Sguido ipfl.fl_unit = (u_char)ifp->ill_ppa; 22892685Sdarrenr bcopy(ifp->ill_name, ipfl.fl_ifname, 22992685Sdarrenr MIN(ifp->ill_name_length, sizeof(ipfl.fl_ifname))); 23053642Sguido mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0; 23153642Sguido# else 23253642Sguido# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ 23353642Sguido (defined(OpenBSD) && (OpenBSD >= 199603)) 23453642Sguido strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ); 23553642Sguido# else 23653642Sguido ipfl.fl_unit = (u_char)ifp->if_unit; 23792685Sdarrenr strncpy(ipfl.fl_ifname, ifp->if_name, MIN(sizeof(ipfl.fl_ifname), 23892685Sdarrenr sizeof(ifp->if_name))); 23953642Sguido# endif 24060857Sdarrenr mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0; 24153642Sguido# endif 24253642Sguido ipfl.fl_plen = (u_char)mlen; 24353642Sguido ipfl.fl_hlen = (u_char)hlen; 24453642Sguido ipfl.fl_rule = fin->fin_rule; 24553642Sguido ipfl.fl_group = fin->fin_group; 24653642Sguido if (fin->fin_fr != NULL) 24753642Sguido ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; 24853642Sguido else 24953642Sguido ipfl.fl_loglevel = 0xffff; 25053642Sguido ipfl.fl_flags = flags; 25192685Sdarrenr ipfl.fl_dir = fin->fin_out; 25253642Sguido ptrs[0] = (void *)&ipfl; 25353642Sguido sizes[0] = sizeof(ipfl); 25453642Sguido types[0] = 0; 25592685Sdarrenr# if SOLARIS && defined(_KERNEL) 25653642Sguido /* 25753642Sguido * Are we copied from the mblk or an aligned array ? 25853642Sguido */ 25953642Sguido if (ip == (ip_t *)m->b_rptr) { 26053642Sguido ptrs[1] = m; 26153642Sguido sizes[1] = hlen + mlen; 26253642Sguido types[1] = 1; 26353642Sguido } else { 26453642Sguido ptrs[1] = ip; 26553642Sguido sizes[1] = hlen + mlen; 26653642Sguido types[1] = 0; 26753642Sguido } 26853642Sguido# else 26953642Sguido ptrs[1] = m; 27053642Sguido sizes[1] = hlen + mlen; 27153642Sguido types[1] = 1; 27253642Sguido# endif 27353642Sguido return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2); 27453642Sguido} 27553642Sguido 27653642Sguido 27753642Sguido/* 27853642Sguido * ipllog 27953642Sguido */ 28053642Sguidoint ipllog(dev, fin, items, itemsz, types, cnt) 28153642Sguidoint dev; 28253642Sguidofr_info_t *fin; 28353642Sguidovoid **items; 28453642Sguidosize_t *itemsz; 28553642Sguidoint *types, cnt; 28653642Sguido{ 28753642Sguido caddr_t buf, s; 28853642Sguido iplog_t *ipl; 28953642Sguido size_t len; 29053642Sguido int i; 29153642Sguido 29253642Sguido /* 29353642Sguido * Check to see if this log record has a CRC which matches the last 29453642Sguido * record logged. If it does, just up the count on the previous one 29553642Sguido * rather than create a new one. 29653642Sguido */ 29753642Sguido MUTEX_ENTER(&ipl_mutex); 29853642Sguido if (fin != NULL) { 29953642Sguido if ((ipll[dev] != NULL) && 30092685Sdarrenr bcmp((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE) == 0) { 30153642Sguido ipll[dev]->ipl_count++; 30253642Sguido MUTEX_EXIT(&ipl_mutex); 30353642Sguido return 1; 30453642Sguido } 30592685Sdarrenr bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE); 30653642Sguido } else 30792685Sdarrenr bzero((char *)&iplcrc[dev], FI_LCSIZE); 30853642Sguido MUTEX_EXIT(&ipl_mutex); 30953642Sguido 31053642Sguido /* 31153642Sguido * Get the total amount of data to be logged. 31253642Sguido */ 31392685Sdarrenr for (i = 0, len = IPLOG_SIZE; i < cnt; i++) 31453642Sguido len += itemsz[i]; 31553642Sguido 31653642Sguido /* 31753642Sguido * check that we have space to record this information and can 31853642Sguido * allocate that much. 31953642Sguido */ 32053642Sguido KMALLOCS(buf, caddr_t, len); 32153642Sguido if (!buf) 32253642Sguido return 0; 32353642Sguido MUTEX_ENTER(&ipl_mutex); 32453642Sguido if ((iplused[dev] + len) > IPLLOGSIZE) { 32553642Sguido MUTEX_EXIT(&ipl_mutex); 32653642Sguido KFREES(buf, len); 32753642Sguido return 0; 32853642Sguido } 32953642Sguido iplused[dev] += len; 33053642Sguido MUTEX_EXIT(&ipl_mutex); 33153642Sguido 33253642Sguido /* 33353642Sguido * advance the log pointer to the next empty record and deduct the 33453642Sguido * amount of space we're going to use. 33553642Sguido */ 33653642Sguido ipl = (iplog_t *)buf; 33753642Sguido ipl->ipl_magic = IPL_MAGIC; 33853642Sguido ipl->ipl_count = 1; 33953642Sguido ipl->ipl_next = NULL; 34053642Sguido ipl->ipl_dsize = len; 34192685Sdarrenr# ifdef _KERNEL 34292685Sdarrenr# if SOLARIS || defined(sun) 34353642Sguido uniqtime((struct timeval *)&ipl->ipl_sec); 34492685Sdarrenr# else 34592685Sdarrenr# if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) 34653642Sguido microtime((struct timeval *)&ipl->ipl_sec); 34792685Sdarrenr# endif 34853642Sguido# endif 34992685Sdarrenr# else 35092685Sdarrenr ipl->ipl_sec = 0; 35192685Sdarrenr ipl->ipl_usec = 0; 35253642Sguido# endif 35353642Sguido 35453642Sguido /* 35553642Sguido * Loop through all the items to be logged, copying each one to the 35653642Sguido * buffer. Use bcopy for normal data or the mb_t copyout routine. 35753642Sguido */ 35892685Sdarrenr for (i = 0, s = buf + IPLOG_SIZE; i < cnt; i++) { 35953642Sguido if (types[i] == 0) 36053642Sguido bcopy(items[i], s, itemsz[i]); 36153642Sguido else if (types[i] == 1) { 36292685Sdarrenr# if SOLARIS && defined(_KERNEL) 36353642Sguido copyout_mblk(items[i], 0, itemsz[i], s); 36453642Sguido# else 36553642Sguido m_copydata(items[i], 0, itemsz[i], s); 36653642Sguido# endif 36753642Sguido } 36853642Sguido s += itemsz[i]; 36953642Sguido } 37053642Sguido MUTEX_ENTER(&ipl_mutex); 37153642Sguido ipll[dev] = ipl; 37253642Sguido *iplh[dev] = ipl; 37353642Sguido iplh[dev] = &ipl->ipl_next; 37492685Sdarrenr# if SOLARIS && defined(_KERNEL) 37553642Sguido cv_signal(&iplwait); 37653642Sguido mutex_exit(&ipl_mutex); 37753642Sguido# else 37853642Sguido MUTEX_EXIT(&ipl_mutex); 37992685Sdarrenr WAKEUP(&iplh[dev]); 38053642Sguido# endif 38153642Sguido return 1; 38253642Sguido} 38353642Sguido 38453642Sguido 38553642Sguidoint ipflog_read(unit, uio) 38653642Sguidominor_t unit; 38753642Sguidostruct uio *uio; 38853642Sguido{ 38953642Sguido size_t dlen, copied; 39053642Sguido int error = 0; 39153642Sguido iplog_t *ipl; 39253642Sguido# if defined(_KERNEL) && !SOLARIS 39353642Sguido int s; 39453642Sguido# endif 39553642Sguido 39653642Sguido /* 39753642Sguido * Sanity checks. Make sure the minor # is valid and we're copying 39853642Sguido * a valid chunk of data. 39953642Sguido */ 40053642Sguido if (IPL_LOGMAX < unit) 40153642Sguido return ENXIO; 40253642Sguido if (!uio->uio_resid) 40353642Sguido return 0; 40492685Sdarrenr if (uio->uio_resid < IPLOG_SIZE) 40553642Sguido return EINVAL; 40653642Sguido 40753642Sguido /* 40853642Sguido * Lock the log so we can snapshot the variables. Wait for a signal 40953642Sguido * if the log is empty. 41053642Sguido */ 41153642Sguido SPL_NET(s); 41253642Sguido MUTEX_ENTER(&ipl_mutex); 41353642Sguido 41453642Sguido while (!iplused[unit] || !iplt[unit]) { 41553642Sguido# if SOLARIS && defined(_KERNEL) 41653642Sguido if (!cv_wait_sig(&iplwait, &ipl_mutex)) { 41753642Sguido MUTEX_EXIT(&ipl_mutex); 41853642Sguido return EINTR; 41953642Sguido } 42053642Sguido# else 42153642Sguido MUTEX_EXIT(&ipl_mutex); 42253642Sguido error = SLEEP(&iplh[unit], "ipl sleep"); 42380482Sdarrenr if (error) { 42480482Sdarrenr SPL_X(s); 42553642Sguido return error; 42680482Sdarrenr } 42753642Sguido MUTEX_ENTER(&ipl_mutex); 42853642Sguido# endif /* SOLARIS */ 42953642Sguido } 43053642Sguido 43153642Sguido# if BSD >= 199306 || defined(__FreeBSD__) 43253642Sguido uio->uio_rw = UIO_READ; 43353642Sguido# endif 43453642Sguido 43553642Sguido for (copied = 0; (ipl = iplt[unit]); copied += dlen) { 43653642Sguido dlen = ipl->ipl_dsize; 43753642Sguido if (dlen > uio->uio_resid) 43853642Sguido break; 43953642Sguido /* 44053642Sguido * Don't hold the mutex over the uiomove call. 44153642Sguido */ 44253642Sguido iplt[unit] = ipl->ipl_next; 44353642Sguido iplused[unit] -= dlen; 44453642Sguido MUTEX_EXIT(&ipl_mutex); 44553642Sguido error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio); 44692685Sdarrenr MUTEX_ENTER(&ipl_mutex); 44753642Sguido if (error) { 44853642Sguido ipl->ipl_next = iplt[unit]; 44953642Sguido iplt[unit] = ipl; 45053642Sguido iplused[unit] += dlen; 45153642Sguido break; 45253642Sguido } 45353642Sguido KFREES((caddr_t)ipl, dlen); 45453642Sguido } 45553642Sguido if (!iplt[unit]) { 45653642Sguido iplused[unit] = 0; 45753642Sguido iplh[unit] = &iplt[unit]; 45853642Sguido ipll[unit] = NULL; 45953642Sguido } 46053642Sguido 46153642Sguido MUTEX_EXIT(&ipl_mutex); 46253642Sguido SPL_X(s); 46353642Sguido return error; 46453642Sguido} 46553642Sguido 46653642Sguido 46753642Sguidoint ipflog_clear(unit) 46853642Sguidominor_t unit; 46953642Sguido{ 47053642Sguido iplog_t *ipl; 47153642Sguido int used; 47253642Sguido 47353642Sguido MUTEX_ENTER(&ipl_mutex); 47453642Sguido while ((ipl = iplt[unit])) { 47553642Sguido iplt[unit] = ipl->ipl_next; 47653642Sguido KFREES((caddr_t)ipl, ipl->ipl_dsize); 47753642Sguido } 47853642Sguido iplh[unit] = &iplt[unit]; 47953642Sguido ipll[unit] = NULL; 48053642Sguido used = iplused[unit]; 48153642Sguido iplused[unit] = 0; 48292685Sdarrenr bzero((char *)&iplcrc[unit], FI_LCSIZE); 48353642Sguido MUTEX_EXIT(&ipl_mutex); 48453642Sguido return used; 48553642Sguido} 48653642Sguido#endif /* IPFILTER_LOG */ 487