2 * Copyright (C) 1997-2001 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
6 * $Id: ip_log.c,v 2.5.2.21 2002/10/26 06:21:30 darrenr Exp $
9 #if defined(KERNEL) && !defined(_KERNEL)
12 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
14 # include "opt_ipfilter_log.h"
17 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
18 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
19 # include "opt_ipfilter.h"
23 # ifndef __FreeBSD_cc_version
24 # include <osreldate.h>
26 # if __FreeBSD_cc_version < 430000
27 # include <osreldate.h>
35 # define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
43 # include <sys/errno.h>
44 # include <sys/types.h>
45 # include <sys/file.h>
46 # if __FreeBSD_version >= 220000 && defined(_KERNEL)
47 # include <sys/fcntl.h>
48 # include <sys/filio.h>
50 # include <sys/ioctl.h>
52 # include <sys/time.h>
54 # include <sys/systm.h>
57 # if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
58 # include <sys/dirent.h>
62 # include <sys/mbuf.h>
64 # include <sys/filio.h>
65 # include <sys/cred.h>
66 # include <sys/kmem.h>
69 # include <sys/sunddi.h>
70 # include <sys/ksynch.h>
71 # include <sys/dditypes.h>
72 # include <sys/cmn_err.h>
75 # include <sys/protosw.h>
76 # include <sys/socket.h>
82 # if __FreeBSD_version >= 300000
83 # include <net/if_var.h>
85 # include <net/route.h>
86 # include <netinet/in.h>
90 # ifdef IFF_DRVRLOCK /* IRIX6 */
91 # include <sys/hashing.h>
94 # if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/
95 # include <netinet/in_var.h>
97 # include <netinet/in_systm.h>
98 # include <netinet/ip.h>
99 # include <netinet/tcp.h>
100 # include <netinet/udp.h>
101 # include <netinet/ip_icmp.h>
103 # include <netinet/icmp6.h>
105 # include <netinet/ip_var.h>
109 # include "netinet/ip_compat.h"
110 # include <netinet/tcpip.h>
111 # include "netinet/ip_fil.h"
112 # if (__FreeBSD_version >= 300000)
113 # include <sys/malloc.h>
117 # define MIN(a,b) (((a)<(b))?(a):(b))
119 # ifdef IPFILTER_LOGSIZE
121 # define IPLLOGSIZE IPFILTER_LOGSIZE
125 # if SOLARIS || defined(__sgi)
126 extern kmutex_t ipl_mutex;
128 extern kcondvar_t iplwait;
132 iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1];
133 size_t iplused[IPL_LOGMAX+1];
134 static fr_info_t iplcrc[IPL_LOGMAX+1];
138 * Initialise log buffers & pointers. Also iniialised the CRC to a local
139 * secret for use in calculating the "last log checksum".
145 for (i = IPL_LOGMAX; i >= 0; i--) {
150 bzero((char *)&iplcrc[i], sizeof(iplcrc[i]));
157 * Create a log record for a packet given that it has been triggered by a
158 * rule (or the default setting). Calculate the transport protocol header
159 * size using predetermined size of a couple of popular protocols and thus
160 * how much data to copy into the log, including part of the data body if
163 int ipflog(flags, ip, fin, m)
170 register size_t mlen, hlen;
175 # if SOLARIS && defined(_KERNEL)
176 ill_t *ifp = fin->fin_ifp;
178 struct ifnet *ifp = fin->fin_ifp;
182 * calculate header size.
184 hlen = fin->fin_hlen;
185 if (fin->fin_off == 0) {
186 p = fin->fin_fi.fi_p;
187 if (p == IPPROTO_TCP)
188 hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
189 else if (p == IPPROTO_UDP)
190 hlen += MIN(sizeof(udphdr_t), fin->fin_dlen);
191 else if (p == IPPROTO_ICMP) {
194 icmp = (struct icmp *)fin->fin_dp;
197 * For ICMP, if the packet is an error packet, also
198 * include the information about the packet which
201 switch (icmp->icmp_type)
204 case ICMP_SOURCEQUENCH :
207 case ICMP_PARAMPROB :
208 hlen += MIN(sizeof(struct icmp) + 8,
212 hlen += MIN(sizeof(struct icmp),
218 else if (p == IPPROTO_ICMPV6) {
219 struct icmp6_hdr *icmp;
221 icmp = (struct icmp6_hdr *)fin->fin_dp;
224 * For ICMPV6, if the packet is an error packet, also
225 * include the information about the packet which
228 if (icmp->icmp6_type < 128) {
229 hlen += MIN(sizeof(struct icmp6_hdr) + 8,
232 hlen += MIN(sizeof(struct icmp6_hdr),
239 * Get the interface number and name to which this packet is
240 * currently associated.
242 bzero((char *)ipfl.fl_ifname, sizeof(ipfl.fl_ifname));
243 # if SOLARIS && defined(_KERNEL)
244 ipfl.fl_unit = (u_char)ifp->ill_ppa;
245 bcopy(ifp->ill_name, ipfl.fl_ifname,
246 MIN(ifp->ill_name_length, sizeof(ipfl.fl_ifname)));
247 mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0;
249 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
250 (defined(OpenBSD) && (OpenBSD >= 199603))
251 strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ);
253 ipfl.fl_unit = (u_char)ifp->if_unit;
254 strncpy(ipfl.fl_ifname, ifp->if_name, MIN(sizeof(ipfl.fl_ifname),
255 sizeof(ifp->if_name)));
257 mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0;
259 ipfl.fl_plen = (u_char)mlen;
260 ipfl.fl_hlen = (u_char)hlen;
261 ipfl.fl_rule = fin->fin_rule;
262 ipfl.fl_group = fin->fin_group;
263 if (fin->fin_fr != NULL)
264 ipfl.fl_loglevel = fin->fin_fr->fr_loglevel;
266 ipfl.fl_loglevel = 0xffff;
267 ipfl.fl_flags = flags;
268 ipfl.fl_dir = fin->fin_out;
269 ptrs[0] = (void *)&ipfl;
270 sizes[0] = sizeof(ipfl);
272 # if SOLARIS && defined(_KERNEL)
274 * Are we copied from the mblk or an aligned array ?
276 if (ip == (ip_t *)m->b_rptr) {
278 sizes[1] = hlen + mlen;
282 sizes[1] = hlen + mlen;
287 sizes[1] = hlen + mlen;
290 return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2);
297 int ipllog(dev, fin, items, itemsz, types, cnt)
310 * Check to see if this log record has a CRC which matches the last
311 * record logged. If it does, just up the count on the previous one
312 * rather than create a new one.
314 MUTEX_ENTER(&ipl_mutex);
316 if ((ipll[dev] != NULL) &&
317 bcmp((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE) == 0) {
318 ipll[dev]->ipl_count++;
319 MUTEX_EXIT(&ipl_mutex);
322 bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE);
324 bzero((char *)&iplcrc[dev], FI_LCSIZE);
325 MUTEX_EXIT(&ipl_mutex);
328 * Get the total amount of data to be logged.
330 for (i = 0, len = IPLOG_SIZE; i < cnt; i++)
334 * check that we have space to record this information and can
335 * allocate that much.
337 KMALLOCS(buf, caddr_t, len);
340 MUTEX_ENTER(&ipl_mutex);
341 if ((iplused[dev] + len) > IPLLOGSIZE) {
342 MUTEX_EXIT(&ipl_mutex);
347 MUTEX_EXIT(&ipl_mutex);
350 * advance the log pointer to the next empty record and deduct the
351 * amount of space we're going to use.
353 ipl = (iplog_t *)buf;
354 ipl->ipl_magic = IPL_MAGIC;
356 ipl->ipl_next = NULL;
357 ipl->ipl_dsize = len;
359 # if SOLARIS || defined(sun)
360 uniqtime(&ipl->ipl_tv);
362 # if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi)
363 microtime(&ipl->ipl_tv);
372 * Loop through all the items to be logged, copying each one to the
373 * buffer. Use bcopy for normal data or the mb_t copyout routine.
375 for (i = 0, s = buf + IPLOG_SIZE; i < cnt; i++) {
377 bcopy(items[i], s, itemsz[i]);
378 else if (types[i] == 1) {
379 # if SOLARIS && defined(_KERNEL)
380 copyout_mblk(items[i], 0, itemsz[i], s);
382 m_copydata(items[i], 0, itemsz[i], s);
387 MUTEX_ENTER(&ipl_mutex);
390 iplh[dev] = &ipl->ipl_next;
391 # if SOLARIS && defined(_KERNEL)
393 mutex_exit(&ipl_mutex);
395 MUTEX_EXIT(&ipl_mutex);
402 int ipflog_read(unit, uio)
409 # if defined(_KERNEL) && !SOLARIS
414 * Sanity checks. Make sure the minor # is valid and we're copying
415 * a valid chunk of data.
417 if (IPL_LOGMAX < unit)
421 if (uio->uio_resid < IPLOG_SIZE)
425 * Lock the log so we can snapshot the variables. Wait for a signal
426 * if the log is empty.
429 MUTEX_ENTER(&ipl_mutex);
431 while (!iplused[unit] || !iplt[unit]) {
432 # if SOLARIS && defined(_KERNEL)
433 if (!cv_wait_sig(&iplwait, &ipl_mutex)) {
434 MUTEX_EXIT(&ipl_mutex);
438 MUTEX_EXIT(&ipl_mutex);
439 error = SLEEP(&iplh[unit], "ipl sleep");
444 MUTEX_ENTER(&ipl_mutex);
445 # endif /* SOLARIS */
448 # if BSD >= 199306 || defined(__FreeBSD__)
449 uio->uio_rw = UIO_READ;
452 for (copied = 0; (ipl = iplt[unit]); copied += dlen) {
453 dlen = ipl->ipl_dsize;
454 if (dlen > uio->uio_resid)
457 * Don't hold the mutex over the uiomove call.
459 iplt[unit] = ipl->ipl_next;
460 iplused[unit] -= dlen;
461 MUTEX_EXIT(&ipl_mutex);
462 error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio);
463 MUTEX_ENTER(&ipl_mutex);
465 ipl->ipl_next = iplt[unit];
467 iplused[unit] += dlen;
470 KFREES((caddr_t)ipl, dlen);
474 iplh[unit] = &iplt[unit];
478 MUTEX_EXIT(&ipl_mutex);
484 int ipflog_clear(unit)
490 MUTEX_ENTER(&ipl_mutex);
491 while ((ipl = iplt[unit])) {
492 iplt[unit] = ipl->ipl_next;
493 KFREES((caddr_t)ipl, ipl->ipl_dsize);
495 iplh[unit] = &iplt[unit];
497 used = iplused[unit];
499 bzero((char *)&iplcrc[unit], FI_LCSIZE);
500 MUTEX_EXIT(&ipl_mutex);
503 #endif /* IPFILTER_LOG */