unbreak world: only include sys/thread2.h in kernel, not in userland
[dragonfly.git] / sys / contrib / ipfilter / netinet / ip_log.c
1 /*
2  * Copyright (C) 1997-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * $Id: ip_log.c,v 2.5.2.1 2000/07/19 13:11:47 darrenr Exp $
7  * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_log.c,v 1.17.2.6 2004/07/05 16:55:16 darrenr Exp $
8  * $DragonFly: src/sys/contrib/ipfilter/netinet/ip_log.c,v 1.10 2005/06/05 12:17:46 corecode Exp $
9  */
10 #include <sys/param.h>
11 #if defined(KERNEL) && !defined(_KERNEL)
12 # define       _KERNEL
13 #endif
14 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
15     defined(_KERNEL)
16 # include "opt_ipfilter_log.h"
17 #endif
18 #if  defined(__DragonFly__) || defined(__FreeBSD__)
19 # if defined(IPFILTER_LKM) || defined(_KERNEL)
20 #  if !defined(__FreeBSD_version) && !defined(__DragonFly__)
21 #   include <sys/osreldate.h>
22 #  endif
23 #  if !defined(IPFILTER_LKM)
24 #   if defined(__DragonFly__) || (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000))
25 #    include "opt_ipfilter.h"
26 #   endif
27 #  endif
28 # else
29 #  ifdef KLD_MODULE
30 #   ifndef __FreeBSD_cc_version
31 #    include <osreldate.h>
32 #   else
33 #    if __FreeBSD_cc_version < 430000
34 #     include <osreldate.h>
35 #    endif
36 #   endif
37 #  endif
38 # endif
39 #endif
40 #ifdef  IPFILTER_LOG
41 # ifndef SOLARIS
42 #  define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
43 # endif
44 # ifndef _KERNEL
45 #  include <stdio.h>
46 #  include <string.h>
47 #  include <stdlib.h>
48 #  include <ctype.h>
49 # endif
50 # include <sys/errno.h>
51 # include <sys/types.h>
52 # include <sys/file.h>
53 # if (defined(__DragonFly__) || __FreeBSD_version >= 220000) && defined(_KERNEL)
54 #  include <sys/fcntl.h>
55 #  include <sys/filio.h>
56 # else
57 #  include <sys/ioctl.h>
58 # endif
59 # include <sys/time.h>
60 # if defined(_KERNEL)
61 #  include <sys/systm.h>
62 # endif
63 # if !SOLARIS
64 #  if defined(__DragonFly__) || (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
65 #   include <sys/dirent.h>
66 #  else
67 #   include <sys/dir.h>
68 #  endif
69 #  include <sys/mbuf.h>
70 # else
71 #  include <sys/filio.h>
72 #  include <sys/cred.h>
73 #  include <sys/kmem.h>
74 #  ifdef _KERNEL
75 #   include <sys/ddi.h>
76 #   include <sys/sunddi.h>
77 #   include <sys/ksynch.h>
78 #   include <sys/dditypes.h>
79 #   include <sys/cmn_err.h>
80 #  endif
81 # endif
82 # include <sys/protosw.h>
83 # include <sys/socket.h>
84
85 # include <net/if.h>
86 # ifdef sun
87 #  include <net/af.h>
88 # endif
89 # if defined(__DragonFly__) || __FreeBSD_version >= 300000
90 #  include <net/if_var.h>
91 # endif
92 # include <net/route.h>
93 # include <netinet/in.h>
94 # ifdef __sgi
95 #  define _KMEMUSER
96 #  include <sys/ddi.h>
97 #  ifdef IFF_DRVRLOCK /* IRIX6 */
98 #   include <sys/hashing.h>
99 #  endif
100 # endif
101 # if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/
102 #  include <netinet/in_var.h>
103 # endif
104 # include <netinet/in_systm.h>
105 # include <netinet/ip.h>
106 # include <netinet/tcp.h>
107 # include <netinet/udp.h>
108 # include <netinet/ip_icmp.h>
109 # ifdef USE_INET6
110 #  include <netinet/icmp6.h>
111 # endif
112 # include <netinet/ip_var.h>
113 # ifndef _KERNEL
114 #  include <syslog.h>
115 # endif
116 # include "ip_compat.h"
117 # include <netinet/tcpip.h>
118 # include "ip_fil.h"
119 # if defined(__DragonFly__) || __FreeBSD_version >= 300000
120 #  include <sys/malloc.h>
121 # endif
122 # if defined(__DragonFly__) && defined(_KERNEL)
123 #  include <sys/thread2.h>
124 # endif
125
126 # ifndef MIN
127 #  define       MIN(a,b)        (((a)<(b))?(a):(b))
128 # endif
129 # ifdef IPFILTER_LOGSIZE
130 #  undef IPLLOGSIZE
131 #  define IPLLOGSIZE IPFILTER_LOGSIZE
132 # endif
133
134
135 # if SOLARIS || defined(__sgi)
136 extern  kmutex_t        ipl_mutex;
137 #  if SOLARIS
138 extern  kcondvar_t      iplwait;
139 #  endif
140 # endif
141
142 iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1];
143 size_t  iplused[IPL_LOGMAX+1];
144 static fr_info_t        iplcrc[IPL_LOGMAX+1];
145
146
147 /*
148  * Initialise log buffers & pointers.  Also iniialised the CRC to a local
149  * secret for use in calculating the "last log checksum".
150  */
151 void ipflog_init()
152 {
153         int     i;
154
155         for (i = IPL_LOGMAX; i >= 0; i--) {
156                 iplt[i] = NULL;
157                 ipll[i] = NULL;
158                 iplh[i] = &iplt[i];
159                 iplused[i] = 0;
160                 bzero((char *)&iplcrc[i], sizeof(iplcrc[i]));
161         }
162 }
163
164
165 /*
166  * ipflog
167  * Create a log record for a packet given that it has been triggered by a
168  * rule (or the default setting).  Calculate the transport protocol header
169  * size using predetermined size of a couple of popular protocols and thus
170  * how much data to copy into the log, including part of the data body if
171  * requested.
172  */
173 int ipflog(flags, ip, fin, m)
174 u_int flags;
175 ip_t *ip;
176 fr_info_t *fin;
177 mb_t *m;
178 {
179         ipflog_t ipfl;
180         size_t mlen, hlen;
181         size_t sizes[2];
182         void *ptrs[2];
183         int types[2];
184         u_char p;
185 # if SOLARIS && defined(_KERNEL)
186         ill_t *ifp = fin->fin_ifp;
187 # else
188         struct ifnet *ifp = fin->fin_ifp;
189 # endif
190
191         /*
192          * calculate header size.
193          */
194         hlen = fin->fin_hlen;
195         if (fin->fin_off == 0) {
196                 p = fin->fin_fi.fi_p;
197                 if (p == IPPROTO_TCP)
198                         hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
199                 else if (p == IPPROTO_UDP)
200                         hlen += MIN(sizeof(udphdr_t), fin->fin_dlen);
201                 else if (p == IPPROTO_ICMP) {
202                         struct icmp *icmp;
203
204                         icmp = (struct icmp *)fin->fin_dp;
205          
206                         /*
207                          * For ICMP, if the packet is an error packet, also
208                          * include the information about the packet which
209                          * caused the error.
210                          */
211                         switch (icmp->icmp_type)
212                         {
213                         case ICMP_UNREACH :
214                         case ICMP_SOURCEQUENCH :
215                         case ICMP_REDIRECT :
216                         case ICMP_TIMXCEED :
217                         case ICMP_PARAMPROB :
218                                 hlen += MIN(sizeof(struct icmp) + 8,
219                                             fin->fin_dlen);
220                                 break;
221                         default :
222                                 hlen += MIN(sizeof(struct icmp),
223                                             fin->fin_dlen);
224                                 break;
225                         }
226                 }
227 #ifdef USE_INET6
228                 else if (p == IPPROTO_ICMPV6) {
229                         struct icmp6_hdr *icmp;
230
231                         icmp = (struct icmp6_hdr *)fin->fin_dp;
232          
233                         /*
234                          * For ICMPV6, if the packet is an error packet, also
235                          * include the information about the packet which
236                          * caused the error.
237                          */
238                         if (icmp->icmp6_type < 128) {
239                                 hlen += MIN(sizeof(struct icmp6_hdr) + 8,
240                                             fin->fin_dlen);
241                         } else {
242                                 hlen += MIN(sizeof(struct icmp6_hdr),
243                                             fin->fin_dlen);
244                         }
245                 }
246 #endif
247         }
248         /*
249          * Get the interface number and name to which this packet is
250          * currently associated.
251          */
252         bzero((char *)ipfl.fl_ifname, sizeof(ipfl.fl_ifname));
253 # if SOLARIS && defined(_KERNEL)
254         ipfl.fl_unit = (u_int)ifp->ill_ppa;
255         bcopy(ifp->ill_name, ipfl.fl_ifname,
256               MIN(ifp->ill_name_length, sizeof(ipfl.fl_ifname)));
257         mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0;
258 # else
259 #  if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
260         (defined(OpenBSD) && (OpenBSD >= 199603)) || \
261         (defined(__DragonFly__))
262         strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ);
263 #  else
264         ipfl.fl_unit = (u_int)ifp->if_unit;
265         strncpy(ipfl.fl_ifname, ifp->if_name, MIN(sizeof(ipfl.fl_ifname),
266                                                   sizeof(ifp->if_name)));
267 #  endif
268         mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0;
269 # endif
270         ipfl.fl_plen = (u_char)mlen;
271         ipfl.fl_hlen = (u_char)hlen;
272         ipfl.fl_rule = fin->fin_rule;
273         ipfl.fl_group = fin->fin_group;
274         if (fin->fin_fr != NULL)
275                 ipfl.fl_loglevel = fin->fin_fr->fr_loglevel;
276         else
277                 ipfl.fl_loglevel = 0xffff;
278         ipfl.fl_flags = flags;
279         ipfl.fl_dir = fin->fin_out;
280         ptrs[0] = (void *)&ipfl;
281         sizes[0] = sizeof(ipfl);
282         types[0] = 0;
283 # if SOLARIS && defined(_KERNEL)
284         /*
285          * Are we copied from the mblk or an aligned array ?
286          */
287         if (ip == (ip_t *)m->b_rptr) {
288                 ptrs[1] = m;
289                 sizes[1] = hlen + mlen;
290                 types[1] = 1;
291         } else {
292                 ptrs[1] = ip;
293                 sizes[1] = hlen + mlen;
294                 types[1] = 0;
295         }
296 # else
297         ptrs[1] = m;
298         sizes[1] = hlen + mlen;
299         types[1] = 1;
300 # endif
301         return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2);
302 }
303
304
305 /*
306  * ipllog
307  */
308 int ipllog(dev, fin, items, itemsz, types, cnt)
309 int dev;
310 fr_info_t *fin;
311 void **items;
312 size_t *itemsz;
313 int *types, cnt;
314 {
315         caddr_t buf, s;
316         iplog_t *ipl;
317         size_t len;
318         int i;
319  
320         /*
321          * Check to see if this log record has a CRC which matches the last
322          * record logged.  If it does, just up the count on the previous one
323          * rather than create a new one.
324          */
325         MUTEX_ENTER(&ipl_mutex);
326         if ((fin != NULL) && (fin->fin_off == 0)) {
327                 if ((ipll[dev] != NULL) &&
328                     bcmp((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE) == 0) {
329                         ipll[dev]->ipl_count++;
330                         MUTEX_EXIT(&ipl_mutex);
331                         return 1;
332                 }
333                 bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE);
334         } else
335                 bzero((char *)&iplcrc[dev], FI_LCSIZE);
336         MUTEX_EXIT(&ipl_mutex);
337
338         /*
339          * Get the total amount of data to be logged.
340          */
341         for (i = 0, len = IPLOG_SIZE; i < cnt; i++)
342                 len += itemsz[i];
343
344         /*
345          * check that we have space to record this information and can
346          * allocate that much.
347          */
348         KMALLOCS(buf, caddr_t, len);
349         if (!buf)
350                 return 0;
351         MUTEX_ENTER(&ipl_mutex);
352         if ((iplused[dev] + len) > IPLLOGSIZE) {
353                 MUTEX_EXIT(&ipl_mutex);
354                 KFREES(buf, len);
355                 return 0;
356         }
357         iplused[dev] += len;
358         MUTEX_EXIT(&ipl_mutex);
359
360         /*
361          * advance the log pointer to the next empty record and deduct the
362          * amount of space we're going to use.
363          */
364         ipl = (iplog_t *)buf;
365         ipl->ipl_magic = IPL_MAGIC;
366         ipl->ipl_count = 1;
367         ipl->ipl_next = NULL;
368         ipl->ipl_dsize = len;
369 # ifdef _KERNEL
370 #  if SOLARIS || defined(sun)
371         uniqtime(&ipl->ipl_tv);
372 #  else
373 #   if defined(__DragonFly__) || BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi)
374         microtime(&ipl->ipl_tv);
375 #   endif
376 #  endif
377 # else
378         ipl->ipl_sec = 0;
379         ipl->ipl_usec = 0;
380 # endif
381
382         /*
383          * Loop through all the items to be logged, copying each one to the
384          * buffer.  Use bcopy for normal data or the mb_t copyout routine.
385          */
386         for (i = 0, s = buf + IPLOG_SIZE; i < cnt; i++) {
387                 if (types[i] == 0)
388                         bcopy(items[i], s, itemsz[i]);
389                 else if (types[i] == 1) {
390 # if SOLARIS && defined(_KERNEL)
391                         copyout_mblk(items[i], 0, itemsz[i], s);
392 # else
393                         m_copydata(items[i], 0, itemsz[i], s);
394 # endif
395                 }
396                 s += itemsz[i];
397         }
398         MUTEX_ENTER(&ipl_mutex);
399         ipll[dev] = ipl;
400         *iplh[dev] = ipl;
401         iplh[dev] = &ipl->ipl_next;
402 # if SOLARIS && defined(_KERNEL)
403         cv_signal(&iplwait);
404         mutex_exit(&ipl_mutex);
405 # else
406         MUTEX_EXIT(&ipl_mutex);
407         WAKEUP(&iplh[dev]);
408 # endif
409         return 1;
410 }
411
412
413 int ipflog_read(unit, uio)
414 minor_t unit;
415 struct uio *uio;
416 {
417         size_t dlen, copied;
418         int error = 0;
419         iplog_t *ipl;
420 # if defined(_KERNEL) && !SOLARIS && !defined(__DragonFly__)
421         int s;
422 # endif
423
424         /*
425          * Sanity checks.  Make sure the minor # is valid and we're copying
426          * a valid chunk of data.
427          */
428         if (IPL_LOGMAX < unit)
429                 return ENXIO;
430         if (!uio->uio_resid)
431                 return 0;
432         if (uio->uio_resid < IPLOG_SIZE)
433                 return EINVAL;
434  
435         /*
436          * Lock the log so we can snapshot the variables.  Wait for a signal
437          * if the log is empty.
438          */
439         SPL_NET(s);
440         MUTEX_ENTER(&ipl_mutex);
441
442         while (iplt[unit] == NULL) {
443 # if SOLARIS && defined(_KERNEL)
444                 if (!cv_wait_sig(&iplwait, &ipl_mutex)) {
445                         MUTEX_EXIT(&ipl_mutex);
446                         return EINTR;
447                 }
448 # else
449                 MUTEX_EXIT(&ipl_mutex);
450                 error = SLEEP(&iplh[unit], "ipl sleep");
451                 if (error) {
452                         SPL_X(s);
453                         return error;
454                 }
455                 MUTEX_ENTER(&ipl_mutex);
456 # endif /* SOLARIS */
457         }
458
459 # if defined(__DragonFly__) || BSD >= 199306 || defined(__FreeBSD__)
460         uio->uio_rw = UIO_READ;
461 # endif
462
463         for (copied = 0; (ipl = iplt[unit]); copied += dlen) {
464                 dlen = ipl->ipl_dsize;
465                 if (dlen > uio->uio_resid)
466                         break;
467                 /*
468                  * Don't hold the mutex over the uiomove call.
469                  */
470                 iplt[unit] = ipl->ipl_next;
471                 iplused[unit] -= dlen;
472                 MUTEX_EXIT(&ipl_mutex);
473                 error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio);
474                 MUTEX_ENTER(&ipl_mutex);
475                 if (error) {
476                         ipl->ipl_next = iplt[unit];
477                         iplt[unit] = ipl;
478                         iplused[unit] += dlen;
479                         break;
480                 }
481                 KFREES((caddr_t)ipl, dlen);
482         }
483         if (!iplt[unit]) {
484                 iplused[unit] = 0;
485                 iplh[unit] = &iplt[unit];
486                 ipll[unit] = NULL;
487         }
488
489         MUTEX_EXIT(&ipl_mutex);
490         SPL_X(s);
491         return error;
492 }
493
494
495 int ipflog_clear(unit)
496 minor_t unit;
497 {
498         iplog_t *ipl;
499         int used;
500
501         MUTEX_ENTER(&ipl_mutex);
502         while ((ipl = iplt[unit])) {
503                 iplt[unit] = ipl->ipl_next;
504                 KFREES((caddr_t)ipl, ipl->ipl_dsize);
505         }
506         iplh[unit] = &iplt[unit];
507         ipll[unit] = NULL;
508         used = iplused[unit];
509         iplused[unit] = 0;
510         bzero((char *)&iplcrc[unit], FI_LCSIZE);
511         MUTEX_EXIT(&ipl_mutex);
512         return used;
513 }
514 #endif /* IPFILTER_LOG */