ip_log.c revision 60925
153642Sguido/* 260857Sdarrenr * Copyright (C) 1997-2000 by Darren Reed. 353642Sguido * 453642Sguido * Redistribution and use in source and binary forms are permitted 553642Sguido * provided that this notice is preserved and due credit is given 653642Sguido * to the original author and the contributors. 753642Sguido * 853642Sguido * $Id: ip_log.c,v 2.1.2.2 1999/09/21 11:55:44 darrenr Exp $ 957126Sguido * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_log.c 60925 2000-05-25 16:24:46Z darrenr $ 1053642Sguido */ 1153642Sguido#include <sys/param.h> 1253642Sguido#if defined(KERNEL) && !defined(_KERNEL) 1353642Sguido# define _KERNEL 1453642Sguido#endif 1553642Sguido#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) 1653642Sguido# include "opt_ipfilter_log.h" 1753642Sguido#endif 1853642Sguido#ifdef __FreeBSD__ 1960925Sdarrenr# if defined(IPFILTER_LKM) || defined(_KERNEL) 2060925Sdarrenr# if !defined(__FreeBSD_version) 2160925Sdarrenr# include <sys/osreldate.h> 2253642Sguido# endif 2360925Sdarrenr# if !defined(IPFILTER_LKM) 2460925Sdarrenr# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 2560925Sdarrenr# include "opt_ipfilter.h" 2660925Sdarrenr# endif 2760925Sdarrenr# endif 2860857Sdarrenr# else 2960857Sdarrenr# include <osreldate.h> 3053642Sguido# endif 3153642Sguido#endif 3260925Sdarrenr#ifdef IPFILTER_LOG 3353642Sguido# ifndef SOLARIS 3453642Sguido# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) 3553642Sguido# endif 3653642Sguido# ifndef _KERNEL 3753642Sguido# include <stdio.h> 3853642Sguido# include <string.h> 3953642Sguido# include <stdlib.h> 4053642Sguido# include <ctype.h> 4153642Sguido# endif 4253642Sguido# include <sys/errno.h> 4353642Sguido# include <sys/types.h> 4453642Sguido# include <sys/file.h> 4553642Sguido# if __FreeBSD_version >= 220000 && defined(_KERNEL) 4653642Sguido# include <sys/fcntl.h> 4753642Sguido# include <sys/filio.h> 4853642Sguido# else 4953642Sguido# include <sys/ioctl.h> 5053642Sguido# endif 5153642Sguido# include <sys/time.h> 5253642Sguido# if defined(_KERNEL) && !defined(linux) 5353642Sguido# include <sys/systm.h> 5453642Sguido# endif 5553642Sguido# include <sys/uio.h> 5653642Sguido# if !SOLARIS 5753642Sguido# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) 5853642Sguido# include <sys/dirent.h> 5953642Sguido# else 6053642Sguido# include <sys/dir.h> 6153642Sguido# endif 6253642Sguido# ifndef linux 6353642Sguido# include <sys/mbuf.h> 6453642Sguido# endif 6553642Sguido# else 6653642Sguido# include <sys/filio.h> 6753642Sguido# include <sys/cred.h> 6853642Sguido# include <sys/ddi.h> 6953642Sguido# include <sys/sunddi.h> 7053642Sguido# include <sys/ksynch.h> 7153642Sguido# include <sys/kmem.h> 7253642Sguido# include <sys/mkdev.h> 7353642Sguido# include <sys/dditypes.h> 7453642Sguido# include <sys/cmn_err.h> 7553642Sguido# endif 7653642Sguido# ifndef linux 7753642Sguido# include <sys/protosw.h> 7853642Sguido# endif 7953642Sguido# include <sys/socket.h> 8053642Sguido 8153642Sguido# include <net/if.h> 8253642Sguido# ifdef sun 8353642Sguido# include <net/af.h> 8453642Sguido# endif 8553642Sguido# if __FreeBSD_version >= 300000 8653642Sguido# include <net/if_var.h> 8753642Sguido# endif 8853642Sguido# include <net/route.h> 8953642Sguido# include <netinet/in.h> 9053642Sguido# ifdef __sgi 9153642Sguido# include <sys/ddi.h> 9253642Sguido# ifdef IFF_DRVRLOCK /* IRIX6 */ 9353642Sguido# include <sys/hashing.h> 9453642Sguido# endif 9553642Sguido# endif 9653642Sguido# if !defined(linux) && !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ 9753642Sguido# include <netinet/in_var.h> 9853642Sguido# endif 9953642Sguido# include <netinet/in_systm.h> 10053642Sguido# include <netinet/ip.h> 10153642Sguido# include <netinet/tcp.h> 10253642Sguido# include <netinet/udp.h> 10353642Sguido# include <netinet/ip_icmp.h> 10453642Sguido# ifndef linux 10553642Sguido# include <netinet/ip_var.h> 10653642Sguido# endif 10753642Sguido# ifndef _KERNEL 10853642Sguido# include <syslog.h> 10953642Sguido# endif 11053642Sguido# include "netinet/ip_compat.h" 11153642Sguido# include <netinet/tcpip.h> 11253642Sguido# include "netinet/ip_fil.h" 11353642Sguido# include "netinet/ip_proxy.h" 11453642Sguido# include "netinet/ip_nat.h" 11553642Sguido# include "netinet/ip_frag.h" 11653642Sguido# include "netinet/ip_state.h" 11753642Sguido# include "netinet/ip_auth.h" 11853642Sguido# if (__FreeBSD_version >= 300000) 11953642Sguido# include <sys/malloc.h> 12053642Sguido# endif 12153642Sguido 12253642Sguido# ifndef MIN 12353642Sguido# define MIN(a,b) (((a)<(b))?(a):(b)) 12453642Sguido# endif 12553642Sguido 12653642Sguido 12753642Sguido# if SOLARIS || defined(__sgi) 12853642Sguidoextern kmutex_t ipl_mutex; 12953642Sguido# if SOLARIS 13053642Sguidoextern kcondvar_t iplwait; 13153642Sguido# endif 13253642Sguido# endif 13353642Sguido 13453642Sguidoiplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; 13553642Sguidosize_t iplused[IPL_LOGMAX+1]; 13660857Sdarrenrstatic fr_info_t iplcrc[IPL_LOGMAX+1]; 13753642Sguido# ifdef linux 13853642Sguidostatic struct wait_queue *iplwait[IPL_LOGMAX+1]; 13953642Sguido# endif 14053642Sguido 14153642Sguido 14253642Sguido/* 14353642Sguido * Initialise log buffers & pointers. Also iniialised the CRC to a local 14453642Sguido * secret for use in calculating the "last log checksum". 14553642Sguido */ 14653642Sguidovoid ipflog_init() 14753642Sguido{ 14853642Sguido int i; 14953642Sguido 15053642Sguido for (i = IPL_LOGMAX; i >= 0; i--) { 15153642Sguido iplt[i] = NULL; 15253642Sguido ipll[i] = NULL; 15353642Sguido iplh[i] = &iplt[i]; 15453642Sguido iplused[i] = 0; 15553642Sguido bzero((char *)&iplcrc[i], sizeof(iplcrc[i])); 15653642Sguido } 15753642Sguido} 15853642Sguido 15953642Sguido 16053642Sguido/* 16153642Sguido * ipflog 16253642Sguido * Create a log record for a packet given that it has been triggered by a 16353642Sguido * rule (or the default setting). Calculate the transport protocol header 16453642Sguido * size using predetermined size of a couple of popular protocols and thus 16553642Sguido * how much data to copy into the log, including part of the data body if 16653642Sguido * requested. 16753642Sguido */ 16853642Sguidoint ipflog(flags, ip, fin, m) 16953642Sguidou_int flags; 17053642Sguidoip_t *ip; 17153642Sguidofr_info_t *fin; 17253642Sguidomb_t *m; 17353642Sguido{ 17453642Sguido ipflog_t ipfl; 17553642Sguido register size_t mlen, hlen; 17653642Sguido size_t sizes[2]; 17753642Sguido void *ptrs[2]; 17853642Sguido int types[2]; 17960857Sdarrenr u_char p; 18053642Sguido# if SOLARIS 18153642Sguido ill_t *ifp = fin->fin_ifp; 18253642Sguido# else 18353642Sguido struct ifnet *ifp = fin->fin_ifp; 18453642Sguido# endif 18553642Sguido 18653642Sguido /* 18753642Sguido * calculate header size. 18853642Sguido */ 18953642Sguido hlen = fin->fin_hlen; 19060857Sdarrenr if (fin->fin_off == 0) { 19160857Sdarrenr p = fin->fin_fi.fi_p; 19260857Sdarrenr if (p == IPPROTO_TCP) 19353642Sguido hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); 19460857Sdarrenr else if (p == IPPROTO_UDP) 19553642Sguido hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); 19660857Sdarrenr else if (p == IPPROTO_ICMP) { 19760857Sdarrenr struct icmp *icmp; 19853642Sguido 19960857Sdarrenr icmp = (struct icmp *)fin->fin_dp; 20053642Sguido 20153642Sguido /* 20253642Sguido * For ICMP, if the packet is an error packet, also 20353642Sguido * include the information about the packet which 20453642Sguido * caused the error. 20553642Sguido */ 20653642Sguido switch (icmp->icmp_type) 20753642Sguido { 20853642Sguido case ICMP_UNREACH : 20953642Sguido case ICMP_SOURCEQUENCH : 21053642Sguido case ICMP_REDIRECT : 21153642Sguido case ICMP_TIMXCEED : 21253642Sguido case ICMP_PARAMPROB : 21353642Sguido hlen += MIN(sizeof(struct icmp) + 8, 21453642Sguido fin->fin_dlen); 21553642Sguido break; 21653642Sguido default : 21753642Sguido hlen += MIN(sizeof(struct icmp), 21853642Sguido fin->fin_dlen); 21953642Sguido break; 22053642Sguido } 22153642Sguido } 22253642Sguido } 22353642Sguido /* 22453642Sguido * Get the interface number and name to which this packet is 22553642Sguido * currently associated. 22653642Sguido */ 22753642Sguido# if SOLARIS 22853642Sguido ipfl.fl_unit = (u_char)ifp->ill_ppa; 22953642Sguido bcopy(ifp->ill_name, ipfl.fl_ifname, MIN(ifp->ill_name_length, 4)); 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# ifndef linux 23753642Sguido ipfl.fl_unit = (u_char)ifp->if_unit; 23853642Sguido# endif 23953642Sguido if ((ipfl.fl_ifname[0] = ifp->if_name[0])) 24053642Sguido if ((ipfl.fl_ifname[1] = ifp->if_name[1])) 24153642Sguido if ((ipfl.fl_ifname[2] = ifp->if_name[2])) 24253642Sguido ipfl.fl_ifname[3] = ifp->if_name[3]; 24353642Sguido# endif 24460857Sdarrenr mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0; 24553642Sguido# endif 24653642Sguido ipfl.fl_plen = (u_char)mlen; 24753642Sguido ipfl.fl_hlen = (u_char)hlen; 24853642Sguido ipfl.fl_rule = fin->fin_rule; 24953642Sguido ipfl.fl_group = fin->fin_group; 25053642Sguido if (fin->fin_fr != NULL) 25153642Sguido ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; 25253642Sguido else 25353642Sguido ipfl.fl_loglevel = 0xffff; 25453642Sguido ipfl.fl_flags = flags; 25553642Sguido ptrs[0] = (void *)&ipfl; 25653642Sguido sizes[0] = sizeof(ipfl); 25753642Sguido types[0] = 0; 25853642Sguido# if SOLARIS 25953642Sguido /* 26053642Sguido * Are we copied from the mblk or an aligned array ? 26153642Sguido */ 26253642Sguido if (ip == (ip_t *)m->b_rptr) { 26353642Sguido ptrs[1] = m; 26453642Sguido sizes[1] = hlen + mlen; 26553642Sguido types[1] = 1; 26653642Sguido } else { 26753642Sguido ptrs[1] = ip; 26853642Sguido sizes[1] = hlen + mlen; 26953642Sguido types[1] = 0; 27053642Sguido } 27153642Sguido# else 27253642Sguido ptrs[1] = m; 27353642Sguido sizes[1] = hlen + mlen; 27453642Sguido types[1] = 1; 27553642Sguido# endif 27653642Sguido return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2); 27753642Sguido} 27853642Sguido 27953642Sguido 28053642Sguido/* 28153642Sguido * ipllog 28253642Sguido */ 28353642Sguidoint ipllog(dev, fin, items, itemsz, types, cnt) 28453642Sguidoint dev; 28553642Sguidofr_info_t *fin; 28653642Sguidovoid **items; 28753642Sguidosize_t *itemsz; 28853642Sguidoint *types, cnt; 28953642Sguido{ 29053642Sguido caddr_t buf, s; 29153642Sguido iplog_t *ipl; 29253642Sguido size_t len; 29353642Sguido int i; 29453642Sguido 29553642Sguido /* 29653642Sguido * Check to see if this log record has a CRC which matches the last 29753642Sguido * record logged. If it does, just up the count on the previous one 29853642Sguido * rather than create a new one. 29953642Sguido */ 30053642Sguido MUTEX_ENTER(&ipl_mutex); 30153642Sguido if (fin != NULL) { 30253642Sguido if ((ipll[dev] != NULL) && 30353642Sguido bcmp((char *)fin, (char *)&iplcrc[dev], FI_CSIZE) == 0) { 30453642Sguido ipll[dev]->ipl_count++; 30553642Sguido MUTEX_EXIT(&ipl_mutex); 30653642Sguido return 1; 30753642Sguido } 30853642Sguido bcopy((char *)fin, (char *)&iplcrc[dev], FI_CSIZE); 30953642Sguido } else 31053642Sguido bzero((char *)&iplcrc[dev], FI_CSIZE); 31153642Sguido MUTEX_EXIT(&ipl_mutex); 31253642Sguido 31353642Sguido /* 31453642Sguido * Get the total amount of data to be logged. 31553642Sguido */ 31653642Sguido for (i = 0, len = sizeof(iplog_t); i < cnt; i++) 31753642Sguido len += itemsz[i]; 31853642Sguido 31953642Sguido /* 32053642Sguido * check that we have space to record this information and can 32153642Sguido * allocate that much. 32253642Sguido */ 32353642Sguido KMALLOCS(buf, caddr_t, len); 32453642Sguido if (!buf) 32553642Sguido return 0; 32653642Sguido MUTEX_ENTER(&ipl_mutex); 32753642Sguido if ((iplused[dev] + len) > IPLLOGSIZE) { 32853642Sguido MUTEX_EXIT(&ipl_mutex); 32953642Sguido KFREES(buf, len); 33053642Sguido return 0; 33153642Sguido } 33253642Sguido iplused[dev] += len; 33353642Sguido MUTEX_EXIT(&ipl_mutex); 33453642Sguido 33553642Sguido /* 33653642Sguido * advance the log pointer to the next empty record and deduct the 33753642Sguido * amount of space we're going to use. 33853642Sguido */ 33953642Sguido ipl = (iplog_t *)buf; 34053642Sguido ipl->ipl_magic = IPL_MAGIC; 34153642Sguido ipl->ipl_count = 1; 34253642Sguido ipl->ipl_next = NULL; 34353642Sguido ipl->ipl_dsize = len; 34453642Sguido# if SOLARIS || defined(sun) || defined(linux) 34553642Sguido uniqtime((struct timeval *)&ipl->ipl_sec); 34653642Sguido# else 34753642Sguido# if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) 34853642Sguido microtime((struct timeval *)&ipl->ipl_sec); 34953642Sguido# endif 35053642Sguido# endif 35153642Sguido 35253642Sguido /* 35353642Sguido * Loop through all the items to be logged, copying each one to the 35453642Sguido * buffer. Use bcopy for normal data or the mb_t copyout routine. 35553642Sguido */ 35653642Sguido for (i = 0, s = buf + sizeof(*ipl); i < cnt; i++) { 35753642Sguido if (types[i] == 0) 35853642Sguido bcopy(items[i], s, itemsz[i]); 35953642Sguido else if (types[i] == 1) { 36053642Sguido# if SOLARIS 36153642Sguido copyout_mblk(items[i], 0, itemsz[i], s); 36253642Sguido# else 36353642Sguido m_copydata(items[i], 0, itemsz[i], s); 36453642Sguido# endif 36553642Sguido } 36653642Sguido s += itemsz[i]; 36753642Sguido } 36853642Sguido MUTEX_ENTER(&ipl_mutex); 36953642Sguido ipll[dev] = ipl; 37053642Sguido *iplh[dev] = ipl; 37153642Sguido iplh[dev] = &ipl->ipl_next; 37253642Sguido# if SOLARIS 37353642Sguido cv_signal(&iplwait); 37453642Sguido mutex_exit(&ipl_mutex); 37553642Sguido# else 37653642Sguido MUTEX_EXIT(&ipl_mutex); 37753642Sguido# ifdef linux 37853642Sguido wake_up_interruptible(&iplwait[dev]); 37953642Sguido# else 38053642Sguido wakeup(&iplh[dev]); 38153642Sguido# endif 38253642Sguido# endif 38353642Sguido return 1; 38453642Sguido} 38553642Sguido 38653642Sguido 38753642Sguidoint ipflog_read(unit, uio) 38853642Sguidominor_t unit; 38953642Sguidostruct uio *uio; 39053642Sguido{ 39153642Sguido size_t dlen, copied; 39253642Sguido int error = 0; 39353642Sguido iplog_t *ipl; 39453642Sguido# if defined(_KERNEL) && !SOLARIS 39553642Sguido int s; 39653642Sguido# endif 39753642Sguido 39853642Sguido /* 39953642Sguido * Sanity checks. Make sure the minor # is valid and we're copying 40053642Sguido * a valid chunk of data. 40153642Sguido */ 40253642Sguido if (IPL_LOGMAX < unit) 40353642Sguido return ENXIO; 40453642Sguido if (!uio->uio_resid) 40553642Sguido return 0; 40653642Sguido if ((uio->uio_resid < sizeof(iplog_t)) || 40753642Sguido (uio->uio_resid > IPLLOGSIZE)) 40853642Sguido return EINVAL; 40953642Sguido 41053642Sguido /* 41153642Sguido * Lock the log so we can snapshot the variables. Wait for a signal 41253642Sguido * if the log is empty. 41353642Sguido */ 41453642Sguido SPL_NET(s); 41553642Sguido MUTEX_ENTER(&ipl_mutex); 41653642Sguido 41753642Sguido while (!iplused[unit] || !iplt[unit]) { 41853642Sguido# if SOLARIS && defined(_KERNEL) 41953642Sguido if (!cv_wait_sig(&iplwait, &ipl_mutex)) { 42053642Sguido MUTEX_EXIT(&ipl_mutex); 42153642Sguido return EINTR; 42253642Sguido } 42353642Sguido# else 42453642Sguido# ifdef linux 42553642Sguido interruptible_sleep_on(&iplwait[unit]); 42653642Sguido if (current->signal & ~current->blocked) 42753642Sguido return -EINTR; 42853642Sguido# else 42953642Sguido MUTEX_EXIT(&ipl_mutex); 43053642Sguido SPL_X(s); 43153642Sguido error = SLEEP(&iplh[unit], "ipl sleep"); 43253642Sguido if (error) 43353642Sguido return error; 43453642Sguido SPL_NET(s); 43553642Sguido MUTEX_ENTER(&ipl_mutex); 43653642Sguido# endif /* linux */ 43753642Sguido# endif /* SOLARIS */ 43853642Sguido } 43953642Sguido 44053642Sguido# if BSD >= 199306 || defined(__FreeBSD__) 44153642Sguido uio->uio_rw = UIO_READ; 44253642Sguido# endif 44353642Sguido 44453642Sguido for (copied = 0; (ipl = iplt[unit]); copied += dlen) { 44553642Sguido dlen = ipl->ipl_dsize; 44653642Sguido if (dlen > uio->uio_resid) 44753642Sguido break; 44853642Sguido /* 44953642Sguido * Don't hold the mutex over the uiomove call. 45053642Sguido */ 45153642Sguido iplt[unit] = ipl->ipl_next; 45253642Sguido iplused[unit] -= dlen; 45353642Sguido MUTEX_EXIT(&ipl_mutex); 45453642Sguido SPL_X(s); 45553642Sguido error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio); 45653642Sguido if (error) { 45753642Sguido SPL_NET(s); 45853642Sguido MUTEX_ENTER(&ipl_mutex); 45953642Sguido ipl->ipl_next = iplt[unit]; 46053642Sguido iplt[unit] = ipl; 46153642Sguido iplused[unit] += dlen; 46253642Sguido break; 46353642Sguido } 46453642Sguido KFREES((caddr_t)ipl, dlen); 46553642Sguido SPL_NET(s); 46653642Sguido MUTEX_ENTER(&ipl_mutex); 46753642Sguido } 46853642Sguido if (!iplt[unit]) { 46953642Sguido iplused[unit] = 0; 47053642Sguido iplh[unit] = &iplt[unit]; 47153642Sguido ipll[unit] = NULL; 47253642Sguido } 47353642Sguido 47453642Sguido MUTEX_EXIT(&ipl_mutex); 47553642Sguido SPL_X(s); 47653642Sguido# ifdef linux 47753642Sguido if (!error) 47853642Sguido return (int)copied; 47953642Sguido return -error; 48053642Sguido# else 48153642Sguido return error; 48253642Sguido# endif 48353642Sguido} 48453642Sguido 48553642Sguido 48653642Sguidoint ipflog_clear(unit) 48753642Sguidominor_t unit; 48853642Sguido{ 48953642Sguido iplog_t *ipl; 49053642Sguido int used; 49153642Sguido 49253642Sguido MUTEX_ENTER(&ipl_mutex); 49353642Sguido while ((ipl = iplt[unit])) { 49453642Sguido iplt[unit] = ipl->ipl_next; 49553642Sguido KFREES((caddr_t)ipl, ipl->ipl_dsize); 49653642Sguido } 49753642Sguido iplh[unit] = &iplt[unit]; 49853642Sguido ipll[unit] = NULL; 49953642Sguido used = iplused[unit]; 50053642Sguido iplused[unit] = 0; 50153642Sguido bzero((char *)&iplcrc[unit], FI_CSIZE); 50253642Sguido MUTEX_EXIT(&ipl_mutex); 50353642Sguido return used; 50453642Sguido} 50553642Sguido#endif /* IPFILTER_LOG */ 506